6

I have various Style elements in my WPF XAML that are the same except for the data binding property, e.g.:

<Style x:Key="HasAlphaStyle" TargetType="TextBlock">
    <Style.Triggers>
        <DataTrigger Binding="{Binding Path=HasAlpha, UpdateSourceTrigger=PropertyChanged}" Value="True">
            <Setter Property="Background" Value="Red"/>
            <Setter Property="Foreground" Value="White"/>
            <Setter Property="FontWeight" Value="Bold"/>                   
        </DataTrigger>
        <DataTrigger Binding="{Binding Path=HasAlpha, UpdateSourceTrigger=PropertyChanged}" Value="False">
            <Setter Property="Background" Value="LightGreen"/>
            <Setter Property="Foreground" Value="Black"/>
            <Setter Property="FontWeight" Value="Normal"/>
        </DataTrigger>
    </Style.Triggers>
</Style>

<Style x:Key="HasBetaStyle" TargetType="TextBlock">
    <Style.Triggers>
        <DataTrigger Binding="{Binding Path=HasBeta, UpdateSourceTrigger=PropertyChanged}" Value="True">
            <Setter Property="Background" Value="Red"/>
            <Setter Property="Foreground" Value="White"/>
            <Setter Property="FontWeight" Value="Bold"/>                   
        </DataTrigger>
        <DataTrigger Binding="{Binding Path=HasBeta, UpdateSourceTrigger=PropertyChanged}" Value="False">
            <Setter Property="Background" Value="LightGreen"/>
            <Setter Property="Foreground" Value="Black"/>
            <Setter Property="FontWeight" Value="Normal"/>
        </DataTrigger>
    </Style.Triggers>
</Style>

The style is applied to a control like:

<TextBlock Style="{StaticResource HasAlphaStyle}" .../>

Is there a way I can consolidate my HasAlphaStyle and HasBetaStyle so that the property setters don't have to be duplicated? The only difference between the two is the Binding Path to the property.

Stealth Rabbi
  • 10,156
  • 22
  • 100
  • 176
  • 1
    Interesting question, is the purpose of consolidating so that you can just maintain one set of values for the setters? Do you want to be able to apply this to just TextBlocks or any FrameworkElement? – Dutts Apr 04 '13 at 15:07
  • 1. Yes; 2. Any set of setters that could be used repeatedly for any FrameworkElement – Stealth Rabbi Apr 04 '13 at 15:38

1 Answers1

3

I would create an attached property and have my triggers on that instead of having data triggers. Sample code as below:

Attached Property

public static class TextBlockBehavior
{
        public static readonly DependencyProperty HasValueProperty = 
            DependencyProperty.RegisterAttached("HasValue", typeof(bool), typeof(TextBlockBehavior),
            new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.None));

        public static void SetHasValue(DependencyObject depObject, bool value)
        {
            depObject.SetValue(HasValueProperty, value);
        }

        public static bool GetHasValue(DependencyObject depObject)
        {
            return (bool)depObject.GetValue(HasValueProperty);
        }
}

and then your combined style would become

<Style x:Key="HasValueStyle" TargetType="TextBlock">
    <Style.Triggers>
        <Trigger Property="behaviors:TextBlockBehavior.HasValue" Value="True">
            <Setter Property="Background" Value="Red"/>
            <Setter Property="Foreground" Value="White"/>
            <Setter Property="FontWeight" Value="Bold"/>                   
        </Trigger>
        <Trigger Property="behaviors:TextBlockBehavior.HasValue" Value="False">
            <Setter Property="Background" Value="LightGreen"/>
            <Setter Property="Foreground" Value="Black"/>
            <Setter Property="FontWeight" Value="Normal"/>
        </Trigger>
    </Style.Triggers>
</Style>

and you can write your textblocks as

<TextBlock Style="{StaticResource HasValueStyle}"
           behaviors:TextBlockBehavior.HasValue="{Binding Path=HasAlpha, UpdateSourceTrigger=PropertyChanged}"            .../>

<TextBlock Style="{StaticResource HasValueStyle}"
           behaviors:TextBlockBehavior.HasValue="{Binding Path=HasBeta, UpdateSourceTrigger=PropertyChanged}"            .../>
Suresh
  • 4,091
  • 28
  • 35
  • what is 'behaviors:'? is that a namespace? What namespace is TextBlockBehavior in? – Stealth Rabbi Apr 04 '13 at 18:45
  • @Stealth Rabbi - Yes it is a namespace, please refer to this aritcle [How to: Import a Namespace into XAML](http://msdn.microsoft.com/en-gb/library/bb514546(v=vs.90).aspx) about importing clr namespaces in XAML – Suresh Apr 04 '13 at 18:48
  • also, does TextBlockBehavior need to inherit from something? – Stealth Rabbi Apr 04 '13 at 18:49
  • Nope, its just a static class – Suresh Apr 04 '13 at 18:49
  • I have imported a namespace before, but I had to have the class I was importing at the root of the namespace / csproj, and not in a sub-directory for some reason. It seems I have to do this for my custom Behavior class, too. – Stealth Rabbi Apr 04 '13 at 18:52
  • It should work even if the importing class is not at the root and in a sub-directory/namespace. – Suresh Apr 04 '13 at 19:00
  • OK, I have my TextBlock set up to apply the value in the behavior. VS is complaining that: A 'Binding' cannot be used within a 'TextBlock' collection. A 'Binding' can only be set on a DependencyProperty of a DependencyObject. – Stealth Rabbi Apr 04 '13 at 19:14
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/27583/discussion-between-sthotakura-and-stealth-rabbi) – Suresh Apr 04 '13 at 19:15