How to get DataTemplate.DataTrigger to check for greater than or less than?

61,912

Solution 1

You could create an IValueConverter, which converts an integer to a boolean based on the CutOff. Then use DataTrigger.Value of True (or False, depending on what you are returning).

WPF DataTriggers are strictly equality comparers if I remember correctly.

So something similar to:

public class CutoffConverter : IValueConverter {
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
        return ((int)value) > Cutoff;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
        throw new NotImplementedException();
    }

    public int Cutoff { get; set; }
}

Then use the following XAML.

<Window.Resources>
    <myNamespace:CutoffConverter x:Key="AgeConverter" Cutoff="30" />
</Window.Resources>

<DataTemplate.Triggers>
    <DataTrigger Binding="{Binding Path=Age,
                                   Converter={StaticResource AgeConverter}}">
        <DataTrigger.Value>true</DataTrigger.Value>
        <Setter TargetName="Age" Property="Foreground" Value="Red"/> 
    </DataTrigger>
</DataTemplate.Triggers>

Solution 2

I'd recommend using an IValueConverter to bind to the Foreground element of the Age TextBlock and isolating the coloring logic there.

<TextBlock x:Name="Age"  
           Text="{Binding Age}" 
           Foreground="{Binding Path=Age, Converter={StaticResource AgeToColorConverter}}" />

Then in the Code:

[ValueConversion(typeof(int), typeof(Brush))]
public class AgeToColorConverter : IValueConverter
{
   public object Convert(object value, Type target)
   {
      int age;
      Int32.TryParse(value.ToString(), age);
      return (age >= 30 ? Brushes.Red : Brushes.Black);
   }
}

Solution 3

I believe there is a simpler way of acheiving the goal by using the powers of MVVM and INotifyPropertyChanged.


With the Age property create another property which will be a boolean called IsAgeValid. The IsAgeValid will simply be an on demand check which does not technically need an the OnNotify call. How?

To get changes pushed to the Xaml, place the OnNotifyPropertyChanged event to be fired for IsAgeValid within the Age setter instead.

Any binding to IsAgeValid will also have a notify message sent on any Age change subscriptions; which is what really is being looked at...


Once setup, of course bind the style trigger for false and true accordingly to the IsAgeValid result.

public bool IsAgeValid{ get { return Age > 30; } }

public int Age
{ 
  get { return _Age; }

  set
  {
   _Age=value;
   OnPropertyChanged("Age");   
   OnPropertyChanged("IsAgeValid"); // When age changes, so does the
                                    // question *is age valid* changes. So 
                                    // update the controls dependent on it.
   } 
 }

Solution 4

If possible, you could add a property to your model, that's the easiest way. Eg.

public int AgeBoundry
{
    get
    {
        if (Age < 30)
            return 0;
        else if (Age == 30)
            return 1;
        else
            return 2;
    }
}

then you can check on the value of the integer.

<DataTemplate.Triggers>
    <DataTrigger Binding="{Binding Path=Age}">
        <DataTrigger.Value>0</DataTrigger.Value>
        <Setter TargetName="Age" Property="Foreground" Value="Green"/> 
    </DataTrigger>
    <DataTrigger Binding="{Binding Path=Age}">
        <DataTrigger.Value>1</DataTrigger.Value>
        <Setter TargetName="Age" Property="Foreground" Value="Orange"/> 
    </DataTrigger>
    <DataTrigger Binding="{Binding Path=Age}">
        <DataTrigger.Value>2</DataTrigger.Value>
        <Setter TargetName="Age" Property="Foreground" Value="Red"/> 
    </DataTrigger>
</DataTemplate.Triggers>
Share:
61,912
Angry Dan
Author by

Angry Dan

web/software developer, .NET, C#, WPF, PHP, software trainer, English teacher, have philosophy degree, love languages, run marathons my tweets: http://www.twitter.com/edward_tanguay my runs: http://www.tanguay.info/run my code: http://www.tanguay.info/web my publications: PHP 5.3 training video (8 hours, video2brain) my projects: http://www.tanguay.info

Updated on July 09, 2022

Comments

  • Angry Dan
    Angry Dan almost 2 years

    The following DataTemplate.DataTrigger makes the age display red if it is equal to 30.

    How do I make the age display red if it is greater than 30?

    <DataTemplate DataType="{x:Type local:Customer}">
        <Grid x:Name="MainGrid" Style="{StaticResource customerGridMainStyle}">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="100"/>
                <ColumnDefinition Width="150"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <TextBlock Grid.Column="0" Grid.Row="0" Text="First Name" Margin="5"/>
            <TextBlock Grid.Column="1" Grid.Row="0" Text="{Binding FirstName}" Margin="5"/>
            <TextBlock Grid.Column="0" Grid.Row="1" Text="Last Name" Margin="5"/>
            <TextBlock Grid.Column="1" Grid.Row="1" Text="{Binding LastName}" Margin="5"/>
            <TextBlock Grid.Column="0" Grid.Row="2" Text="Age" Margin="5"/>
            <TextBlock x:Name="Age" Grid.Column="1" Grid.Row="2" Text="{Binding Age}" Margin="5"/>
        </Grid>
    
        <DataTemplate.Triggers>
            <DataTrigger Binding="{Binding Path=Age}">
                <DataTrigger.Value>30</DataTrigger.Value>
                <Setter TargetName="Age" Property="Foreground" Value="Red"/> 
            </DataTrigger>
        </DataTemplate.Triggers>
    
    </DataTemplate>
    
  • Denis Troller
    Denis Troller about 15 years
    alternatively you can use ConverterParameter to pass in the cutoff value if you need different values for different triggers: Binding="{Binding Path=Age, Converter={StaticResource AgeConverter}, ConverterParameter=30}"
  • CheapReference
    CheapReference about 7 years
    This should be the answer for this specific example. Where possible control properties that represent real business logic should be provided to the view through a ViewModel, not 'view side'. This allows values to be configured through configuration/database etc.
  • ΩmegaMan
    ΩmegaMan about 7 years
    @TomDeloford Having the business logic on the VM, makes sense to me as well.
  • ΩmegaMan
    ΩmegaMan over 4 years
    Where does Ageboundry come into effect on the triggers? Instead of binding to Age, shouldn't it be AgeBoundary?