rachelle
Topic Author
Posts: 4
Joined: 26 Mar 2021, 01:39

Trouble with DataTriggers when the bindings rarely -- if ever -- change

17 Aug 2022, 02:20

We are using an ObservableCollection that contains elements of type MyItem, where a MyItem contains a field called MyItemCategory that is an enum. In our xaml we have data triggers that look like this:
<b:DataTrigger Binding="{Binding MyItemCategory}" Comparison="Equal" Value="{x:Static definitions:MyItemCategory.None}">
  <b:GoToStateAction x:Name="MyItemCategoryNoneTrigger" StateName="MyItemCategoryNone" TargetName="Root"/>
</b:DataTrigger>
<b:DataTrigger Binding="{Binding MyItemCategory}" Comparison="Equal" Value="{x:Static definitions:MyItemCategory.CategoryA}">
  <b:GoToStateAction x:Name="MyItemCategoryATrigger" StateName="MyItemCategoryA" TargetName="Root"/>
</b:DataTrigger>
<b:DataTrigger Binding="{Binding MyItemCategory}" Comparison="Equal" Value="{x:Static definitions:MyItemCategory.CategoryB}">
  <b:GoToStateAction x:Name="MyItemCategoryBTrigger" StateName="MyItemCategoryB" TargetName="Root"/>
</b:DataTrigger>
<b:DataTrigger Binding="{Binding MyItemCategory}" Comparison="Equal" Value="{x:Static definitions:MyItemCategory.CategoryC}">
  <b:GoToStateAction x:Name="MyItemCategoryCTrigger" StateName="MyItemCategoryC" TargetName="Root"/>
</b:DataTrigger>
The category of each item can change at runtime, but in practice rarely does, which means the value of MyItemCategory isn't changing and therefore the above triggers aren't firing (I am assuming that the value is set before the view loads). We tried adding this trigger to account for that as a test:
<b:EventTrigger EventName="Loaded">
  <b:GoToStateAction x:Name="LoadedEventTrigger" StateName="MyItemCategoryA" TargetName="Root"/>
</b:EventTrigger>
With the above LoadedEventTrigger hack, the FIRST element of the list isn't properly transitioning into the MyItemCategoryA state, but all subsequent list elements are. Furthermore, there doesn't seem to be a way to switch states based on the bound value in MyItemCategory with this approach, so it doesn't really solve the problem.

Is there some other way we should go about doing this? Is there a bug here?
 
User avatar
sfernandez
Site Admin
Posts: 3364
Joined: 22 Dec 2011, 19:20

Re: Trouble with DataTriggers when the bindings rarely -- if ever -- change

17 Aug 2022, 11:35

Hi Rachelle,

DataTriggers will evaluate the binding the first time they are attached or when the data context changes, so it doesn't matter if the property in your items changes or not. The corresponding visual state should be activated depending on the current value of the property. If the visual state is not changing then it must be a bug.

I tried a simple example with a collection of items and similar data triggers and it works as expected, each item gets its own color depending on the category:
using System.Collections.ObjectModel;
using UnityEngine;
using Testing;

namespace Testing
{
    public enum ItemCategory
    {
        None,
        CategoryA,
        CategoryB,
        CategoryC
    }

    public class MyItem
    {
        public string Name { get; set; }
        public ItemCategory Category { get; set; }
    }

    public class VM
    {
        public ObservableCollection<MyItem> Items { get; set; }
    }
}

