WPF Trigger based on Object Type

28,784

Solution 1

Why not just use a converter that takes an object and returns a string of the object type?

Binding="{Binding SelectedItem, Converter={StaticResource ObjectToTypeString}}"

and define the converter as:

public class ObjectToTypeStringConverter : IValueConverter
{
    public object Convert(
     object value, Type targetType,
     object parameter, System.Globalization.CultureInfo culture)
    {
        return value.GetType().Name;            
    }

    public object ConvertBack(
     object value, Type targetType,
     object parameter, System.Globalization.CultureInfo culture)
    {
        // I don't think you'll need this
        throw new Exception("Can't convert back");
    }
}

You'll need to declare the static resource somewhere in your xaml:

<Window.Resources>
    <convs:ObjectToTypeStringConverter x:Key="ObjectToTypeString" />
</Window.Resources>

Where 'convs' in this case is the namespace of where the converter is.

Hope this helps.

Solution 2

This is based on @AndyG's answer but is a bit safer because it's strongly typed.

Implement an IValueConverter named DataTypeConverter, which accepts an object and returns its Type (as a System.Type):

public class DataTypeConverter:IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, 
      CultureInfo culture)
    {
        return value?.GetType() ?? Binding.DoNothing;
    }

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

Change your DataTrigger to use the Converter, and set the value to the Type:

<DataTrigger Binding="{Binding SelectedItem,  
      Converter={StaticResource DataTypeConverter}}" 
      Value="{x:Type local:MyType}">
...
</DataTrigger>

Declare DataTypeConverter in the resources:

<UserControl.Resources>
    <v:DataTypeConverter x:Key="DataTypeConverter"></v:DataTypeConverter>
</UserControl.Resources>

Solution 3

Not a trigger but this worked for me. (The trigger-approach didn't as it can't create a checkbox for a string. This is pretty much Thomas Levesque's suggestion)

using:

xmlns:mscorlib="clr-namespace:System;assembly=mscorlib"

  A CheckBox or TextBox depending on the type:

<ContentPresenter Content="{TemplateBinding SelectedItem}">
      <ContentPresenter.Resources>
               <DataTemplate DataType="{x:Type mscorlib:Boolean}">
                    <CheckBox Height="25" Width="25" HorizontalAlignment="Left" IsChecked="{Binding Path=.}"/>
               </DataTemplate>
                  <DataTemplate DataType="{x:Type mscorlib:String}">
                    <TextBox Height="25" Width="200" HorizontalAlignment="Left" Text="{Binding Path=.}"/>
                </DataTemplate>
       </ContentPresenter.Resources>
</ContentPresenter>

Note: for Greg Sansom's solution you either got to return the type as String or use mscorlib as above

Solution 4

Using a converter as suggested by AndyG is a good option. Alternatively, you could also use a different DataTemplate for each target type. WPF will automatically pick the DataTemplate that matches the object type

Solution 5

If you are in a position to modify the (base) type assigned to 'SelectedItem' by adding the property:

public Type Type => this.GetType();

Then you could use the DataTrigger in xaml like this:

<DataTrigger Binding="{Binding SelectedItem.Type}" Value="{x:Type local:MyClass}">
</DataTrigger>

Advantage compared to AndyG's good answer is, that you do not have a magic string of your type in XAML, but have everything compile safe. Disadvantage: You need to modify your model - which might not always be possible.

Share:
28,784

Related videos on Youtube

Exist
Author by

Exist

Updated on March 12, 2020

Comments

  • Exist
    Exist about 4 years

    Is there a way to do a comparison on object type for a trigger?

    <DataTrigger Binding="{Binding SelectedItem}" Value="SelectedItem's Type">
    </DataTrigger>
    

    Background: I have a Toolbar and I want to Hide button's depending on what subclass is currently set to the selected item object.

    Thanks

  • Thomas Levesque
    Thomas Levesque over 14 years
    +1 for the general idea, however the converter should return the Type object rather than its name...
  • AndyG
    AndyG over 14 years
    Would that work? Wouldn't the runtime be comparing something of type String to something of type Type? I know it handles converting/comparing most value types but not familiar with how it handles other Type comparisons.
  • Thomas Levesque
    Thomas Levesque over 14 years
    Yes, it would work, you just have to use the {x:Type} markup extension in the DataTrigger's value.
  • RobJohnson
    RobJohnson over 11 years
    This doesn't work for me. I get a XamlParseException if I try to use a mark up extension in DataTrigger.Value, so I have just used the string comparison method instead. See here: social.msdn.microsoft.com/Forums/en-US/wpf/thread/…
  • Viv
    Viv about 11 years
    Better check if value is null before trying to GetType(). return value != null ? value.GetType() : null;
  • Staeff
    Staeff almost 11 years
    But it will also affect every subelement of that datatype
  • Firo
    Firo over 10 years
    Binding="{Binding SelectedItem}" Converter={StaticResource DataTypeConverter}}" should be Binding="{Binding SelectedItem, Converter={StaticResource DataTypeConverter}}"
  • karmasponge
    karmasponge about 2 years
    Without some example XAML to demonstrate the use of the converter the answer from '@Greg Sansom' seems far more applicable/useful.