WPF Custom DataTemplateSelector基于Custom UserControl中的Enum属性

时间:2017-03-14 18:12:10

标签: c# wpf xaml user-controls

我刚学会了创建自定义UserControls,我现在正在学习DataTemplates,仍然在学习属性,所以我可以想象控件属性的实现是错误的。

我已经开始创建名为ExtendedListBox的UserControl,它可以使用复选框或普通列表框显示其项目。以下是ExtendedListBox的实现。属性DisplayAs用于选择要使用的DataTemplate。

我已经在StackOverflow上看了很多与DataTemplateSelectors相关的问题,它现在让我质疑这个实现,这应该由ContentControl完成吗? (见:Bind a property to DataTemplateSelector

public partial class ExtendedListBox : UserControl
{
    public ExtendedListBoxDisplay DisplayAs { get; set; }

    public ExtendedListBox()
    {
        InitializeComponent();
    }
}

以下是用户控件的xaml,DataTemplates在UserControl资源中作为CheckedListBoxTemplate和ListBoxTemplate

<UserControl x:Class="UserControlTest.Configuration.Controls.ExtendedListBox"
             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:enums="clr-UserControlTest.Configuration.Enums"
             xmlns:local="clr-UserControlTest.Configuration.Controls"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:templateSelectors="clr-namespace:UserControlTest.Configuration.Controls.TemplateSelectors"
             x:Name="UcExtendedListBox"
             d:DesignHeight="84"
             d:DesignWidth="100"
             SizeChanged="ResizeControl"
             mc:Ignorable="d">
    <UserControl.Resources>
        <ResourceDictionary>
            <DataTemplate x:Key="CheckedListBoxTemplate" DataType="enums:ExtendedListBoxDisplay">
                <CheckBox IsChecked="{Binding IsChecked}">
                    <TextBlock Text="{Binding}" TextWrapping="Wrap" />
                </CheckBox>
            </DataTemplate>
            <DataTemplate x:Key="ListBoxTemplate" DataType="enums:ExtendedListBoxDisplay">
                <TextBlock Text="{Binding}" TextWrapping="Wrap" />
            </DataTemplate>
        </ResourceDictionary>
    </UserControl.Resources>
    <ListBox x:Name="LstItems"
             Grid.Row="2"
             Width="{Binding ActualWidth,
                             ElementName=UcExtendedListBox}"
             HorizontalAlignment="Center"
             VerticalAlignment="Center"
             HorizontalContentAlignment="Center"
             ScrollViewer.HorizontalScrollBarVisibility="Disabled"
             ScrollViewer.VerticalScrollBarVisibility="Visible"
             SelectionChanged="RaiseSelectionChanged">
                    <ItemsControl>
            <ItemsControl.ItemTemplateSelector>
                <templateSelectors:ExtendedListBoxDataTemplateSelector 
                        CheckedListBoxTemplate="{StaticResource CheckedListBoxTemplate}"
                        ListBoxTemplate="{StaticResource ListBoxTemplate}" />
            </ItemsControl.ItemTemplateSelector>
        </ItemsControl>
    </ListBox>
</UserControl>

这是DataTemplateSelector,它的实现相当简单。

public class ExtendedListBoxDataTemplateSelector : DataTemplateSelector
{
    public DataTemplate CheckedListBoxTemplate { get; set; }

    public DataTemplate ListBoxTemplate { get; set; }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        if (item == null)
        {
            return base.SelectTemplate(item, container);
        }

        var data = (ExtendedListBoxDisplay)item;

        switch (data)
        {
            case ExtendedListBoxDisplay.CheckedListBox:
                return CheckedListBoxTemplate;
            case ExtendedListBoxDisplay.ListBox:
                return ListBoxTemplate;
            default:
                return base.SelectTemplate(item, container);

        }
    }
}

所以我去运行它并且它不起作用,我猜它是因为我没有绑定项目和属性来寻找?作为DataTemplateSelectors的首次使用者,能不能指导我正确的方向?

非常感谢。

3 个答案:

答案 0 :(得分:0)

您应该将ItemsSource的{​​{1}}属性设置或绑定到ListBox(或实际为IEnumerable<ExtendedListBoxDisplay>):

IEnumerable<YourDataObject>

public partial class ExtendedListBox : UserControl { public ExtendedListBoxDisplay DisplayAs { get; set; } public ExtendedListBox() { InitializeComponent(); LstItems.ItemsSource = new List<ExtendedListBoxDisplay>() { new ExtendedListBoxDisplay() }; } } 集合中SelectTemplate类的ExtendedListBoxDataTemplateSelector方法将在ItemsSource集合中的每个项目中调用一次,并且您返回的DataTemplate将应用于此项目。

传递给方法的object参数是对ItemsSource中相应项的引用。

请注意,如果ExtendedListBoxDisplay实际上是枚举,则应修改SelectTemplate方法,并将ItemsSource设置为其他类型。

答案 1 :(得分:0)

基本上你必须将枚举值设置为dataTemplate。希望这个链接有所帮助,它提供了一些如何做到这一点的见解。 DataTemplate in case of Enum 希望这会有所帮助。

答案 2 :(得分:0)

首先,当您指定DataType的{​​{1}}时,您说该模板应仅应用于该类型的项目(或从该类型派生)。 因此,您需要做的第一件事就是从两个模板中删除DataTemplate

接下来,您需要修改模板选择器以使用绑定的DependancyObject而不是数据本身,因为您并不关心这些项目的数据类型。

E.g:

DataType="enums:ExtendedListBoxDisplay"

现在,我们现在期望该容器是public class ExtendedListBoxDataTemplateSelector : DataTemplateSelector { public DataTemplate CheckedListBoxTemplate { get; set; } public DataTemplate ListBoxTemplate { get; set; } public override DataTemplate SelectTemplate(object item, DependencyObject container) { if (container == null || !(container is ExtendedListBox)) { return base.SelectTemplate(item, container); } var listBox = (ExtendedListBox)container; switch (listBox.DisplayAs) { case ExtendedListBoxDisplay.CheckedListBox: return CheckedListBoxTemplate; case ExtendedListBoxDisplay.ListBox: return ListBoxTemplate; default: return base.SelectTemplate(item, container); } } } ,而不是期望该项成为ExtendedListBoxDisplay枚举。然后我们检查ExtendedListBox的DisplayAs属性,并使用它来确定要显示的模板。