tags:

views:

930

answers:

4

I have such WPF binding code:

TestModel source = new TestModel();
TestModel target = new TestModel();

Bind(source, target, BindingMode.OneWay);

source.Attribute = "1";
AssertAreEqual(target.Attribute, "1");

target.Attribute = "foo";

source.Attribute = "2";
AssertAreEqual(target.Attribute, "2");

The second assertion fails! This seems odd for me.

Also, I tried 'OneWayToSource' instead of 'OneWay', and all works as expected.

Bind(source, target, BindingMode.OneWayToSource);

target.Attribute = "1";
AssertAreEqual(source.Attribute, "1");

source.Attribute = "foo";

target.Attribute = "2";
AssertAreEqual(source.Attribute, "2");

Other details:

void Bind(TestModel source, TestModel target, BindingMode mode)
{
    Binding binding = new Binding();
    binding.Source = source;
    binding.Path = new PropertyPath(TestModel.AttributeProperty);
    binding.Mode = mode;
    BindingOperations.SetBinding(target, TestModel.AttributeProperty, binding);
}

class TestModel : DependencyObject
{
    public static readonly DependencyProperty AttributeProperty =
        DependencyProperty.Register("Attribute", typeof(string), typeof(TestModel), new PropertyMetadata(null));

    public string Attribute
    {
        get { return (string)GetValue(AttributeProperty); }
        set { SetValue(AttributeProperty, value); }
    }
}

What is wrong with my code?

+1  A: 

Not a binding expert but I believe you are running into a WPF dependency property precedence issues. It's likely that setting the value directly takes precedence over the binding value. That's why it overrides the binding.

Here's a full dependency property listing: http://msdn.microsoft.com/en-us/library/ms743230.aspx

JaredPar
It makes sence that value set throught style will override the template value, and the local value will override the style value, etc. But I have nothing of this. So not sure this explaines the issue... Thanks any way.
alex2k8
Also, this does not explain the difference between OneWay and OneWayToSource
alex2k8
A: 

If you set Binding Mode to OneWay, this means that the binding works only in one way: the target is updated when the source change.

But the target must be a dependency property, and the code you have is a CLR .NET property. You should set the value on the the target using the registered dependency property name, not just an ordinary .NET property name. The Jared's answer is quite right, this might bring confusion in resolving conflict between WPF dependency property and ordinary .NET CLR property.

If you follow the convention, the dependency property should be in the form of "propertyname"+property.

Example: TextProperty is "Text" dependency property of TextBox. Calling these in code should be:

TextBox1.TextProperty="value";

For more information on setting the source of Binding:

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

eriawan
I added the TestModel to avoid confustion... Also, please, see my Binding method - I am using the WPF depenency property. I use CLR property wrapper just to set the WPF property value... Also, TextBox1.TextProperty="value"; What do you mean? TextBox instance has only the Text property.
alex2k8
+3  A: 

Setting target.Attribute = "foo"; cleared the binding.

MSDN:

Not only do dynamic resources and bindings operate at the same precedence as a local value, they really are a local value, but with a value that is deferred. One consequence of this is that if you have a dynamic resource or binding in place for a property value, any local value that you set subsequently replaces the dynamic binding or binding entirely. Even if you call ClearValue to clear the locally set value, the dynamic resource or binding will not be restored. In fact, if you call ClearValue on a property that has a dynamic resource or binding in place (with no "literal" local value), they are cleared by the ClearValue call too.

alex2k8
A: 

Example: TextProperty is "Text" dependency property of TextBox. Calling these in code should be:

TextBox1.TextProperty="value";

WPF properties can be set two ways: by invoking DependencyObject.SetValue method (eg. instance.SetValue(TextProperty,"some text")) or using CLR Wrapper (eg. instance.Text="some text").

TextBox.TextProperty is a static DependencyProperty object, so you can't assign a string value to a reference type.

Vladimir