Data mapping not updated when changing using storyboard?

I have an instance of the MyBool class with the IsTrue property stored as StaticResource. And I also have a CheckBox with the IsChecked property bound to the class instance.

{Binding IsTrue, Mode=TwoWay, Source={StaticResource MyBoolInstance}} 

It works great. If I change the check property to CheckBox, the instance of MyBool will also be updated and vice versa.

However, if I manipulate the IsChecked CheckBox property through the StoryBoard

 <Storyboard x:Key="ColourToggle"> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="IsChecked" Storyboard.TargetName="ThisCheckBox"> <DiscreteObjectKeyFrame KeyTime="0"> <DiscreteObjectKeyFrame.Value> <System:Boolean>True</System:Boolean> </DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame> </ObjectAnimationUsingKeyFrames> </Storyboard> 

The IsTrue property of the MyBool instance is not updated!

Any suggestions or workarounds?

+4
source share
2 answers

Here is an example that fully reproduces your problem:

 <StackPanel> <StackPanel.Resources> <l:MyBool x:Key="MyBool" IsTrue="False" /> </StackPanel.Resources> <CheckBox x:Name="myCheckBox" Content="{Binding RelativeSource={RelativeSource Mode=Self}, Path=IsChecked}" IsChecked="{Binding Source={StaticResource MyBool}, Path=IsTrue, Mode=TwoWay}" HorizontalAlignment="Center" VerticalAlignment="Top"> <CheckBox.Triggers> <EventTrigger RoutedEvent="UIElement.MouseEnter"> <BeginStoryboard x:Name="isCheckedBeginStoryboard"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="IsChecked"> <DiscreteObjectKeyFrame KeyTime="0"> <DiscreteObjectKeyFrame.Value> <System:Boolean>True</System:Boolean> </DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame> </ObjectAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger> <EventTrigger RoutedEvent="UIElement.MouseLeave"> <StopStoryboard BeginStoryboardName="isCheckedBeginStoryboard" /> </EventTrigger> </CheckBox.Triggers> </CheckBox> <CheckBox Content="Also two way binding to MyBool.IsTrue no animation" IsChecked="{Binding Source={StaticResource MyBool}, Path=IsTrue}" /> <TextBlock Text="{Binding Source={StaticResource MyBool}, Path=IsTrue, StringFormat={}MyBool.IsTrue: {0}}" /> <TextBlock Text="{Binding ElementName=myCheckBox, Path=IsChecked, StringFormat={}myCheckBox.IsChecked: {0}}" /> </StackPanel> 

Where MyBool is a simple class that also implements INotifyPropertyChanged :

 public class MyBool : INotifyPropertyChanged { private bool _isTrue; public bool IsTrue { get { return _isTrue; } set { if (_isTrue != value) { _isTrue = value; NotifyPropertyChanged("IsTrue"); } } } public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } 

As you can see from this run, when the animation is active, your StaticResource not updated when the animation is NOT active. This happens when the animation starts WPF, gives a new value for the IsChecked property (as defined by your Storyboard ). This effectively overrides the old value - two-way Binding to StaticResource . Once the animation has finished and stopped, WPF will return the old IsChecked value back to the original binding expression, so your MyBool resource will continue to receive updates.

An excellent article on prioritizing DependencyProperty values ​​can be found here:

http://msdn.microsoft.com/en-us/library/ms743230.aspx

Hope this helps!

+3
source

The problem is with the binding, not the user interface. You can try setting IsChecked to code-behind ThisCheckBox.IsChecked = true; and this will be ignored if you have XAML binding!

XAML:

 <Window x:Class="WpfApplication3.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300"> <Grid> <CheckBox x:Name="ThisCheckBox" IsChecked="{Binding IsTrue}" /> </Grid> 

code:

 public partial class Window1 : Window { public Window1() { InitializeComponent(); this.DataContext = new CData(); ThisCheckBox.ClearValue(CheckBox.IsCheckedProperty); //next will work only after clear binding ThisCheckBox.IsChecked = true; } } public class CData : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private bool _isTrue; public bool IsTrue { get { return _isTrue; } set { if (_isTrue != value) { _isTrue = value; OnPropertyChanged(new PropertyChangedEventArgs("IsTrue")); } } } protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, e); } } } 
+1
source

Source: https://habr.com/ru/post/1385518/


All Articles