Children 更改 TreeView 的 ItemsSource 时丢失

Children missing when changing ItemsSource of TreeView

我有多个 ObservableCollections of Items children。我试图将 TreeView 绑定到一个集合,用户将在运行时 select 源代码。用户可以将列表拖放到 reorganise/edit 活动源集合。

只要您从不切换到以前的 selected 源,我所尝试的就可以完美运行。切换回以前的源将导致丢失 children,仅显示根项目。如果 children 在返回之前展开,一些 children 剩余,而另一些则没有,则此行为会变得更加不一致。

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)
        );
    }
}

问题动图: Code result

更新:临时解决方法,直到我找到适合我需要的更好的东西

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

其次,我能够通过清除 TreeView 源、更新绑定、然后设置为虚拟集合(至少有 1 个成员,0 结果为由于某种原因未能仅加载最后一个 children),更新绑定,然后最终将其设置为真实源,并最后一次更新绑定。每次绑定更新之间都需要异步延迟来刷新 TreeView。这样做的缺点是它会在源为空白时引入闪烁帧。

抱歉我迟到的回复。

我们研究了您的问题,此问题已在新版 Microsoft.UI.Xaml (WinUI 2.x). You can check this commit 中得到解决。

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

此致。

此问题的修复已随 Microsoft.UI.Xaml v2.4.0 一起提供。请参阅此 commit 了解更多信息。