.net - 在 xaml 中使用数据模板时如何对不同的项目设置不同的样式?

标签 .net silverlight data-binding xaml expression-blend

我希望从数据模板生成的元素根据模型中的某些属性看起来有所不同。例如,我想以各种颜色显示文本,或者为每个生成的元素呈现不同的图像或路径图。我知道一般情况下该怎么做,但我正在寻找一种解决方案,允许设计师在不接触代码的情况下编辑 Expression Blend 中的视觉细节。例如最简单的解决方案:

   <DataTemplate>
        <StackPanel Orientation="Horizontal"> 
            <Image Source="{Binding MyImageSource}"/>
            <TextBlock Width="200"  Text="{Binding MyText}" Forecolor="{Binding MyColor}"></TextBox> 
        </StackPanel> 
    </DataTemplate> 

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

编辑(根据答案):

我找到了与 bendewey 描述的解决方案类似的解决方案 here - 它需要使用 ItemsSource 属性为控件派生自定义控件。为每种元素类型使用不同的数据模板的想法很巧妙,但在我看来,它涵盖了我们想要为每个项目生成完全不同的视觉元素的情况。当元素仅在某些颜色和图像上有所不同(除此之外还包含许多公共(public)元素)时,为每种元素类型创建单独的数据模板会导致不必要的代码 (xaml) 重复。在这种情况下,弗拉德的解决方案更适合。 除了这两个还有别的技巧吗?

最佳答案

您可以从 WPF 剧本中窃取 ItemTemplateSelector 概念。这就是它的样子:

应用程序.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>

主页.xaml

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

<Grid x:Name="LayoutRoot">
    <local:CustomItemsControl ItemsSource="{Binding}" ItemTemplateSelector="{StaticResource PersonTemplateSelector}" />
</Grid>

MainPage.xaml.cs

public partial class MainPage : UserControl
{
    public MainPage()
    {
        InitializeComponent();
        this.DataContext = Person.GetSampleData();
    }
}

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

如果这是从那以后产生的东西并且您有兴趣使用您将需要使用此 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;
    }
}

关于.net - 在 xaml 中使用数据模板时如何对不同的项目设置不同的样式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2302250/

相关文章:

c# - 如何忽略 Silverlight 中的 SSL 证书错误?

.net - 我可以使用某些查看器来查看和搜索serilog日志文件吗?

asp.net - Global.asax Application_Error() 中要记录什么以及要忽略什么?

c# - 绑定(bind)到 ListBox 中已排序的 ObservableCollection<T>

css - 添加带有 css 绑定(bind)的动态类

wpf - 如何将数据网格行的背景绑定(bind)到特定颜色?

wpf - 有哪些方法可用于 WPF 中的虚拟设计时数据?

.net - LinkPoint 支付与 IIS7 的集成导致 w3wp.exe 崩溃

.net - 手动在ASCII和.NET字符之间转换

c# - 什么时候关闭 WCF 客户端?