Skip to content

CompositeStateTrigger does not work with MVVM #38

@deepea

Description

@deepea

When trying to use CompositeStateTrigger with a ViewModel the PropertyChangedCallback of the Dependency Property of the inner StateTrigger is only fired once upon page load and never again. The examples in the TestApp project, which do not use MVVM and bind directly to the page elements, work as intended.

To Reproduce:

To reproduce the issue I have put together a simple example project. Please note that the EqualsStateTrigger should already use the fix mentioned in issue #37.

View - MainPage.xaml
<Page
    x:Class="TestComposite.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:TestComposite"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:wst="using:WindowsStateTriggers"
    mc:Ignorable="d">

    <Page.DataContext>
        <local:MainViewModel />
    </Page.DataContext>

    <Page.Resources>
        <x:Boolean x:Key="TrueValue">True</x:Boolean>
        <x:Boolean x:Key="FalseValue">False</x:Boolean>
    </Page.Resources>

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup>
                <VisualState>
                    <VisualState.StateTriggers>
                        <wst:CompositeStateTrigger Operator="And">
                            <wst:EqualsStateTrigger Value="{Binding IsOption1Checked}" EqualTo="{StaticResource TrueValue}" />
                            <wst:EqualsStateTrigger Value="{Binding IsOption2Checked}" EqualTo="{StaticResource TrueValue}" />
                        </wst:CompositeStateTrigger>
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Target="optionStatus.Text" Value="Both options are checked" />
                    </VisualState.Setters>
                </VisualState>
                <VisualState>
                    <VisualState.StateTriggers>
                        <wst:EqualsStateTrigger Value="{Binding IsOption1Checked}" EqualTo="{StaticResource TrueValue}" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Target="optionStatus.Text" Value="Option 1 is checked" />
                    </VisualState.Setters>
                </VisualState>
                <VisualState>
                    <VisualState.StateTriggers>
                        <wst:EqualsStateTrigger Value="{Binding IsOption2Checked}" EqualTo="{StaticResource TrueValue}" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Target="optionStatus.Text" Value="Option 2 is checked" />
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>

        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <CheckBox Grid.Row="0" Margin="3" Content="Option 1" IsChecked="{Binding IsOption1Checked, Mode=TwoWay}" />
        <CheckBox Grid.Row="1" Margin="3" Content="Option 2" IsChecked="{Binding IsOption2Checked, Mode=TwoWay}" />
        <TextBlock x:Name="optionStatus" Grid.Row="2" Margin="3"/>
    </Grid>
</Page>
ViewModel - MainViewModel.cs
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace TestComposite
{
    public class MainViewModel : INotifyPropertyChanged
    {
        public bool IsOption1Checked
        {
            get { return _isOption1Checked; }
            set
            {
                if (_isOption1Checked == value) return;

                _isOption1Checked = value;
                RaisePropertyChanged();
            }
        }
        private bool _isOption1Checked = false;

        public bool IsOption2Checked
        {
            get { return _isOption2Checked; }
            set
            {
                if (_isOption2Checked == value) return;

                _isOption2Checked = value;
                RaisePropertyChanged();
            }
        }
        private bool _isOption2Checked = false;

        #region INotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;

        public void RaisePropertyChanged([CallerMemberName]string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion INotifyPropertyChanged
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions