【问题标题】:Children missing when changing ItemsSource of TreeView更改 TreeView 的 ItemsSource 时缺少子项
【发布时间】:2020-02-27 13:01:54
【问题描述】:

我有多个带有子项的 ObservableCollections。我正在尝试将 TreeView 绑定到集合,用户将在运行时选择源。用户可以在列表上拖放以重新组织/编辑活动源集合。

只要您从不切换到先前选择的来源,我所尝试的方法就可以完美运行。切换回上一个源将导致缺少子项,仅显示根项。如果孩子在返回之前被展开,一些孩子留下,而其他孩子没有,这种行为会变得更加不一致。

xaml:

<Grid RowSpacing="8" Margin="8">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <StackPanel Orientation="Horizontal" Spacing="8">
        <Button x:Name="ShowC1" Click="ShowC1_Click" Content="Container 1"/>
        <Button x:Name="ShowC2" Click="ShowC2_Click" Content="Container 2"/>
        <Button x:Name="ShowC3" Click="ShowC3_Click" Content="Container 3"/>
    </StackPanel>
    <muxc:TreeView x:Name="ItemTree" ItemsSource="{x:Bind Source}" Grid.Row="1">
        <muxc:TreeView.ItemTemplate>
            <DataTemplate x:DataType="local:Item">
                <muxc:TreeViewItem ItemsSource="{x:Bind Children}" Content="{x:Bind Name}"/>
            </DataTemplate>
        </muxc:TreeView.ItemTemplate>
    </muxc:TreeView>
</Grid>

xaml.cs

public sealed partial class MainPage : Page
{
    private Container _con1, _con2, _con3;
    ExtendedObservableCollection<Item> Source = new ExtendedObservableCollection<Item>();

    public MainPage()
    {
        this.InitializeComponent();
        _con1 = new Container("Container 1", 2);
        _con2 = new Container("Container 2", 3);
        _con3 = new Container("Container 3", 4);
    }

    private void ShowC1_Click(object sender, RoutedEventArgs e)
    {
        Source.ReplaceAll(_con1.Items);
    }

    private void ShowC2_Click(object sender, RoutedEventArgs e)
    {
        Source.ReplaceAll(_con2.Items);
    }

    private void ShowC3_Click(object sender, RoutedEventArgs e)
    {
        Source.ReplaceAll(_con3.Items);
    }
}

public class Container
{
    public string Title { get; set; } = "Untitled";
    public ObservableCollection<Item> Items { get; private set; } = new ObservableCollection<Item>();

    public Container(string title, int numItems)
    {
        Title = title;

        for (int i = 0; i < numItems; i++)
        {
            Items.Add(new Item("Item " + i, i + 1));
        }
    }
}

public class Item
{
    public string Name { get; set; } = "Item";
    public ObservableCollection<Item> Children { get; set; } = new ObservableCollection<Item>();

    public Item(string name, int numChildren)
    {
        Name = name;

        for (int i = 0; i < numChildren; i++)
        {
            Children.Add(new Item("Child " + i, 0));
        }
    }
}

ExtendedObservableCollection.cs

public class ExtendedObservableCollection<T> : ObservableCollection<T>
{
    public void ReplaceAll(ICollection<T> items)
    {
        this.Items.Clear();
        foreach (T item in items)
        {
            this.Items.Add(item);
        }
        this.OnCollectionChanged(
            new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)
        );
    }
}

问题的 Gif: Code result

更新:临时解决方法,直到我找到更好的东西,在我需要的范围内工作

首先,我注意到该集合甚至没有通过拖放操作进行更新,而是引用了最新的 WinUI 修复了该问题。我还更改了绑定以使用 x:Bind。

其次,通过清除 TreeView 源,更新绑定,然后设置为虚拟集合(至少有 1 个成员,0 导致无法仅加载最后一个成员),我能够让孩子们以一种相当肮脏的方式工作出于某种原因的孩子),更新绑定,然后最终将其设置为真实源,最后一次更新绑定。每次绑定更新之间需要异步延迟以刷新 TreeView。这样做的缺点是它会在源为空白时引入一帧闪烁。

【问题讨论】:

  • 您好,我重现了您的问题,似乎是缓存问题。我已经报告了这个问题。如果我有新的进展,我会在这里回复。感谢您的支持。
  • 非常感谢!几天来,我一直试图以不同的方式解决这个问题,现在我认为这纯粹是我对绑定缺乏了解。期待更新。
  • 您好,在我收到反馈之前,有一个简单的方法可以解决问题。当你按下按钮时,创建一个新的Source实例作为绑定源,而不是使用使用过的实例,这可以帮助你刷新数据源。
  • 啊,是的,这行得通。尽管不幸的是,我认为创建新实例不会在我的实际项目中起作用,因为我仍然需要使用原始实例。对于上下文,按钮实际上是 TabView 中的选项卡。 “源”是指 TabViewItem 中的整个页面。 Source 包含有关画布的信息,其中 Items 集合包含有关构成在页面上绘制的画布位图的图层的信息。 TreeView 切换以在活动选项卡中显示来自页面(源)的数据。
  • 我明白了,也许你可以这样做:Tab 对应于FrameFrame 导航到指定页面。在你的页面构造方法中使用(Page)NavigationCacheMode = NavigationCacheMode.Enabled;,你不必刷新整个页面的数据,它会保持你离开时的状态。

标签: c# xaml data-binding uwp treeview


【解决方案1】:

Microsoft.UI.Xaml v2.4.0 附带了针对此问题的修复程序。请参阅此commit 了解更多信息。

【讨论】:

    【解决方案2】:

    对不起,我的回复晚了。

    我们研究了您的问题,此问题已在新的Microsoft.UI.Xaml (WinUI 2.x) 中得到解决。你可以查看这个commit

    WinUI是微软新一代开源UI工具框架。感谢社区的支持,它可以更快地更新。我们建议您使用它提供的TreeView 控件来完成您的 UI 布局。

    最好的问候。

    【讨论】:

    • 我在最新的预发布版中试了一下,但遗憾的是我仍然遇到和以前一样的问题?我查看了相关的测试页面,并尝试将 ExtendedObservableCollection 与 ReplaceAll() 一样使用,但像以前一样,使用 TreeView 之前显示的集合中的项目填充 ItemSource 设置的集合(即如果用户决定返回他们之前查看的数据集)所有子节点都会在 TreeView 中丢失 - 根节点很好。
    • 您好,我使用ObservableCollection 测试了您的代码,但没有重现您的问题,您能提供ExtendedObservableCollection 的实现吗?
    • 更新了我的帖子以包含 ExtendedObservableCollection 和一个 Gif,它准确地显示了我所看到的内容。 (使用 muxc 版本 2.3.191127001-prerelease)
    • 您好,您的问题我已经复现了,您可以考虑在Github issue提交新的issue,并将您的问题反馈给WinUI的开发团队。
    猜你喜欢
    • 2018-04-09
    • 2010-10-16
    • 2021-11-22
    • 1970-01-01
    • 1970-01-01
    • 2011-04-14
    • 2017-02-09
    • 2014-01-10
    • 1970-01-01
    相关资源
    最近更新 更多