XAML binding doesn't seem to set if the property is initialized in the constructor

我与影子孤独终老i 提交于 2019-12-04 04:09:51
archimed7592

I've crossposted the problem at MSDN forums, someone there has suggested to create an issue at Microsft Connect... Long story short: the key mechanism I didn't clearly understand was DP's value precedence. It is perfectly described here (local value has higher priority than templated parent's value).

Second, not really obvious moment is that the value is considered as templated parent's if it was set by any template (not even element's own template).

HTH.

Maybe you should use TwoWay binding mode? What should you control do with "Some content"? It can not store it in your control's model since binding is OneWay. in your case binding sees that there is a value in your model's property and takes it overwriting "Some content". If don't initialize property, binding does nothing, because it ignores null values and you see "Some content". I hope my explanation is clear.

EDIT

Sorry for little misunderstanding of your problem. I've downloaded your demo app and reproduced the issue. Reading this and this MSDN articles shows that your intentions were right. However you can find there this words:

The following virtual methods or callbacks are potentially called during the computations of the SetValue call that sets a dependency property value: ValidateValueCallback, PropertyChangedCallback, CoerceValueCallback, OnPropertyChanged.

So, setting value of DependencyProperty in constructor potentially is as dangerous as calling a virtual method of object that is not constructed.

Ok, setting a DependencyProperty in constructor is bad. My next idea was to set value in some callback (I've used OnInitialized since it should be called right after Control's constructor). And I found another really strange behavior. If I don't set any value in constructor (this way)

    public CustomControl1()
    {
        //Content = "Initial1";
    }
    protected override void OnInitialized(EventArgs e)
    {
        Content = "Initial2";
        var check = Content; // after this  check == "Initial_2"
    }

I don't see "Initial2" in the window even if I don't specify any value for Content in Window1.xaml. Notice that value is set correctly (as you I see check it). But if I uncomment Content = "Initial1"; string, I see "Initial2". Also if I initialize Content in OnInitialized binding works fine, but it doesn't resolve that actual value of Content is "Initial2". Looks like its source is not that Content property.

I'll continue working around this issue later. I hope this information can be helpful.

Don't initialize the value in ctor, use CoerceValue()

In ctor

public SomeUserControl()
{
    InitializeComponent();
    CoerceValue(SomeProperty);    
}

SomeProperty Defenition

public static readonly DependencyProperty SomeProperty =
    DependencyProperty.Register(
        "Some", typeof(ObservableCollection<IModel>),
        typeof(SomeUserControl),
        new PropertyMetadata()
        {
            DefaultValue = null,
            PropertyChangedCallback = OnSomeChanged,
            CoerceValueCallback = OnCoerceSome
        }
    );

private static object OnCoerceSome(DependencyObject d, object baseValue)
{
    var v = (ObservableCollection<IModel>)baseValue;
    return v ?? new ObservableCollection<IModel>();
}   
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!