在xaml中使用数据模板时,如何以不同方式设置不同的项目?

Pan*_*nek 3 .net data-binding silverlight xaml expression-blend

我希望从datatemplate生成的元素看起来有所不同,具体取决于模型中的某些属性.例如,我希望以各种颜色显示文本,或者为每个生成的元素显示不同的图像或路径绘图.我知道如何一般地做到这一点,但我正在寻找一种解决方案,允许设计师在不触及代码的情况下编辑Expression Blend中的视觉细节.例如最简单的解决方案:

   <DataTemplate>
        <StackPanel Orientation="Horizontal"> 
            <Image Source="{Binding MyImageSource}"/>
            <TextBlock Width="200"  Text="{Binding MyText}" Forecolor="{Binding MyColor}"></TextBox> 
        </StackPanel> 
    </DataTemplate> 
Run Code Online (Sandbox Code Playgroud)

其中'MyImageSource'和'MyColor'是项目模型(ImageSource和Brush类型)的属性,不能满足我的需求,因为我不想分配这些值.我希望设计师这样做.我的模型不是'MyImageSource'和'MyColor'属性,而是具有类型为enum或string(或其他类型)的'ItemType'或'ItemStyle'属性.我不是在寻找"宗教"MVVM的严格解决方案.我唯一的要求是避免设计师等待我按照他的指示纠正代码,例如"将列表Y中的X类型的项目颜色更改为#FFAACC",因为它似乎在某种程度上违反了SoC规则.

编辑(根据答案):

我找到了bendewey 在这里描述的类似解决方案- 它需要使用ItemsSource属性为控件派生自定义控件.为每种元素类型使用不同数据模板的想法很简洁,但在我看来,它涵盖了我们想要为每个项目生成完全不同的可视元素的情况.当元素仅在某些颜色和图像上有所不同(并且除此之外还包含许多常见元素),那么为每个元素类型创建单独的数据模板将导致不必要的代码(xaml)重复.在这种情况下,弗拉德的解决方案更适合.除了两个人之外还有其他技术吗?

ben*_*wey 6

您可以从WPF playbook中窃取ItemTemplateSelector概念.这就是这样:

App.xaml中

<DataTemplate x:Key="MaleTemplate">
    <StackPanel Orientation="Horizontal">
        <TextBlock Text="M - " />
        <TextBlock Text="{Binding Name}" />
    </StackPanel>
</DataTemplate>

<DataTemplate x:Key="FemaleTemplate">
    <StackPanel Orientation="Horizontal">
        <TextBlock Text="F - " />
        <TextBlock Text="{Binding Name}" />
    </StackPanel>
</DataTemplate>
Run Code Online (Sandbox Code Playgroud)

MainPage.xaml中

<UserControl.Resources>
    <local:PersonTemplateSelector x:Key="PersonTemplateSelector" />
</UserControl.Resources>

<Grid x:Name="LayoutRoot">
    <local:CustomItemsControl ItemsSource="{Binding}" ItemTemplateSelector="{StaticResource PersonTemplateSelector}" />
</Grid>
Run Code Online (Sandbox Code Playgroud)

MainPage.xaml.cs中

public partial class MainPage : UserControl
{
    public MainPage()
    {
        InitializeComponent();
        this.DataContext = Person.GetSampleData();
    }
}
Run Code Online (Sandbox Code Playgroud)

PersonTemplateSelector.cs

public class PersonTemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        var person = item as Person;
        if (person != null)
        {
            switch (person.Gender)
            {
                case Gender.Male:
                    return Application.Current.Resources["MaleTemplate"] as DataTemplate;
                case Gender.Female:
                    return Application.Current.Resources["FemaleTemplate"] as DataTemplate;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果这是因为你有兴趣使用它,你将需要使用这个CustomItemsControl,或一些变化:

CustomItemsControl.cs

public class CustomItemsControl : ItemsControl
{
    public DataTemplateSelector ItemTemplateSelector
    {
        get { return (DataTemplateSelector)GetValue(ItemTemplateSelectorProperty); }
        set { SetValue(ItemTemplateSelectorProperty, value); }
    }

    public static readonly DependencyProperty ItemTemplateSelectorProperty =
        DependencyProperty.Register("ItemTemplateSelector", typeof(DataTemplateSelector), typeof(CustomItemsControl), new PropertyMetadata(null));

    protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
    {
        ContentPresenter presenter = element as ContentPresenter;

        if (presenter != null)
        {
            DataTemplate itemTemplate = null;
            if (base.ItemTemplate != null)
            {
                itemTemplate = base.ItemTemplate;
            }
            else if (this.ItemTemplateSelector != null)
            {
                itemTemplate = this.ItemTemplateSelector.SelectTemplate(item, element);
            }

            presenter.Content = item;
            presenter.ContentTemplate = itemTemplate;
        }
    }
}

public class DataTemplateSelector
{
    public virtual DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)