public class DataTriggerTest : MonoBehaviour
{
    void Start()
    {
        NoesisView view = GetComponent<NoesisView>();

        VM vm = new VM { Items = new ObservableCollection<MyItem>() };
        vm.Items.Add(new MyItem { Name = "Item1", Category = ItemCategory.CategoryA });
        vm.Items.Add(new MyItem { Name = "Item2", Category = ItemCategory.CategoryB });
        vm.Items.Add(new MyItem { Name = "Item3", Category = ItemCategory.CategoryB });
        vm.Items.Add(new MyItem { Name = "Item4", Category = ItemCategory.CategoryC });
        vm.Items.Add(new MyItem { Name = "Item5", Category = ItemCategory.CategoryA });
        vm.Items.Add(new MyItem { Name = "Item6", Category = ItemCategory.CategoryC });
        vm.Items.Add(new MyItem { Name = "Item7", Category = ItemCategory.CategoryB });
        vm.Items.Add(new MyItem { Name = "Item8", Category = ItemCategory.CategoryA });
        vm.Items.Add(new MyItem { Name = "Item9", Category = ItemCategory.CategoryC });

        view.Content.DataContext = vm;
    }
}
<Grid
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
  xmlns:local="clr-namespace:Testing">
  <Grid.Resources>
    <DataTemplate x:Key="itemTemplate">
      <Grid x:Name="root">
        <VisualStateManager.VisualStateGroups>
          <VisualStateGroup x:Name="CategoryStates">
            <VisualState x:Name="None">
              <Storyboard>
                <ColorAnimationUsingKeyFrames Storyboard.TargetName="bd" Storyboard.TargetProperty="Background.Color">
                  <EasingColorKeyFrame KeyTime="0" Value="Silver"/>
                </ColorAnimationUsingKeyFrames>
              </Storyboard>
            </VisualState>
            <VisualState x:Name="CategoryA">
              <Storyboard>
                <ColorAnimationUsingKeyFrames Storyboard.TargetName="bd" Storyboard.TargetProperty="Background.Color">
                  <EasingColorKeyFrame KeyTime="0" Value="Red"/>
                </ColorAnimationUsingKeyFrames>
              </Storyboard>
            </VisualState>
            <VisualState x:Name="CategoryB">
              <Storyboard>
                <ColorAnimationUsingKeyFrames Storyboard.TargetName="bd" Storyboard.TargetProperty="Background.Color">
                  <EasingColorKeyFrame KeyTime="0" Value="Green"/>
                </ColorAnimationUsingKeyFrames>
              </Storyboard>
            </VisualState>
            <VisualState x:Name="CategoryC">
              <Storyboard>
                <ColorAnimationUsingKeyFrames Storyboard.TargetName="bd" Storyboard.TargetProperty="Background.Color">
                  <EasingColorKeyFrame KeyTime="0" Value="Blue"/>
                </ColorAnimationUsingKeyFrames>
              </Storyboard>
            </VisualState>
          </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <Border x:Name="bd" Background="Black" Margin="2" Padding="20,10">
          <TextBlock Text="{Binding Name}" TextAlignment="Center" Foreground="White"/>
        </Border>
        <Decorator x:Name="interaction">
          <b:Interaction.Triggers>
            <b:DataTrigger Binding="{Binding Category}" Value="{x:Static local:ItemCategory.None}">
              <b:GoToStateAction TargetName="root" StateName="None"/>
            </b:DataTrigger>
            <b:DataTrigger Binding="{Binding Category}" Value="{x:Static local:ItemCategory.CategoryA}">
              <b:GoToStateAction TargetName="root" StateName="CategoryA"/>
            </b:DataTrigger>
            <b:DataTrigger Binding="{Binding Category}" Value="{x:Static local:ItemCategory.CategoryB}">
              <b:GoToStateAction TargetName="root" StateName="CategoryB"/>
            </b:DataTrigger>
            <b:DataTrigger Binding="{Binding Category}" Value="{x:Static local:ItemCategory.CategoryC}">
              <b:GoToStateAction TargetName="root" StateName="CategoryC"/>
            </b:DataTrigger>
          </b:Interaction.Triggers>
        </Decorator>
      </Grid>
    </DataTemplate>
  </Grid.Resources>
  <ItemsControl Width="200" Height="400" ItemsSource="{Binding Items}" ItemTemplate="{StaticResource itemTemplate}"/>
</Grid>
Could you please point me how to reproduce it in your repository so I can debug it?

Who is online

Users browsing this forum: No registered users and 2 guests