How to style different elements differently when using data template in xaml?

I would like my elements created from the datatemplate to look different depending on some properties in the model. For example, I want to display text in different colors or to present different images or a path drawing for each element that is generated. I know how to do this in general, but I'm looking for a solution that will allow the designer to edit visual details in Expression Blend without touching the code. For example, the simplest solution:

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

Where "MyImageSource" and "MyColor" are the properties of the element model (such as ImageSource and Brush), do not satisfy my needs, because I do not want to assign these values. I want the designer to do this. Instead of the MyImageSource and MyColor properties, my model will have a property of the ItemType or ItemStyle type of the enum or string type (or another type). I am not looking for a "religious" MVVM solution. My only requirement is to avoid the need for the designer to expect me to correct the code following his instructions, for example "change the color of an element of type X in list Y to #FFAACC" because it seems to violate the SoC rule.

EDIT (based on answers):

, bendewey - ItemsSource. , , , , . ( ), (xaml). . ?

+3
3

. , Forecolor="{Binding MyText, Converter=ColorFromText}. .

0

ItemTemplateSelector playbook WPF. :

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>

MainPage.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;
    }
}
+6

Afaik, DataTemplateSelector Blend. , .

The complete Blendable solution includes one custom control inherited from the ListBox and exposing a property (one or more, but one of them is simpler), which will regulate which data templates to apply. Then you edit the style for this list and add triggers. Inside a trigger (Property Trigger), you change the data template to one that matches the value of the trigger.

Example:

<Style x:Key="OrientedListStyle" TargetType="{x:Type local:OrientedListBox}">
<Setter Property="ItemTemplate" Value="{DynamicResource TemplateVertical}"/>
<Setter Property="ItemsPanel" Value="{DynamicResource PanelVertical}"/>

<Style.Triggers>
    <Trigger Property="Orientation" Value="Horizontal">
        <Setter Property="ItemTemplate" Value="{DynamicResource TemplateHorizontal}"/>
        <Setter Property="ItemsPanel" Value="{DynamicResource PanelHorizontal}"/>
    </Trigger>
</Style.Triggers>

0
source

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


All Articles