3

I have bound a ListBox to my ViewModel including the ListBox.SelectedItem. I want to change a visual state depending on if there is one selected or not, but The following doesn't update the state initially, so it stays in the wrong state:

<DataStateBehavior Binding="{Binding SelectedCamera}" Value="{x:Null}" TrueState="CameraSettingsUnselected" FalseState="CameraSettingsSelected"/>

Why is that and how to fix it?

Markus Hütter
  • 7,796
  • 1
  • 36
  • 63

2 Answers2

3

The problem here seems to be that the binding initially evaluates to null and thus doesn't fire the change notification required for the evaluation and state change.

I've fixed it with the following subclass:

public class FixedDataStateBehavior: DataStateBehavior
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.Loaded += (sender, routedEventArgs) =>
            {
                var bindingExpression = BindingOperations.GetBindingExpression(this, BindingProperty);
                SetCurrentValue(BindingProperty,new object());
                bindingExpression.UpdateTarget();
            };
    }
}

and used it like this:

<FixedDataStateBehavior Binding="{Binding SelectedCamera}" Value="{x:Null}" TrueState="CameraSettingsUnselected" FalseState="CameraSettingsSelected"/>
Markus Hütter
  • 7,796
  • 1
  • 36
  • 63
0

The answer above works, but I ended up creating a more generic Behavior class that would simply work with all bindings without needing to specify them individually.

public class RefreshDataContextBehavior : Behavior<FrameworkElement>
{
    protected override void OnAttached()
    {
        base.OnAttached();

        this.AssociatedObject.Loaded += AssociatedObject_Loaded;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();

        this.AssociatedObject.Loaded -= AssociatedObject_Loaded;
    }

    private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
    {
        var dc = this.AssociatedObject.DataContext;
        this.AssociatedObject.DataContext = null;
        this.AssociatedObject.DataContext = dc;
    }
}

Then simply insert it into the XAML like so on the object which has the DataContext:

<i:Interaction.Behaviors>
    <local:RefreshDataContextBehavior />
</i:Interaction.Behaviors>
Trevor Elliott
  • 11,292
  • 11
  • 63
  • 102
  • Be careful with OnDetaching(). It doesn't always fire when the behavior is being destroyed. If you add a this.AssociatedObject.UnLoaded event handler and unsubscribe everything there, you should be safe. – Mike Parkhill Dec 13 '16 at 22:57