Is there an easy way in WPF to bind VisualStates to enum values? Kinda like DataStateBehavior, but for an Enum?
The best way is to just go ahead and implement a Behavior that does just that -
public class EnumStateBehavior : Behavior<FrameworkElement>
{
public object EnumProperty
{
get { return (object)GetValue(EnumPropertyProperty); }
set { SetValue(EnumPropertyProperty, value); }
}
// Using a DependencyProperty as the backing store for EnumProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty EnumPropertyProperty =
DependencyProperty.Register("EnumProperty", typeof(object), typeof(EnumStateBehavior), new UIPropertyMetadata(null, EnumPropertyChanged));
static void EnumPropertyChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue == null) return;
EnumStateBehavior eb = sender as EnumStateBehavior;
VisualStateManager.GoToElementState(eb.AssociatedObject, e.NewValue.ToString(), true);
}
}
The usage is extremely simple - use as follows:
<i:Interaction.Behaviors>
<local:EnumStateBehavior EnumProperty="{Binding MyEnumProperty}" />
</i:Interaction.Behaviors>
null
or change it to EnumStateBehavior eb = (EnumStateBehavior)sender;
otherwise you could get a non-informative NullReferenceException
. –
Fitzpatrick You can do it in pure xaml by using a DataTrigger per possible enum value with each trigger calling GoToStateAction with a different state. See the example below. For more details take a look at Enum driving a Visual State change via the ViewModel.
<i:Interaction.Triggers>
<ei:DataTrigger Binding="{Binding ConfirmedAnswerStatus}" Value="Unanswered">
<ei:GoToStateAction StateName="UnansweredState" UseTransitions="False" />
</ei:DataTrigger>
<ei:DataTrigger Binding="{Binding ConfirmedAnswerStatus}" Value="Correct">
<ei:GoToStateAction StateName="CorrectlyAnsweredState" UseTransitions="True" />
</ei:DataTrigger>
<ei:DataTrigger Binding="{Binding ConfirmedAnswerStatus}" Value="Incorrect">
<ei:GoToStateAction StateName="IncorrectlyAnsweredState" UseTransitions="True" />
</ei:DataTrigger>
</i:Interaction.Triggers>
There is a DataStateSwitchBehavior in SL that could be ported to WPF: Anyone have a DataStateSwitchBehavior for WPF4?
the syntax is pretty straightforward:
<is:DataStateSwitchBehavior Binding="{Binding Orientation}">
<is:DataStateSwitchCase Value="Left" State="LeftState"/>
<is:DataStateSwitchCase Value="Right" State="RightState"/>
<is:DataStateSwitchCase Value="Down" State="DownState"/>
<is:DataStateSwitchCase Value="Up" State="UpState"/>
<is:DataStateSwitchCase/>
I was having issues with the above EnumStateBehavior answer.
The PropertyChanged handler will first trigger when the AssociatedObject is null (since the binding has been set up but the Behavior hasn't been attached yet). Also, even when the behavior is first attached, the target elements of the VisualState animation may not yet exist since the behavior may have been attached before other child visual trees.
The solution was to use the Loaded event on the associated object to ensure the binding's initial state is set.
public class EnumStateBehavior : Behavior<FrameworkElement>
{
public static readonly DependencyProperty BindingProperty =
DependencyProperty.Register(nameof(Binding), typeof(object), typeof(EnumStateBehavior), new UIPropertyMetadata(null, BindingPropertyChanged));
public object Binding
{
get { return (object)GetValue(BindingProperty); }
set { SetValue(BindingProperty, value); }
}
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.Loaded += AssociatedObject_Loaded;
}
protected override void OnDetaching()
{
this.AssociatedObject.Loaded -= AssociatedObject_Loaded;
base.OnDetaching();
}
private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
{
if (Binding != null)
GoToState();
}
private void GoToState()
{
VisualStateManager.GoToElementState(this.AssociatedObject, Binding.ToString(), true);
}
private static void BindingPropertyChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var eb = (EnumStateBehavior)sender;
if (e.NewValue == null || eb.AssociatedObject == null || !eb.AssociatedObject.IsLoaded)
return;
eb.GoToState();
}
}
© 2022 - 2024 — McMap. All rights reserved.