dotMorten / WindowsStateTriggers

A collection of custom visual state triggers
MIT License
244 stars 59 forks source link

CompositeStateTrigger does not work with MVVM #38

Open deepea opened 9 years ago

deepea commented 9 years ago

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
    }
}
Chrissteven81 commented 8 years ago

I am having this same issue.

`

                                <WindowsStateTriggers:CompareStateTrigger Value="{Binding ConnectionStatus, Mode=OneWay}" CompareTo="Connected" Comparison="Equal"/>
                            </WindowsStateTriggers:CompositeStateTrigger>`
bezysoftware commented 8 years ago

Can you try {x:Bind} instead of {Binding} in the StateTrigger?

tibitoth commented 7 years ago

I have the same issue but with x:Bind it works. I have no idea why is classic Binding broken.

MatFillion commented 4 years ago

I observed the same thing, x:Bind works but not Binding.