Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In WPF two-way binding, how can you check if it was a UI element or ViewModel that triggered the binding change?

I'm not sure what keywords to search for...lost in a sea of Google.

I have a two-way databinding specified between a visual element (slider bar) and a numeric value in my ViewModel. I want to differentiate between when a value change is user-initiated vs ViewModel-based, so that I can selectively trigger an event elsewhere in my application. How can I do this in the code-behind of the XAML file?

Update 2015-02-26: In reply to Amit's question, WHY I need this capability is that I actually have more than one visual element set up for 2-way databinding to the same ViewModel source, so not differentiating leads to an infinite loop (stack overflow) in callbacks to dependent code that itself has the ability update the same values.

Aside - shouldn't there be reputation points for the first time one appropriately ues "stack overflow" on SO?

like image 890
lightw8 Avatar asked Jan 20 '15 02:01

lightw8


2 Answers

Your best bet is not to have two different behaviors. You need to fire the same notifications and recalculate the same dependent properties either way. But I've run into cases where, say, sometimes I want to fire off an animation and sometimes I don't, so different behaviors can be necessary.

If you really do need two different behaviors, I would just make two different properties (or a property and a method). Bind one property to the UI, and use the other when you're setting the value programmatically. Give each one the side effects it needs to have.

Not only does this keep things simple, it also means you can write unit tests for both sets of behaviors.

like image 59
Joe White Avatar answered Oct 23 '22 22:10

Joe White


I think the short answer is: not really.

When you bind to a ViewModel property from your XAML element, ultimately the WPF binding system will call the property setter in the ViewModel. Once inside the setter method you have no context as to how you got there. You could possibly check the stack to see where you came from but that would be very brittle code and presumably quite slow as well.

If the property was only being set by either the XAML binding or by the ViewModel, then you could set some kind of Boolean flag in your ViewModel like so:

bool _isBeingSetByVM;

public int Number
{
    get { return _number; }
    set
    {
        if (_isBeingSetByVM)
        {
            // ViewModel has set the property
            // Do whatever you need to do...
            _isBeingSetByVM = false;
        }

        if (_number != value)
        {
            _number = value;
            OnPropertyChanged("Number");  // generate PropertyChanged event
        }
    }
}
int _number;

void SomeMethodInVM()
{
    _isBeingSetByVM = true;
    Number = 42;
}

But again, this is very brittle code that is hard to maintain. As @Amit says in his comment, the better question might be why you need to do this.

like image 28
Steven Rands Avatar answered Oct 23 '22 22:10

Steven Rands