Триггер WPF на основе типа объекта

Есть ли способ сравнить тип объекта для триггера?

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

Фон: у меня есть панель инструментов, и я хочу скрыть кнопки в зависимости от того, какой подкласс в настоящее время установлен для выбранного объекта элемента.

Спасибо


person Exist    schedule 30.10.2009    source источник


Ответы (5)


Почему бы просто не использовать преобразователь, который принимает объект и возвращает строку типа объекта?

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

и определите преобразователь как:

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");
    }
}

Вам нужно будет объявить статический ресурс где-нибудь в вашем xaml:

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

Где «convs» в данном случае — это пространство имен, в котором находится преобразователь.

Надеюсь это поможет.

person AndyG    schedule 31.10.2009
comment
+1 за общую идею, однако преобразователь должен возвращать объект типа, а не его имя... - person Thomas Levesque; 31.10.2009
comment
Будет ли это работать? Не будет ли среда выполнения сравнивать что-то типа String с чем-то типа Type? Я знаю, что он обрабатывает преобразование/сравнение большинства типов значений, но не знаком с тем, как он обрабатывает другие сравнения типов. - person AndyG; 31.10.2009
comment
Да, это сработает, просто нужно использовать расширение разметки {x:Type} в значении DataTrigger. - person Thomas Levesque; 31.10.2009

Это основано на ответе @AndyG, но немного безопаснее, потому что оно строго типизировано.

Реализуйте IValueConverter с именем DataTypeConverter, который принимает объект и возвращает его тип (как 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();
    }
}

Измените свой DataTrigger, чтобы использовать Converter, и установите значение Type:

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

Объявите DataTypeConverter в ресурсах:

<UserControl.Resources>
    <v:DataTypeConverter x:Key="DataTypeConverter"></v:DataTypeConverter>
</UserControl.Resources>
person Greg Sansom    schedule 11.02.2011
comment
Это не работает для меня. Я получаю исключение XamlParseException, если пытаюсь использовать расширение разметки в DataTrigger.Value, поэтому вместо этого я просто использовал метод сравнения строк. См. здесь: социальный. msdn.microsoft.com/Forums/en-US/wpf/thread/ - person RobJohnson; 04.12.2012
comment
Перед попыткой GetType() лучше проверить, является ли значение null. возвращаемое значение != ноль? значение.GetType(): ноль; - person Viv; 18.03.2013
comment
Binding="{Binding SelectedItem}" Converter={StaticResource DataTypeConverter}}" должно быть Binding="{Binding SelectedItem, Converter={StaticResource DataTypeConverter}}" - person Firo; 19.08.2013

Не триггер, но это сработало для меня. (Триггерный подход не работает, поскольку он не может создать флажок для строки. Это в значительной степени предложение Томаса Левеска)

с использованием:

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

CheckBox или TextBox в зависимости от типа:

<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>

Примечание. Для решения Грега Сансома вам нужно либо вернуть тип как String, либо использовать mscorlib, как указано выше.

person mYnDstrEAm    schedule 10.09.2014

Использование конвертера, предложенного AndyG, является хорошим вариантом. В качестве альтернативы вы также можете использовать разные DataTemplate для каждого типа цели. WPF автоматически выберет DataTemplate, соответствующий типу объекта.

person Thomas Levesque    schedule 31.10.2009
comment
Но это также повлияет на каждый подэлемент этого типа данных. - person Staeff; 25.06.2013

Если вы можете изменить (базовый) тип, назначенный «SelectedItem», добавив свойство:

public Type Type => this.GetType();

Затем вы можете использовать DataTrigger в xaml следующим образом:

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

Преимущество по сравнению с хорошим ответом AndyG заключается в том, что у вас нет волшебной строки вашего типа в XAML, но все компилируется безопасно. Недостаток: вам нужно изменить свою модель, что не всегда возможно.

person sa.he    schedule 31.01.2019