Linking data to a heterogeneous list

I have a UserControl WPF with a ListBox and a ContentPanel. The ListBox is tied to an ObservableCollection, which has apples and oranges.

What is considered the correct way to configure it, so if I select an apple, I see AppleEditor on the right, and if I select orange, the OrangeEditor icon appears in the content pane?

+3
source share
1 answer

I would suggest using DataTemplating to create and apply different editors. Depending on how different your “apples” and “oranges” are, I would recommend using a DataTemplateSelector . Also, if they have something like a Type property, you can also use DataTriggers to disable editors.

Allows you to customize a small sample with apples and oranges. They will have common properties, as well as several different properties. And then we can create an ObservableCollection of basic IFruits for use in the user interface.

public partial class Window1 : Window
{
    public ObservableCollection<IFruit> Fruits { get; set; }
    public Window1()
    {
        InitializeComponent();

        Fruits = new ObservableCollection<IFruit>();
        Fruits.Add(new Apple { AppleType = "Granny Smith", HasWorms = false });
        Fruits.Add(new Orange { OrangeType = "Florida Orange", VitaminCContent = 75 });
        Fruits.Add(new Apple { AppleType = "Red Delicious", HasWorms = true });
        Fruits.Add(new Orange { OrangeType = "Navel Orange", VitaminCContent = 130 });

        this.DataContext = this;
    }
}

public interface IFruit
{
    string Name { get; }
    string Color { get; }
}

public class Apple : IFruit
{
    public Apple() { }
    public string AppleType { get; set; }
    public bool HasWorms { get; set; }
    #region IFruit Members
    public string Name { get { return "Apple"; } }
    public string Color { get { return "Red"; } }
    #endregion
}

public class Orange : IFruit
{
    public Orange() { }
    public string OrangeType { get; set; }
    public int VitaminCContent { get; set; }
    #region IFruit Members
    public string Name { get { return "Orange"; } }
    public string Color { get { return "Orange"; } }
    #endregion
}

Then we can create a DataTemplateSelector that will simply check the Fruit type and assign the correct DataTemplate.

public class FruitTemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        string templateKey = null;

        if (item is Orange)
        {
            templateKey = "OrangeTemplate";
        }
        else if (item is Apple)
        {
            templateKey = "AppleTemplate";
        }

        if (templateKey != null)
        {
            return (DataTemplate)((FrameworkElement)container).FindResource(templateKey);
        }
        else
        {
            return base.SelectTemplate(item, container);
        }
    }
}

, , .

<Window x:Class="FruitSample.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:FruitSample"
    Title="Fruits"
    Height="300"
    Width="300">
<Window.Resources>

    <local:FruitTemplateSelector x:Key="Local_FruitTemplateSelector" />

    <DataTemplate x:Key="AppleTemplate">
        <StackPanel Background="{Binding Color}">
            <TextBlock Text="{Binding AppleType}" />
            <TextBlock Text="{Binding HasWorms, StringFormat=Has Worms: {0}}" />
        </StackPanel>
    </DataTemplate>

    <DataTemplate x:Key="OrangeTemplate">
        <StackPanel Background="{Binding Color}">
            <TextBlock Text="{Binding OrangeType}" />
            <TextBlock Text="{Binding VitaminCContent, StringFormat=Has {0} % of daily Vitamin C}" />
        </StackPanel>
    </DataTemplate>

</Window.Resources>

<DockPanel>
    <ListBox x:Name="uiFruitList"
             ItemsSource="{Binding Fruits}"
             DisplayMemberPath="Name" />
    <ContentControl Content="{Binding Path=SelectedItem, ElementName=uiFruitList}"
                    ContentTemplateSelector="{StaticResource Local_FruitTemplateSelector}"/>
</DockPanel>
</Window>
+5

Source: https://habr.com/ru/post/1710610/


All Articles