xaml - 在 Windows 8.1 存储 XAML 中添加新项目后,ListView.ContainerFromItem 返回 null

标签 xaml windows-store-apps winrt-xaml windows-8.1

我有一个没有项目模板的简单 ListView 和 SelectionChanged 事件设置:

    <ListView x:Name="list1" HorizontalAlignment="Left"
              Height="556"
              Margin="209,93,0,0"
              VerticalAlignment="Top"
              Width="1033"
              SelectionChanged="list1_SelectionChanged" />

    private void list1_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {            
        var container = (sender as ListView).ContainerFromItem(e.AddedItems.First());
        var presenter = VisualTreeHelper.GetChild(container, 0);            
    }

我还有一个测试类,如下所示:
class Test
{
    public string FirstName { get; set; }
    public string Surname { get; set; }
}

现在在页面的构造函数中,我有以下代码创建测试项的 ObservableCollection,添加一些,然后将其设置为 ListView 的 ItemSource:
ObservableCollection<Test> testCollection;

public MainPage()
{
    this.InitializeComponent();

    testCollection = new ObservableCollection<Test>();
    testCollection.Add(new Test { FirstName = "Bob", Surname = "Smith1" });
    testCollection.Add(new Test { FirstName = "Bob", Surname = "Smith2" });
    testCollection.Add(new Test { FirstName = "Bob", Surname = "Smith3" });

    list1.ItemsSource = testCollection;
}

现在,当我在列表中选择一个项目并触发 SelectionChanged 事件时,容器变量按预期包含 ListViewItem。

现在,我在表单上也有按钮,这是按钮单击事件:
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        testCollection.Add(new Test { FirstName = "Bob", Surname = "Smith4" });

        list1.SelectedIndex = list1.Items.Count - 1;
    }

最后一行选择新项目并触发 SelectionChanged 事件,但这次容器变量为空。

谁能告诉我为什么这是空的,我该如何解决这个问题?

谢谢

最佳答案

我可以告诉你。

您在这里遇到的是时间问题。您认为将项目添加到集合的速度有多快?快速 - 只需一两毫秒。您认为 ListView 需要多快设置 SelectedItem属性(property)和提高SelectionChanged事件?快速 - 一两毫秒。但是,您认为 ListView 需要多快实际在屏幕上呈现新项目并为其生成容器?很长一段时间——比如 10 到 100 毫秒,取决于 DataTemplate 的复杂性.

我意识到你的测试没有设置 ItemTemplate ,并且我假设您这样做是假设它会渲染得更快 - 可能是即时的。但是有一个默认的 DataTemplate在每个 ItemsControl .而且,即使是一个简单的 DataTemplate与内置的一样,仍然比推进单个 C# 行需要更多的时间。

这段代码将说明我的意思:

async void MainPage_Loaded(object sender, RoutedEventArgs e)
{
    var items = Enumerable.Range(1, 10)
        .Select(x => new Item { FirstName = "Bob", LastName = "Smith" + x.ToString() });
    var list = new ObservableCollection<Item>(items);
    MyListView.ItemsSource = list;
    var item = new Item { FirstName = "Jerry", LastName = "Nixon" };
    list.Add(item);
    await Task.Delay(1000);
    MyListView.SelectedItem = item;
}

private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    System.Diagnostics.Debug.Assert(e.AddedItems.Any());
    var listview = sender as ListView;
    var container = listview.ContainerFromItem(e.AddedItems.First());
    System.Diagnostics.Debug.Assert(container != null);
    var presenter = VisualTreeHelper.GetChild(container, 0);
    System.Diagnostics.Debug.Assert(presenter != null);
}

Please notice the Delay code; this is what makes it work.



希望您简化了您的问题,这就是您在代码隐藏而不是在 View 模型中进行工作的原因。美好的。首先,确定并处理 Loaded 中的此类逻辑所以您可以放心,您的 ListView甚至可用。然后,在您的 View 模型中执行此操作。

所以,我已经回答了你的问题。为什么?因为时机。

在我看来,这一切都可以用一个简单的 View 模型来解决,但话说回来,我只知道一点点你的情况。也许有些东西我没有看到。

祝你好运!

关于xaml - 在 Windows 8.1 存储 XAML 中添加新项目后,ListView.ContainerFromItem 返回 null,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23995504/

相关文章:

c# - 如何绑定(bind)到 UWP 中的附加属性?

c# - 文件名、目录名或卷标语法不正确。 (来自 HRESULT : 0x8007007B) 的异常

c# - MVVM CanExecute 返回 false 并且 Button 保持禁用状态

xaml - Xamarin Forms 不在 MVVMCross MvxContentPage 中显示图像

c# - 本地化 WPF 应用程序不起作用?

c# - 仅当应用程序被激活时才会弹出 Toast 通知

c# - RelayCommand 未执行

c# - 如何在 Windows 商店应用程序中实现登录注销功能?

c# - LiveLoginResult.Status 未知?

c# - 使用itextsharp使用哪个xaml控件显示pdf文件?