Home > Mobile >  MultiDataTrigger.Conditions Check binding type
MultiDataTrigger.Conditions Check binding type

Time:03-16

I want to check that the ListBox element has a specific type to assign a visual style to, but the constant check fails. Maybe I'm doing it wrong?

Problem with this line:

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>

CodePudding user response:

The binding fails, because it binds an instance of type DishDTOAdvance and compares it with an instance of Type that describes the DishDTOAdvance type. Obviously they are different types and the condition is never true. In XAML x:Type is like typeof() or GetType() in code.

The x:Type markup extension has a similar function to the typeof() operator in C# or the GetType operator in Microsoft Visual Basic. The x:Type markup extension supplies a from-string conversion behavior for properties that take the type Type.

That is exactly the case for a custom DataTemplateSelector, no need for bindings.

Provides a way to choose a DataTemplate based on the data object and the data-bound element.

With a data template selector you can provide arbitrary logic to choose a data template for an item. In your case a switch statement for the type is enough to choose a template that can be found through FindResource in the resources up the visual tree. Of course you could also assign data templates trough properties if you do not want to search in all resources.

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

Create and add an instance of the data template selector to your ListBox. Remove the ItemTemplate completely, it it now automatically assigned by the selector.

<ListBox ...>
   <ListBox.ItemTemplateSelector>
      <local:TypeTemplateSelector/>
   </ListBox.ItemTemplateSelector>
   <!-- ...other markup. -->
</ListBox>

The ContentControl is redundant. However in case you need it within an item template, it works just the same. ContentControl exposes an ContentTemplateSelector property for the same purpose.


Bonus round: Is the trigger impossible? No. You can create a converter that returns the type.

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

Create an instance of the converter in a resource dictionary in scope.

<Window.Resources>
   <local:TypeConverter x:Key="TypeConverter"/>
</Window.Resources>

Use the converter in the condition binding. Now types are compared.

<Condition Binding="{Binding Converter={StaticResource TypeConverter}}"
           Value="{x:Type econemodels:DishDTOAdvance}"/>
  • Related