UWP Treeview C# 中的无效转换异常
Invalid Cast Exception in UWP Treeview C#
使用绑定到三层层次结构的树视图时 collection(订单 - SKU - 位置)。我正在使用 DataTemplateSelector 来选择要使用的 TreeViewItem 模板。当我滚动时,我得到一个与此 中完全相同的无效异常 - 如果我滚动得更快,异常似乎发生得更快。
我在 post 中尝试了两种建议的解决方案(将树视图包装在滚动查看器和自定义用户控件中)。包装 TreeView 没有帮助,我无法让自定义用户控件解决方案为我正常工作,我想知道这是否与我有一个三层 collection 而不是两层的事实有关。自定义 UserControl 的代码与链接 post 中的代码完全相同,除了为我的 collection 进行了修改。当我尝试它时,它只将 collection 的一层绑定到树视图。我正在寻找的是一种解决方案,可防止框架代码重复使用模板,这似乎是导致异常的原因。
这是我的 XAML 和当前产生异常的 TreeView 的代码:
<Page
x:Class="PickSheetManager.Views.PickSheetManagerPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:winui="using:Microsoft.UI.Xaml.Controls"
xmlns:model="using:PickSheetManager.Core.Models"
xmlns:behaviors="using:PickSheetManager.Behaviors"
xmlns:templateSelectors="using:PickSheetManager.TemplateSelectors"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:controls1="using:PickSheetManager.Controls"
xmlns:ic="using:Microsoft.Xaml.Interactions.Core"
xmlns:i="using:Microsoft.Xaml.Interactivity"
Style="{StaticResource PageStyle}"
behaviors:NavigationViewHeaderBehavior.HeaderMode="Never"
mc:Ignorable="d">
<Page.Resources>
<DataTemplate x:Key="OrderTemplate" x:DataType="model:Order">
<winui:TreeViewItem
AutomationProperties.Name="{x:Bind PoIDx}"
ItemsSource="{x:Bind SKUs}" IsExpanded="True">
<StackPanel x:Name="stack" Orientation="Horizontal">
<i:Interaction.Behaviors>
<ic:DataTriggerBehavior Binding ="{x:Bind NotEnoughInventory}" Value="True">
<ic:ChangePropertyAction TargetObject="{Binding ElementName=stack}" PropertyName="Background" Value="Red" />
</ic:DataTriggerBehavior>
</i:Interaction.Behaviors>
<CheckBox IsChecked="{x:Bind IsSelected, Mode=TwoWay}" Padding="5" MinWidth="0"/>
<TextBlock Text="PoIDx: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind PoIDx}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Delivery: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind DeliveryType}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Delivery: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind DeliveryType}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Type: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind OrderType}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Total Quantity: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind TotalQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Printed: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind IsPrinted}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Notes: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBox Text="{x:Bind Notes, Mode=TwoWay}" Margin="{StaticResource XXSmallTopRightBottomMargin}" Width="150"/>
</StackPanel>
</winui:TreeViewItem>
</DataTemplate>
<DataTemplate x:Key="SKUTemplate" x:DataType="model:SKU">
<winui:TreeViewItem
AutomationProperties.Name="{x:Bind SKUNum}"
ItemsSource="{x:Bind Locations}" IsExpanded="True">
<StackPanel x:Name="stack2" Orientation="Horizontal">
<i:Interaction.Behaviors>
<ic:DataTriggerBehavior Binding ="{x:Bind NotEnoughInventory}" Value="True">
<ic:ChangePropertyAction TargetObject="{Binding ElementName=stack2}" PropertyName="Background" Value="Yellow" />
</ic:DataTriggerBehavior>
</i:Interaction.Behaviors>
<CheckBox IsChecked="{x:Bind IsSelected, Mode=TwoWay}" Padding="5" MinWidth="0" />
<TextBlock Text="SKU: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind SKUNum}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Needed: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind NeedQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Available: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind AvailableQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
</StackPanel>
</winui:TreeViewItem>
</DataTemplate>
<DataTemplate x:Key="LocationTemplate" x:DataType="model:Location">
<winui:TreeViewItem
AutomationProperties.Name="{x:Bind LocationName}"
IsExpanded="True">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{x:Bind IsSelected, Mode=TwoWay}" Padding="5" MinWidth="0" />
<TextBlock Text="{x:Bind LocationName}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Pick Type: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind PickType}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Pick Quantity: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind PickQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Available Quantity: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind AvailableQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBox Text="{x:Bind Notes, Mode=TwoWay}" Margin="{StaticResource XXSmallTopRightBottomMargin}" Width="150" />
</StackPanel>
</winui:TreeViewItem>
</DataTemplate>
<templateSelectors:SampleDataTemplateSelector x:Key="TreeViewTemplateSelector"
OrderDetailTemplate="{StaticResource OrderTemplate}"
SKUDetailTemplate="{StaticResource SKUTemplate}"
LocationDetailTemplate="{StaticResource LocationTemplate}" />
</Page.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="treeViewColumn" Width="6*" />
<ColumnDefinition x:Name="detailViewColumn" Width="4*" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition x:Name="treeViewRow" Height="8*" />
<RowDefinition x:Name="controlRow" Height="2*" />
</Grid.RowDefinitions>
<ScrollViewer x:Name="WrapViewer" Grid.Row="0" Grid.Column="0" Padding="{StaticResource DetailPageMargin}">
</ScrollViewer>
<winui:TreeView
x:Name="treeView"
Grid.Row="0"
SelectionMode="Single"
ItemsSource="{x:Bind ViewModel.openOrders}"
ItemTemplateSelector="{StaticResource TreeViewTemplateSelector}">
<i:Interaction.Behaviors>
<behaviors:TreeViewCollapseBehavior x:Name="collapseBehavior" />
<ic:EventTriggerBehavior EventName="ItemInvoked">
<ic:InvokeCommandAction Command="{x:Bind ViewModel.ItemInvokedCommand}" />
</ic:EventTriggerBehavior>
</i:Interaction.Behaviors>
</winui:TreeView>
</Grid>
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition x:Name="detailViewRow" Height="4*" />
<RowDefinition x:Name="iarRow" Height="4*" />
<RowDefinition x:Name="controlRow2" Height="2*" />
</Grid.RowDefinitions>
</Grid>
</Grid>
正在绑定collection
public ObservableCollection<Order> openOrders { get; } = new ObservableCollection<Order>();
public async Task LoadDataAsync()
{
var data2 = await OrderDataLoader.GetTreeViewDataAsync();
foreach (var item in data2)
{
openOrders.Add(item);
}
}
DataTemplateSelector 代码:
public class SampleDataTemplateSelector : DataTemplateSelector
{
public DataTemplate OrderDetailTemplate { get; set; }
public DataTemplate SKUDetailTemplate { get; set; }
public DataTemplate LocationDetailTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item)
{
return GetTemplate(item) ?? base.SelectTemplateCore(item);
}
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
return GetTemplate(item) ?? base.SelectTemplateCore(item, container);
}
private DataTemplate GetTemplate(object item)
{
switch (item)
{
case Order order:
return OrderDetailTemplate;
case SKU sku:
return SKUDetailTemplate;
case Location location:
return LocationDetailTemplate;
}
return null;
}
}
更新
我实际上已经尝试了两种不同的尝试来让用户控件工作。两者都导致仅显示一层。
尝试 #1 用户控件 XAML:
<UserControl
x:Class="PickSheetManager.Controls.OrderTreeItemControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:winui="using:Microsoft.UI.Xaml.Controls"
xmlns:model="using:PickSheetManager.Core.Models"
xmlns:behaviors="using:PickSheetManager.Behaviors"
xmlns:templateSelectors="using:PickSheetManager.TemplateSelectors"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:controls1="using:PickSheetManager.Controls"
xmlns:ic="using:Microsoft.Xaml.Interactions.Core"
xmlns:i="using:Microsoft.Xaml.Interactivity"
mc:Ignorable="d">
<UserControl.Resources>
<DataTemplate x:Name="OrderTemplate" x:DataType="model:Order">
<StackPanel x:Name="stack" Orientation="Horizontal">
<i:Interaction.Behaviors>
<ic:DataTriggerBehavior Binding ="{x:Bind NotEnoughInventory}" Value="True">
<ic:ChangePropertyAction TargetObject="{Binding ElementName=stack}" PropertyName="Background" Value="Red" />
</ic:DataTriggerBehavior>
</i:Interaction.Behaviors>
<CheckBox IsChecked="{x:Bind IsSelected, Mode=TwoWay}" Padding="5" MinWidth="0"/>
<TextBlock Text="PoIDx: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind PoIDx}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Delivery: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind DeliveryType}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Delivery: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind DeliveryType}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Type: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind OrderType}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Total Quantity: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind TotalQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Printed: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind IsPrinted}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Notes: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBox Text="{x:Bind Notes, Mode=TwoWay}" Margin="{StaticResource XXSmallTopRightBottomMargin}" Width="150"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Name="SKUTemplate" x:DataType="model:SKU">
<StackPanel x:Name="stack2" Orientation="Horizontal">
<i:Interaction.Behaviors>
<ic:DataTriggerBehavior Binding ="{x:Bind NotEnoughInventory}" Value="True">
<ic:ChangePropertyAction TargetObject="{Binding ElementName=stack2}" PropertyName="Background" Value="Yellow" />
</ic:DataTriggerBehavior>
</i:Interaction.Behaviors>
<CheckBox IsChecked="{x:Bind IsSelected, Mode=TwoWay}" Padding="5" MinWidth="0" />
<TextBlock Text="SKU: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind SKUNum}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Needed: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind NeedQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Available: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind AvailableQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Name="LocationTemplate" x:DataType="model:Location">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{x:Bind IsSelected, Mode=TwoWay}" Padding="5" MinWidth="0" />
<TextBlock Text="{x:Bind LocationName}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Pick Type: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind PickType}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Pick Quantity: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind PickQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Available Quantity: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind AvailableQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBox Text="{x:Bind Notes, Mode=TwoWay}" Margin="{StaticResource XXSmallTopRightBottomMargin}" Width="150" />
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<Grid>
<ContentControl x:Name="MainContent"/>
</Grid>
</UserControl>
尝试 #1 .cs
namespace PickSheetManager.Controls
{
public sealed partial class OrderTreeItemControl : UserControl
{
public OrderTreeItemControl()
{
this.InitializeComponent();
}
public Order Data
{
get { return (OpenOrdersBase)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(OpenOrdersBase), typeof(OrderTreeItemControl), new PropertyMetadata(null, new PropertyChangedCallback(Data_Changed)));
private static void Data_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue != null)
{
var instance = d as OrderTreeItemControl;
if (e.NewValue is Location)
{
instance.MainContent.ContentTemplate = instance.LocationTemplate;
}
else if (e.NewValue is SKU)
{
instance.MainContent.ContentTemplate = instance.SKUTemplate;
}
else
{
instance.MainContent.ContentTemplate = instance.OrderTemplate;
}
}
}
}
}
尝试 #1 模型 类
public class OpenOrdersBase
{
public ObservableCollection<Order> Orders { get; } = new ObservableCollection<Order>();
}
public class Order : OpenOrdersBase
{
public bool IsSelected { get; set; }
public string OrderNumber { get; set; }
public string PoIDx { get; set; }
...
public ICollection<SKU> SKUs { get; set; }
}
public class SKU : OpenOrderBase
{
public bool IsSelected { get; set; }
public string SKUNum { get; set; }
...
public ICollection<Location> Locations { get; set; }
}
public class Location : OpenOrdersBase
{
public bool IsSelected { get; set; }
...
public string Notes { get; set; }
}
尝试 #1 页 XAML
<DataTemplate x:Key="BaseTemplate" x:DataType="model:Order">
<winui:TreeViewItem
IsExpanded="False"
ItemsSource="{x:Bind SKUs}">
<controls1:TestControl Data="{Binding}"/>
</winui:TreeViewItem>
</DataTemplate>
...
<winui:TreeView
x:Name="treeView"
Grid.Row="0"
SelectionMode="Single"
Margin="10,10,10,10"
ItemsSource="{x:Bind ViewModel.openOrders}"
ItemTemplate="{StaticResource BaseTemplate}">
<i:Interaction.Behaviors>
<behaviors:TreeViewCollapseBehavior x:Name="collapseBehavior" />
<ic:EventTriggerBehavior EventName="ItemInvoked">
<ic:InvokeCommandAction Command="{x:Bind ViewModel.ItemInvokedCommand}" />
</ic:EventTriggerBehavior>
</i:Interaction.Behaviors>
</winui:TreeView>
尝试 #2 最大的区别在于用户控件 XAML 和模型
用户控件 XAML
<UserControl
x:Class="PickSheetManager.Controls.OrderTreeItemControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:winui="using:Microsoft.UI.Xaml.Controls"
xmlns:model="using:PickSheetManager.Core.Models"
xmlns:behaviors="using:PickSheetManager.Behaviors"
xmlns:templateSelectors="using:PickSheetManager.TemplateSelectors"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:controls1="using:PickSheetManager.Controls"
xmlns:ic="using:Microsoft.Xaml.Interactions.Core"
xmlns:i="using:Microsoft.Xaml.Interactivity"
mc:Ignorable="d">
<UserControl.Resources>
<DataTemplate x:Name="OrderTemplate" x:DataType="model:Order">
<winui:TreeViewItem
AutomationProperties.Name="{x:Bind PoIDx}"
ItemsSource="{x:Bind SKUs}"
IsExpanded="True">
<StackPanel x:Name="stack" Orientation="Horizontal">
<i:Interaction.Behaviors>
<ic:DataTriggerBehavior Binding ="{x:Bind NotEnoughInventory}" Value="True">
<ic:ChangePropertyAction TargetObject="{Binding ElementName=stack}" PropertyName="Background" Value="Red" />
</ic:DataTriggerBehavior>
</i:Interaction.Behaviors>
<CheckBox IsChecked="{x:Bind IsSelected, Mode=TwoWay}" Padding="5" MinWidth="0"/>
<TextBlock Text="PoIDx: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind PoIDx}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Delivery: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind DeliveryType}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Delivery: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind DeliveryType}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Type: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind OrderType}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Total Quantity: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind TotalQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Printed: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind IsPrinted}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Notes: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBox Text="{x:Bind Notes, Mode=TwoWay}" Margin="{StaticResource XXSmallTopRightBottomMargin}" Width="150"/>
</StackPanel>
</winui:TreeViewItem>
</DataTemplate>
<DataTemplate x:Name="SKUTemplate" x:DataType="model:SKU">
<winui:TreeViewItem
AutomationProperties.Name="{x:Bind SKUNum}"
ItemsSource="{x:Bind Locations}"
IsExpanded="True">
<StackPanel x:Name="stack2" Orientation="Horizontal">
<i:Interaction.Behaviors>
<ic:DataTriggerBehavior Binding ="{x:Bind NotEnoughInventory}" Value="True">
<ic:ChangePropertyAction TargetObject="{Binding ElementName=stack2}" PropertyName="Background" Value="Yellow" />
</ic:DataTriggerBehavior>
</i:Interaction.Behaviors>
<CheckBox IsChecked="{x:Bind IsSelected, Mode=TwoWay}" Padding="5" MinWidth="0" />
<TextBlock Text="SKU: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind SKUNum}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Needed: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind NeedQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Available: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind AvailableQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
</StackPanel>
</winui:TreeViewItem>
</DataTemplate>
<DataTemplate x:Name="LocationTemplate" x:DataType="model:Location">
<winui:TreeViewItem
AutomationProperties.Name="{x:Bind LocationName}"
IsExpanded="True">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{x:Bind IsSelected, Mode=TwoWay}" Padding="5" MinWidth="0" />
<TextBlock Text="{x:Bind LocationName}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Pick Type: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind PickType}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Pick Quantity: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind PickQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Available Quantity: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind AvailableQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBox Text="{x:Bind Notes, Mode=TwoWay}" Margin="{StaticResource XXSmallTopRightBottomMargin}" Width="150" />
</StackPanel>
</winui:TreeViewItem>
</DataTemplate>
</UserControl.Resources>
<Grid>
<ContentControl x:Name="MainContent"/>
</Grid>
</UserControl>
在用户控件的代码中,我只是将 OpenOrdersBase 更新为 Order,因为我删除了所有模型的继承。
最后页面 XAML 以这种方式更改
<DataTemplate x:Key="BaseTemplate" x:DataType="model:Order">
<controls1:TestControl Data="{Binding}"/>
</DataTemplate>
其实你的尝试1已经很接近成功了,只需要稍微修改一下就可以了。
这个问题出在class的定义上:
Order
、SKU
、Location
有一个共同的基数classOpenOperBase
,这很好,但是基数class应该提供一个通用的 属性,而不是一个特殊的 Order
集合。
试试这个:
public class OpenOrdersBase
{
public ObservableCollection<OpenOrdersBase> Children { get; set; } = new ObservableCollection<OpenOrdersBase>();
}
在你的Order
和SKU
class中,有一个sub-collection属性,将它们提取为一个单独的基础class集合属性,这将稍后在数据绑定中查看效果。
现在您可以删除 Order.SKUs
和 SKU.Locations
。
绑定时,TestControl
的内容不用改(保持attempt#1的写法),但TreeViewItem
模板需要改DataType
<DataTemplate x:DataType="models:OpenOrdersBase" x:Key="BaseTemplate">
<TreeViewItem ItemsSource="{x:Bind Children}">
<controls:TestControl Data="{Binding}"/>
</TreeViewItem>
</DataTemplate>
我们的大致思路如下:
- 由于
TreeViewItem
仅作为 TreeView.Children
的 child 直接生效,因此尝试 #2 的方法不可取。
TreeView.ItemTemplate
属性影响所有内部children,所以在绑定TreeViewItem.ItemsSource
时,最好绑定一个基class集合,而不是比特定类型的集合(例如 SKUs
)
- 如果你想根据数据类型显示不同的模板,创建一个
UserControl
并在内部判断类型是一种可行的方法(你已经做到了)。
谢谢。
使用绑定到三层层次结构的树视图时 collection(订单 - SKU - 位置)。我正在使用 DataTemplateSelector 来选择要使用的 TreeViewItem 模板。当我滚动时,我得到一个与此
我在 post 中尝试了两种建议的解决方案(将树视图包装在滚动查看器和自定义用户控件中)。包装 TreeView 没有帮助,我无法让自定义用户控件解决方案为我正常工作,我想知道这是否与我有一个三层 collection 而不是两层的事实有关。自定义 UserControl 的代码与链接 post 中的代码完全相同,除了为我的 collection 进行了修改。当我尝试它时,它只将 collection 的一层绑定到树视图。我正在寻找的是一种解决方案,可防止框架代码重复使用模板,这似乎是导致异常的原因。
这是我的 XAML 和当前产生异常的 TreeView 的代码:
<Page
x:Class="PickSheetManager.Views.PickSheetManagerPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:winui="using:Microsoft.UI.Xaml.Controls"
xmlns:model="using:PickSheetManager.Core.Models"
xmlns:behaviors="using:PickSheetManager.Behaviors"
xmlns:templateSelectors="using:PickSheetManager.TemplateSelectors"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:controls1="using:PickSheetManager.Controls"
xmlns:ic="using:Microsoft.Xaml.Interactions.Core"
xmlns:i="using:Microsoft.Xaml.Interactivity"
Style="{StaticResource PageStyle}"
behaviors:NavigationViewHeaderBehavior.HeaderMode="Never"
mc:Ignorable="d">
<Page.Resources>
<DataTemplate x:Key="OrderTemplate" x:DataType="model:Order">
<winui:TreeViewItem
AutomationProperties.Name="{x:Bind PoIDx}"
ItemsSource="{x:Bind SKUs}" IsExpanded="True">
<StackPanel x:Name="stack" Orientation="Horizontal">
<i:Interaction.Behaviors>
<ic:DataTriggerBehavior Binding ="{x:Bind NotEnoughInventory}" Value="True">
<ic:ChangePropertyAction TargetObject="{Binding ElementName=stack}" PropertyName="Background" Value="Red" />
</ic:DataTriggerBehavior>
</i:Interaction.Behaviors>
<CheckBox IsChecked="{x:Bind IsSelected, Mode=TwoWay}" Padding="5" MinWidth="0"/>
<TextBlock Text="PoIDx: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind PoIDx}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Delivery: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind DeliveryType}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Delivery: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind DeliveryType}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Type: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind OrderType}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Total Quantity: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind TotalQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Printed: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind IsPrinted}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Notes: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBox Text="{x:Bind Notes, Mode=TwoWay}" Margin="{StaticResource XXSmallTopRightBottomMargin}" Width="150"/>
</StackPanel>
</winui:TreeViewItem>
</DataTemplate>
<DataTemplate x:Key="SKUTemplate" x:DataType="model:SKU">
<winui:TreeViewItem
AutomationProperties.Name="{x:Bind SKUNum}"
ItemsSource="{x:Bind Locations}" IsExpanded="True">
<StackPanel x:Name="stack2" Orientation="Horizontal">
<i:Interaction.Behaviors>
<ic:DataTriggerBehavior Binding ="{x:Bind NotEnoughInventory}" Value="True">
<ic:ChangePropertyAction TargetObject="{Binding ElementName=stack2}" PropertyName="Background" Value="Yellow" />
</ic:DataTriggerBehavior>
</i:Interaction.Behaviors>
<CheckBox IsChecked="{x:Bind IsSelected, Mode=TwoWay}" Padding="5" MinWidth="0" />
<TextBlock Text="SKU: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind SKUNum}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Needed: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind NeedQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Available: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind AvailableQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
</StackPanel>
</winui:TreeViewItem>
</DataTemplate>
<DataTemplate x:Key="LocationTemplate" x:DataType="model:Location">
<winui:TreeViewItem
AutomationProperties.Name="{x:Bind LocationName}"
IsExpanded="True">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{x:Bind IsSelected, Mode=TwoWay}" Padding="5" MinWidth="0" />
<TextBlock Text="{x:Bind LocationName}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Pick Type: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind PickType}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Pick Quantity: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind PickQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Available Quantity: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind AvailableQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBox Text="{x:Bind Notes, Mode=TwoWay}" Margin="{StaticResource XXSmallTopRightBottomMargin}" Width="150" />
</StackPanel>
</winui:TreeViewItem>
</DataTemplate>
<templateSelectors:SampleDataTemplateSelector x:Key="TreeViewTemplateSelector"
OrderDetailTemplate="{StaticResource OrderTemplate}"
SKUDetailTemplate="{StaticResource SKUTemplate}"
LocationDetailTemplate="{StaticResource LocationTemplate}" />
</Page.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="treeViewColumn" Width="6*" />
<ColumnDefinition x:Name="detailViewColumn" Width="4*" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition x:Name="treeViewRow" Height="8*" />
<RowDefinition x:Name="controlRow" Height="2*" />
</Grid.RowDefinitions>
<ScrollViewer x:Name="WrapViewer" Grid.Row="0" Grid.Column="0" Padding="{StaticResource DetailPageMargin}">
</ScrollViewer>
<winui:TreeView
x:Name="treeView"
Grid.Row="0"
SelectionMode="Single"
ItemsSource="{x:Bind ViewModel.openOrders}"
ItemTemplateSelector="{StaticResource TreeViewTemplateSelector}">
<i:Interaction.Behaviors>
<behaviors:TreeViewCollapseBehavior x:Name="collapseBehavior" />
<ic:EventTriggerBehavior EventName="ItemInvoked">
<ic:InvokeCommandAction Command="{x:Bind ViewModel.ItemInvokedCommand}" />
</ic:EventTriggerBehavior>
</i:Interaction.Behaviors>
</winui:TreeView>
</Grid>
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition x:Name="detailViewRow" Height="4*" />
<RowDefinition x:Name="iarRow" Height="4*" />
<RowDefinition x:Name="controlRow2" Height="2*" />
</Grid.RowDefinitions>
</Grid>
</Grid>
正在绑定collection
public ObservableCollection<Order> openOrders { get; } = new ObservableCollection<Order>();
public async Task LoadDataAsync()
{
var data2 = await OrderDataLoader.GetTreeViewDataAsync();
foreach (var item in data2)
{
openOrders.Add(item);
}
}
DataTemplateSelector 代码:
public class SampleDataTemplateSelector : DataTemplateSelector
{
public DataTemplate OrderDetailTemplate { get; set; }
public DataTemplate SKUDetailTemplate { get; set; }
public DataTemplate LocationDetailTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item)
{
return GetTemplate(item) ?? base.SelectTemplateCore(item);
}
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
return GetTemplate(item) ?? base.SelectTemplateCore(item, container);
}
private DataTemplate GetTemplate(object item)
{
switch (item)
{
case Order order:
return OrderDetailTemplate;
case SKU sku:
return SKUDetailTemplate;
case Location location:
return LocationDetailTemplate;
}
return null;
}
}
更新
我实际上已经尝试了两种不同的尝试来让用户控件工作。两者都导致仅显示一层。
尝试 #1 用户控件 XAML:
<UserControl
x:Class="PickSheetManager.Controls.OrderTreeItemControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:winui="using:Microsoft.UI.Xaml.Controls"
xmlns:model="using:PickSheetManager.Core.Models"
xmlns:behaviors="using:PickSheetManager.Behaviors"
xmlns:templateSelectors="using:PickSheetManager.TemplateSelectors"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:controls1="using:PickSheetManager.Controls"
xmlns:ic="using:Microsoft.Xaml.Interactions.Core"
xmlns:i="using:Microsoft.Xaml.Interactivity"
mc:Ignorable="d">
<UserControl.Resources>
<DataTemplate x:Name="OrderTemplate" x:DataType="model:Order">
<StackPanel x:Name="stack" Orientation="Horizontal">
<i:Interaction.Behaviors>
<ic:DataTriggerBehavior Binding ="{x:Bind NotEnoughInventory}" Value="True">
<ic:ChangePropertyAction TargetObject="{Binding ElementName=stack}" PropertyName="Background" Value="Red" />
</ic:DataTriggerBehavior>
</i:Interaction.Behaviors>
<CheckBox IsChecked="{x:Bind IsSelected, Mode=TwoWay}" Padding="5" MinWidth="0"/>
<TextBlock Text="PoIDx: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind PoIDx}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Delivery: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind DeliveryType}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Delivery: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind DeliveryType}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Type: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind OrderType}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Total Quantity: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind TotalQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Printed: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind IsPrinted}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Notes: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBox Text="{x:Bind Notes, Mode=TwoWay}" Margin="{StaticResource XXSmallTopRightBottomMargin}" Width="150"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Name="SKUTemplate" x:DataType="model:SKU">
<StackPanel x:Name="stack2" Orientation="Horizontal">
<i:Interaction.Behaviors>
<ic:DataTriggerBehavior Binding ="{x:Bind NotEnoughInventory}" Value="True">
<ic:ChangePropertyAction TargetObject="{Binding ElementName=stack2}" PropertyName="Background" Value="Yellow" />
</ic:DataTriggerBehavior>
</i:Interaction.Behaviors>
<CheckBox IsChecked="{x:Bind IsSelected, Mode=TwoWay}" Padding="5" MinWidth="0" />
<TextBlock Text="SKU: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind SKUNum}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Needed: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind NeedQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Available: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind AvailableQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Name="LocationTemplate" x:DataType="model:Location">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{x:Bind IsSelected, Mode=TwoWay}" Padding="5" MinWidth="0" />
<TextBlock Text="{x:Bind LocationName}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Pick Type: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind PickType}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Pick Quantity: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind PickQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Available Quantity: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind AvailableQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBox Text="{x:Bind Notes, Mode=TwoWay}" Margin="{StaticResource XXSmallTopRightBottomMargin}" Width="150" />
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<Grid>
<ContentControl x:Name="MainContent"/>
</Grid>
</UserControl>
尝试 #1 .cs
namespace PickSheetManager.Controls
{
public sealed partial class OrderTreeItemControl : UserControl
{
public OrderTreeItemControl()
{
this.InitializeComponent();
}
public Order Data
{
get { return (OpenOrdersBase)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(OpenOrdersBase), typeof(OrderTreeItemControl), new PropertyMetadata(null, new PropertyChangedCallback(Data_Changed)));
private static void Data_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue != null)
{
var instance = d as OrderTreeItemControl;
if (e.NewValue is Location)
{
instance.MainContent.ContentTemplate = instance.LocationTemplate;
}
else if (e.NewValue is SKU)
{
instance.MainContent.ContentTemplate = instance.SKUTemplate;
}
else
{
instance.MainContent.ContentTemplate = instance.OrderTemplate;
}
}
}
}
}
尝试 #1 模型 类
public class OpenOrdersBase
{
public ObservableCollection<Order> Orders { get; } = new ObservableCollection<Order>();
}
public class Order : OpenOrdersBase
{
public bool IsSelected { get; set; }
public string OrderNumber { get; set; }
public string PoIDx { get; set; }
...
public ICollection<SKU> SKUs { get; set; }
}
public class SKU : OpenOrderBase
{
public bool IsSelected { get; set; }
public string SKUNum { get; set; }
...
public ICollection<Location> Locations { get; set; }
}
public class Location : OpenOrdersBase
{
public bool IsSelected { get; set; }
...
public string Notes { get; set; }
}
尝试 #1 页 XAML
<DataTemplate x:Key="BaseTemplate" x:DataType="model:Order">
<winui:TreeViewItem
IsExpanded="False"
ItemsSource="{x:Bind SKUs}">
<controls1:TestControl Data="{Binding}"/>
</winui:TreeViewItem>
</DataTemplate>
...
<winui:TreeView
x:Name="treeView"
Grid.Row="0"
SelectionMode="Single"
Margin="10,10,10,10"
ItemsSource="{x:Bind ViewModel.openOrders}"
ItemTemplate="{StaticResource BaseTemplate}">
<i:Interaction.Behaviors>
<behaviors:TreeViewCollapseBehavior x:Name="collapseBehavior" />
<ic:EventTriggerBehavior EventName="ItemInvoked">
<ic:InvokeCommandAction Command="{x:Bind ViewModel.ItemInvokedCommand}" />
</ic:EventTriggerBehavior>
</i:Interaction.Behaviors>
</winui:TreeView>
尝试 #2 最大的区别在于用户控件 XAML 和模型 用户控件 XAML
<UserControl
x:Class="PickSheetManager.Controls.OrderTreeItemControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:winui="using:Microsoft.UI.Xaml.Controls"
xmlns:model="using:PickSheetManager.Core.Models"
xmlns:behaviors="using:PickSheetManager.Behaviors"
xmlns:templateSelectors="using:PickSheetManager.TemplateSelectors"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:controls1="using:PickSheetManager.Controls"
xmlns:ic="using:Microsoft.Xaml.Interactions.Core"
xmlns:i="using:Microsoft.Xaml.Interactivity"
mc:Ignorable="d">
<UserControl.Resources>
<DataTemplate x:Name="OrderTemplate" x:DataType="model:Order">
<winui:TreeViewItem
AutomationProperties.Name="{x:Bind PoIDx}"
ItemsSource="{x:Bind SKUs}"
IsExpanded="True">
<StackPanel x:Name="stack" Orientation="Horizontal">
<i:Interaction.Behaviors>
<ic:DataTriggerBehavior Binding ="{x:Bind NotEnoughInventory}" Value="True">
<ic:ChangePropertyAction TargetObject="{Binding ElementName=stack}" PropertyName="Background" Value="Red" />
</ic:DataTriggerBehavior>
</i:Interaction.Behaviors>
<CheckBox IsChecked="{x:Bind IsSelected, Mode=TwoWay}" Padding="5" MinWidth="0"/>
<TextBlock Text="PoIDx: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind PoIDx}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Delivery: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind DeliveryType}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Delivery: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind DeliveryType}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Type: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind OrderType}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Total Quantity: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind TotalQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Printed: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind IsPrinted}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Notes: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBox Text="{x:Bind Notes, Mode=TwoWay}" Margin="{StaticResource XXSmallTopRightBottomMargin}" Width="150"/>
</StackPanel>
</winui:TreeViewItem>
</DataTemplate>
<DataTemplate x:Name="SKUTemplate" x:DataType="model:SKU">
<winui:TreeViewItem
AutomationProperties.Name="{x:Bind SKUNum}"
ItemsSource="{x:Bind Locations}"
IsExpanded="True">
<StackPanel x:Name="stack2" Orientation="Horizontal">
<i:Interaction.Behaviors>
<ic:DataTriggerBehavior Binding ="{x:Bind NotEnoughInventory}" Value="True">
<ic:ChangePropertyAction TargetObject="{Binding ElementName=stack2}" PropertyName="Background" Value="Yellow" />
</ic:DataTriggerBehavior>
</i:Interaction.Behaviors>
<CheckBox IsChecked="{x:Bind IsSelected, Mode=TwoWay}" Padding="5" MinWidth="0" />
<TextBlock Text="SKU: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind SKUNum}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Needed: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind NeedQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Available: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind AvailableQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
</StackPanel>
</winui:TreeViewItem>
</DataTemplate>
<DataTemplate x:Name="LocationTemplate" x:DataType="model:Location">
<winui:TreeViewItem
AutomationProperties.Name="{x:Bind LocationName}"
IsExpanded="True">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{x:Bind IsSelected, Mode=TwoWay}" Padding="5" MinWidth="0" />
<TextBlock Text="{x:Bind LocationName}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Pick Type: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind PickType}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Pick Quantity: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind PickQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="Available Quantity: " Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBlock Text="{x:Bind AvailableQuantity}" Margin="{StaticResource XXSmallTopRightBottomMargin}" />
<TextBox Text="{x:Bind Notes, Mode=TwoWay}" Margin="{StaticResource XXSmallTopRightBottomMargin}" Width="150" />
</StackPanel>
</winui:TreeViewItem>
</DataTemplate>
</UserControl.Resources>
<Grid>
<ContentControl x:Name="MainContent"/>
</Grid>
</UserControl>
在用户控件的代码中,我只是将 OpenOrdersBase 更新为 Order,因为我删除了所有模型的继承。
最后页面 XAML 以这种方式更改
<DataTemplate x:Key="BaseTemplate" x:DataType="model:Order">
<controls1:TestControl Data="{Binding}"/>
</DataTemplate>
其实你的尝试1已经很接近成功了,只需要稍微修改一下就可以了。
这个问题出在class的定义上:
Order
、SKU
、Location
有一个共同的基数classOpenOperBase
,这很好,但是基数class应该提供一个通用的 属性,而不是一个特殊的 Order
集合。
试试这个:
public class OpenOrdersBase
{
public ObservableCollection<OpenOrdersBase> Children { get; set; } = new ObservableCollection<OpenOrdersBase>();
}
在你的Order
和SKU
class中,有一个sub-collection属性,将它们提取为一个单独的基础class集合属性,这将稍后在数据绑定中查看效果。
现在您可以删除 Order.SKUs
和 SKU.Locations
。
绑定时,TestControl
的内容不用改(保持attempt#1的写法),但TreeViewItem
模板需要改DataType
<DataTemplate x:DataType="models:OpenOrdersBase" x:Key="BaseTemplate">
<TreeViewItem ItemsSource="{x:Bind Children}">
<controls:TestControl Data="{Binding}"/>
</TreeViewItem>
</DataTemplate>
我们的大致思路如下:
- 由于
TreeViewItem
仅作为TreeView.Children
的 child 直接生效,因此尝试 #2 的方法不可取。 TreeView.ItemTemplate
属性影响所有内部children,所以在绑定TreeViewItem.ItemsSource
时,最好绑定一个基class集合,而不是比特定类型的集合(例如SKUs
)- 如果你想根据数据类型显示不同的模板,创建一个
UserControl
并在内部判断类型是一种可行的方法(你已经做到了)。
谢谢。