简体   繁体   English

在FrameworkPropertyMetadata中覆盖DefaultTwoWayByDefault

[英]Overriding DefaultTwoWayByDefault in FrameworkPropertyMetadata

I wanted to create a readonly TextBox that has a default OneWay Binding on its Text property. 我想创建一个只读的TextBox,其Text属性具有默认的OneWay绑定。 Like in a very similar question my first try was this: 就像在一个非常类似的问题中一样,我的第一次尝试是:

public partial class SelectableTextBlock : TextBox
{
    static SelectableTextBlock ()
    {
        TextBox.TextProperty.OverrideMetadata(typeof(ReadOnlyTextBox), 
            new FrameworkPropertyMetadata() { BindsTwoWayByDefault = false, Journal = true, DefaultUpdateSourceTrigger = UpdateSourceTrigger.Explicit }); 
    }
    public SelectableTextBlock()
    {
        InitializeComponent();
    }
}

I discovered that this is does not work because WPF combines the existing metadata and the overriding metadata by basically ORing all flags together. 我发现这是行不通的,因为WPF通过将所有标志进行基本“或”运算来将现有的元数据和覆盖的元数据合并在一起。 Since BindsTwoWayByDefault is one of those flags, as long as one of the Metadata objects has BindsTwoWayByDefault=true is stays true. 由于BindsTwoWayByDefault是这些标志之一,因此只要元数据对象之一具有BindsTwoWayByDefault = true便保持为true。

The only way around that is to change the Metadata after the WPF merging process takes places in OverrideMetadata. 解决此问题的唯一方法是在WPF合并过程发生后在OverrideMetadata中更改元数据。 However the Metadata object is marked as Sealed in the method. 但是,该方法中元数据对象被标记为“已密封”。

As any good developer would I stopped here and reconsidered... Naaa, I used reflection to "unseal" the metadata object and set the BindsTwoWayByDefault back to true. 作为任何优秀的开发人员,我都会在这里停下来并重新考虑... Naaa,我使用反射来“解封”元数据对象并将BindsTwoWayByDefault设置为true。

Please tell me that I am stupid and did not see the obvious and correct way of doing this in WPF. 请告诉我,我很愚蠢,没有在WPF中看到这样做的明显而正确的方法。

Here my code: 这是我的代码:

public partial class SelectableTextBlock : TextBox
{
    static SelectableTextBlock()
    {
        var defaultMetadata = (FrameworkPropertyMetadata)TextProperty.GetMetadata(typeof(TextBox));

        var newMetadata = new FrameworkPropertyMetadata(
            defaultMetadata.DefaultValue,
            FrameworkPropertyMetadataOptions.Journal,
            defaultMetadata.PropertyChangedCallback,
            defaultMetadata.CoerceValueCallback,
            defaultMetadata.IsAnimationProhibited,
            defaultMetadata.DefaultUpdateSourceTrigger);

        TextProperty.OverrideMetadata(typeof(SelectableTextBlock), newMetadata);

        //Workaround for a bug in WPF were the Metadata is merged wrongly and BindsTwoWayByDefault is always true
        var sealedProperty = typeof(PropertyMetadata).GetProperty("Sealed", BindingFlags.Instance | BindingFlags.NonPublic);
        sealedProperty.SetValue(newMetadata, false);
        newMetadata.BindsTwoWayByDefault = false;
        sealedProperty.SetValue(newMetadata, true);
    }

    public SelectableTextBlock()
    {
        InitializeComponent();
    }
}

因此,在尝试寻找更好的解决方案近一年之后,似乎我的反射解决方案仍然是最好的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM