I have written a control with a bindable property. This control also has a method to modify that property's value:
public class MyControl : ContentView // WPF: inherited from UserControl
{
// Xamarin:
public static readonly BindableProperty MyValueProperty = ...
// WPF:
// public static readonly DependencyProperty MyValueProperty = ...
public int MyValue
{
get { return (int) GetValue(MyValueProperty); }
set { SetValue(MyValueProperty, value); }
}
public void Reset()
{
MyValue = 0;
}
}
I am using that control in a normal XAML page and update MyValue
via binding:
<local:MyControl x:Name="TheControl"
MyValue="{Binding MyValueSource, Mode=OneWay}" />
The binding initially propagates changes from MyValueSource
to MyValue
. But as soon as I call the Reset()
method once, the binding is overwritten by the 0
and updates to MyValueSource
are no longer pulled.
I suppose any direct assignment of MyValue
is intended to replace a OneWay
binding. With a TwoWay
binding, the change is just propagated back to MyValueSource
and the binding remains functional.
If Reset()
was in the view model, I could do this:
public void Reset()
{
// TheControl.MyValue = 0; // Bad practice, destroys the binding
MyValueSource = 0; // Good practice, preserves the binding
}
I don't want to implement the reset logic (which is more complex than in this reduced example) in every VM though, so it's located in the view/control.
So I wonder - can you assign a bindable property's value from the control's code behind and still preserve a possible OneWay
binding? I know this means the VM does not get the changed value; binding OneWay
is likely not correct if the control updates the property as well; you should rather use a TwoWay
binding then.
But if someone says OneWay
in XAML, I'd rather have it behave that way down to the wire than implement some "OneWay
until you call Reset()
" behavior.
Side note: I am working in Xamarin, but I guess the behavior is the same for WPF.
Taken and fleshed out from @Clemens' comment:
You can use the SetCurrentValue
method on an DependencyObject
(i. e. the control) to change the current effective value of a DependencyProperty
. Unlike SetValue
, with SetCurrentValue
any triggers, data bindings and styles to that property remain intact.
public void Reset()
{
// this.SetValue(MyValueProperty, 0); // Replaces the binding
this.SetCurrentValue(MyValueProperty, 0); // Keeps the binding
}
Remember that if you defined a OneWay
binding, the view model will not be notified about the changed value, and that any change to the VM's MyValueSource
property will override the control's value again (if the property is implemented correctly).
There is currently no proper way to assign a BindableProperty
's value without replacing a OneWay
binding attached to it. BindableObject
(the control's base class) does not have any method comparable to WPF's SetCurrentValue
and SetValue
will allways replace the binding.
However, if you change the binding to BindingMode.TwoWay
, the internal value change is propagated back to the view model. You should probably do this anyway to keep the control and the VM synchronized.
public void Reset()
{
// Replaces any OneWay bindings
// Updates MyValueSource for TwoWay bindings
this.SetValue(MyValueProperty, 0);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With