Я хочу проверить, что элемент ListBox
имеет определенный тип для назначения визуального стиля, но постоянная проверка не удалась. Может я неправильно делаю?
Проблема с этой строкой:
Condition Binding = "{Binding}" Value = "{x:Type econemodels:DishDTOAdvance}"
<ListBox.ItemTemplate>
<DataTemplate>
<ContentControl Content = "{Binding}">
<ContentControl.Style>
<Style TargetType = "ContentControl">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding = "{Binding}"
Value = "{x:Type econemodels:DishDTOAdvance}" />
</MultiDataTrigger.Conditions>
<Setter Property = "ContentTemplate"
Value = "{StaticResource DishNoImage}" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
</ListBox.ItemTemplate>
Связывание завершается неудачно, потому что оно связывает экземпляр типа DishDTOAdvance
и сравнивает его с экземпляр Type
, описывающим тип DishDTOAdvance
. Очевидно, что это разные типы, и условие никогда не бывает истинным. В XAML x:Type
похож на typeof()
или GetType()
в коде.
The
x:Type
markup extension has a similar function to thetypeof()
operator in C# or the GetType operator in Microsoft Visual Basic. Thex:Type
markup extension supplies a from-string conversion behavior for properties that take the type Type.
Именно так обстоит дело с кастомным DataTemplateSelector
, привязки не нужны.
Provides a way to choose a
DataTemplate
based on the data object and the data-bound element.
С помощью селектора шаблонов данных вы можете предоставить произвольную логику для выбора шаблона данных для элемента. В вашем случае оператора switch
для типа достаточно, чтобы выбрать шаблон, который можно найти через FindResource
в ресурсах вверх по визуальному дереву. Конечно, вы также можете назначать шаблоны данных через свойства, если не хотите искать во всех ресурсах.
public class TypeTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var contentPresenter = (ContentPresenter)container;
switch (item)
{
case DishDTOAdvance _:
return (DataTemplate)contentPresenter.FindResource("DishNoImage");
// ...other type cases.
default:
return base.SelectTemplate(item, container);
}
}
}
Создайте и добавьте экземпляр селектора шаблона данных в свой ListBox
. Полностью удалите ItemTemplate
, теперь он автоматически назначается селектором.
<ListBox ...>
<ListBox.ItemTemplateSelector>
<local:TypeTemplateSelector/>
</ListBox.ItemTemplateSelector>
<!-- ...other markup. -->
</ListBox>
ContentControl
является избыточным. Однако, если вам это нужно в шаблоне элемента, он работает точно так же. ContentControl
предоставляет свойство ContentTemplateSelector
для той же цели.
Бонусный раунд: триггер невозможен? Нет. Вы можете создать преобразователь, который возвращает тип.
public class TypeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value?.GetType();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new InvalidOperationException();
}
}
Создайте экземпляр преобразователя в словаре ресурсов в области видимости.
<Window.Resources>
<local:TypeConverter x:Key = "TypeConverter"/>
</Window.Resources>
Используйте преобразователь в привязке условия. Теперь типы сравниваются.
<Condition Binding = "{Binding Converter = {StaticResource TypeConverter}}"
Value = "{x:Type econemodels:DishDTOAdvance}"/>