简体   繁体   中英

Invalid Cast Exception in UWP Treeview C#

When using a treeview that is bound to a three tier hierarchical collection (Order - SKU - Location). I am using a DataTemplateSelector to choose the TreeViewItem template to use. I am getting an Invalid exception exactly the same as in this post when I scroll - the exception seems to occur faster if I scroll faster.

I have attempted both suggested solutions in that post (wrapping the treeview in a scroll viewer, and the custom user control). Wrapping the TreeView does not help, and I cannot get the custom user control solution to work correctly for me and I wonder if it is related to the fact I have a three tier collection instead of two tiers. The code for the custom UserControl is exactly the same as in the linked post except modified for my collection. When I try it it only binds one tier of the collection to the treeview. What I am looking for is a solution prevents the framework code from reusing the templates which appears to be what is causing the exception.

Here is my XAML and code for the TreeView that currently produces the exception:

<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>    

The collection being bound

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

And the DataTemplateSelector code:

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

Update

I have actually tried two different attempts to get the user control to work. Both resulted in only one tier being displayed.

Attempt #1 UserControl 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>

Attempt #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;
                }
            }
        }
    }
}

Attempt #1 Model Classes

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

Attempt #1 Page 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>

Attempt #2 The big difference was in the UserControl XAML and In the Models UserControl 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>

In the code for the user control I simply updated OpenOrdersBase to Order as I removed the inheritance from all the models.

Fianlly the Page XAML changed in this manner

<DataTemplate x:Key="BaseTemplate" x:DataType="model:Order">
    <controls1:TestControl Data="{Binding}"/>                                        
</DataTemplate>

In fact, your attempt 1 is very close to success, and only requires some minor modifications.

This problem lies in the definition of the class:

Order , SKU , Location have a common base class OpenOperBase , which is good, but the base class should provide a common property, rather than a special Order collection.

Try this:

public class OpenOrdersBase
{
    public ObservableCollection<OpenOrdersBase> Children { get; set; } = new ObservableCollection<OpenOrdersBase>();
}

In your Order and SKU class, there is a sub-collection attribute, extract them as a separate base class collection attribute, which will see the effect in the data binding later.

Now you can delete Order.SKUs and SKU.Locations .

When binding, the content of TestControl does not need to be changed (keep the wording in attempt#1), but the TreeViewItem template needs to change the DataType

<DataTemplate x:DataType="models:OpenOrdersBase" x:Key="BaseTemplate">
    <TreeViewItem ItemsSource="{x:Bind Children}">
        <controls:TestControl Data="{Binding}"/>
    </TreeViewItem>
</DataTemplate>

Our general idea is as follows:

  1. Since TreeViewItem only has effect directly as a child of TreeView.Children , the method of attempt #2 is not desirable.
  2. The TreeView.ItemTemplate property affects all internal children, so when binding TreeViewItem.ItemsSource , it is best to bind a base class collection, rather than a specific type of collection (such as SKUs )
  3. If you want to display different templates based on the data type, creating a UserControl and judging the type internally is a feasible way (you have already done it).

Thanks.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM