WPF Trigger based on Object Type
Asked Answered
G

5

51

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

Gail answered 30/10, 2009 at 21:9 Comment(0)
O
39

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.

Outsole answered 31/10, 2009 at 2:40 Comment(4)
+1 for the general idea, however the converter should return the Type object rather than its name...Briquette
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.Outsole
Yes, it would work, you just have to use the {x:Type} markup extension in the DataTrigger's value.Briquette
Without some example XAML to demonstrate the use of the converter the answer from '@Greg Sansom' seems far more applicable/useful.Renie
B
64

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>
Bernt answered 11/2, 2011 at 4:40 Comment(3)
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/…Endgame
Better check if value is null before trying to GetType(). return value != null ? value.GetType() : null;Mulcahy
Binding="{Binding SelectedItem}" Converter={StaticResource DataTypeConverter}}" should be Binding="{Binding SelectedItem, Converter={StaticResource DataTypeConverter}}" Nickell
O
39

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.

Outsole answered 31/10, 2009 at 2:40 Comment(4)
+1 for the general idea, however the converter should return the Type object rather than its name...Briquette
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.Outsole
Yes, it would work, you just have to use the {x:Type} markup extension in the DataTrigger's value.Briquette
Without some example XAML to demonstrate the use of the converter the answer from '@Greg Sansom' seems far more applicable/useful.Renie
F
9

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

Floyfloyd answered 10/9, 2014 at 10:12 Comment(0)
B
5

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

Briquette answered 31/10, 2009 at 2:47 Comment(1)
But it will also affect every subelement of that datatypeRemonstrance
M
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.

Mammal answered 31/1, 2019 at 10:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.