2016-12-13 3 views
2

Я хотел создать текстовое поле только для чтения, которое имеет свойство OneWay Binding по умолчанию в свойстве Text. Как в very similar question моей первой попытки был такой:Переопределение DefaultTwoWayByDefault в FrameworkPropertyMetadata

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

я обнаружил, что это не работает, потому что WPF объединяет существующие метаданные и первостепенные метаданные по существу ORing всех флагов вместе. Поскольку BindsTwoWayByDefault является одним из этих флагов, пока один из объектов метаданных имеет BindsTwoWayByDefault = true, остается true.

Единственный способ изменить метаданные после того, как процесс объединения WPF занимает место в OverrideMetadata. Однако объект Metadata отмечен как запечатанный в методе.

Как любой хороший разработчик, я бы остановился здесь и передумал ... Нааа, я использовал отражение, чтобы «распечатать» объект метаданных и вернуть BindsTwoWayByDefault в true.

Пожалуйста, скажите мне, что я глуп и не вижу очевидного и правильного способа сделать это в WPF.

Вот мой код:

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(); 
    } 
} 
+1

Действительно ли это цель сделать это инструкцией по коду? Я бы лучше определил стиль вашего дела и применил его по типу во всем содержимом вашей формы, если он соответствует вашим требованиям. –

+0

Я не уверен, что полностью понимаю, что вы имеете в виду. Но установка режима привязки по умолчанию для DependencyProperty может выполняться только в коде, а не в стиле. – Bluuu

+2

То, что он, вероятно, имел в виду, это игнорировать значение по умолчанию и каждый раз устанавливать его в OneWay, когда вам это нужно, чтобы избежать головной боли. – nkoniishvt

ответ

0

Так после попытки найти лучшее решение для почти года, кажется, что мой обходной путь с отражением по-прежнему является лучшим решением.

Смежные вопросы