简体   繁体   中英

How to apply different set of colors to each item in ItemsControl?

I have an ItemsControl and want each item to set its color theme based on data it contains. I have 2 resource dictionaries for 2 possible themes (Red and Blue) and a DataTemplate that defines how to apply those colors. How do I assign current resource dictionary for each row?

<Window x:Class="WpfApplication1.MainWindow"
        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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <ResourceDictionary>
            <!-- 2 dictionaries with style colors -->
            <ResourceDictionary x:Key="RedStyle">
                <SolidColorBrush x:Key="BorderBrush" Color="Red" />
                <SolidColorBrush x:Key="TextBrush" Color="Red" />
            </ResourceDictionary>

            <ResourceDictionary x:Key="BlueStyle">
                <SolidColorBrush x:Key="BorderBrush" Color="Blue" />
                <SolidColorBrush x:Key="TextBrush" Color="Blue" />
            </ResourceDictionary>

        </ResourceDictionary>
    </Window.Resources>
    <Grid>
        <ItemsControl ItemsSource="{Binding list}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Border BorderBrush="{StaticResource BorderBrush}">
                        <TextBlock Text="{Binding}" Foreground="TextBrush" />
                    </Border>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>        
    </Grid>
</Window>

Update: The DataTemplate and brush sets are much larger in my real project. What I'm trying to do is to avoid duplicating DataTemplate layout code while still being able to have 2 different color styles on it.

Pertinent to your task, you can apply DataTriggers like shown in the following example:

<ItemsControl.Style>
    <Style>
        <Style.Triggers>
            <DataTrigger Binding="{Binding Items.TheAttribute}" Value="AttributeValue1">
                <Setter Property="BorderBrush" Value="Red"/>
                <Setter Property="TextBrush" Value="Red"/>
            </DataTrigger>
            <DataTrigger Binding="{Binding Items.TheAttribute}" Value="AttributeValue2">
                <Setter Property="BorderBrush" Value="Blue"/>
                <Setter Property="TextBrush" Value="Blue"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</ItemsControl.Style>

In this example, you do not need the Styles specified in your ResourceDictionary .

Alternatively, you can use <Style.Triggers> to set the Style per your ResourceDictionary rather than setting the values of individual properties.

Hope this may help.

Note : You cannot apply ResourceDictionary conditionally, using Triggers.

You have four options at your disposable.

  1. Put your DataTemplate in single resource dictionary, or corresponding DataTemplate s in separate dictionaries.

     <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sys="clr-namespace:System;assembly=mscorlib"> <DataTemplate DataType="{x:Type sys:String}"> <TextBlock Text="{Binding .}"> <TextBlock.Style> <Style TargetType="TextBlock"> <Style.Triggers> <Trigger Property="Text" Value="Name1"> <Setter Property="Background" Value="Red"/> </Trigger> </Style.Triggers> </Style> </TextBlock.Style> </TextBlock> </DataTemplate> </ResourceDictionary> 

    Usage :

      <ItemsControl.Resources> <ResourceDictionary Source="RedStyle.xaml"/> </ItemsControl.Resources> 
  2. Use DataTemplateSelector to apply some complicated logic and assign DataTemplates accordingly. There are good tutorials on net on this.

  3. Use Blend Behaviors to do this using pure XAML.

  4. Use Loaded event of the control present in DataTemplate to load Res Dictionary using code. Simplest approach !

      <DataTemplate> <TextBlock Loaded="TextBlock_Loaded" Text="{Binding .}"/> </DataTemplate> 

    Code :

      private void TextBlock_Loaded(object sender, RoutedEventArgs e) { TextBlock tb = sender as TextBlock; if (tb.Text == "Name123") tb.Resources.MergedDictionaries.Add(new ResourceDictionary() { Source = new Uri("RedStyle.xaml", UriKind.Relative) }); } 

There is an AlternationCount:

<ItemsControl  ItemsSource="{Binding List}"
                  AlternationCount="2"
                  HorizontalContentAlignment="Stretch">

plus:

<DataTemplate.Triggers>
    <Trigger Property="ItemsControl.AlternationIndex" Value="0">
        <Setter Property="Background" Value="White" TargetName="Grid" />
    </Trigger>
    <Trigger Property="ItemsControl.AlternationIndex" Value="1">
        <Setter Property="Background" Value="#FFF1F1F1" TargetName="Grid" />
    </Trigger>
</DataTemplate.Triggers>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM