【发布时间】: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对应于Frame,Frame导航到指定页面。在你的页面构造方法中使用(Page)NavigationCacheMode = NavigationCacheMode.Enabled;,你不必刷新整个页面的数据,它会保持你离开时的状态。
标签: c# xaml data-binding uwp treeview