WPF TextBox: how to change default snap mode on OneWay?

First I have the following code:

<TextBox Text="{Binding LengthUnit, Mode=OneWay}" IsReadOnly="True" Background="{x:Static SystemColors.ControlBrush}" /> 

I know that I can define a style like this:

 <Style TargetType="{x:Type TextBox}" x:Key="readOnlyTextBox"> <Setter Property="Background" Value="{x:Static SystemColors.ControlBrush}"></Setter> <Setter Property="IsReadOnly" Value="True"></Setter> </Style> 

So, I can write:

 <TextBox Text="{Binding LengthUnit, Mode=OneWay}" Style="{StaticResource readOnlyTextBox}" /> 

Since this text field is read-only, the binding mode cannot be twoway. So, is it possible to bind OneWay as the default for my TextBox with this style?

EDIT: I need to change the binding mode to OneWay because my property has only get-only, and not because I marked the TextBox as read-only. However, I still want to change the default binding mode of the text box to OneWay, if possible.


this is the code that i follow your suggestion but it doesn't work. Did I miss something?

 public class ReadOnlyTextBox : TextBox { static ReadOnlyTextBox() { TextBox.TextProperty.OverrideMetadata(typeof(ReadOnlyTextBox), new FrameworkPropertyMetadata() { BindsTwoWayByDefault = false, Journal = true, DefaultUpdateSourceTrigger = UpdateSourceTrigger.Explicit }); } public ReadOnlyTextBox() { base.Background = SystemColors.ControlBrush; base.IsReadOnly = true; } } 
+7
source share
3 answers

Since this text field is read-only, the binding mode cannot be twoway.

Why not? IsReadOnly will not allow the user to modify the text and thereby modify the property. Just remember to change the Text property in the code.

You can prevent updates to the associated property if you subclass TextBox. If you do, you can override the metadata of the properties of the TextBox.Text property.

 public class TextBoxEx : TextBox { public TextBoxEx() : base() { } static TextBoxEx() { TextBox.TextProperty.OverrideMetadata(typeof(TextBoxEx), new FrameworkPropertyMetadata() { BindsTwoWayByDefault = false, Journal = true, DefaultUpdateSourceTrigger = System.Windows.Data.UpdateSourceTrigger.Explicit }); } } 

For some reasion, changing BindsTwoWayByDefault to false does not work for me, but you can set DefaultUpdateSourceTrigger to Explicit, which means that the related property will not be updated if it is done not by code, which effectively does OneWay binding.

+4
source

Styles are a way to apply the same set of settings to one or more properties for user interface objects, for example. Background, IsReadOnly, etc., which are usually dependency properties.

A mode is a property of a Binding object that is not a UI object.

You can set the style for any element that derives from FrameworkElement or FrameworkContentElement. - Source (MSDN)

So this is usually not done with XAML / Styling. I suppose you have to write code for it. Although XAML allows you to set the attached properties of Text.Mode = "value", it is error prone (since it assumes that Text is already installed in the binding object). This will result in a binding exception if the Text property returns an object that does not have a Mode property on it - for example. if Text = "simple string".

If you absolutely need this, then you will need to create the binding programmatically. For example, you can use the naming convention to find out if the backing property has a setter property and adds OneWay if it is not.

+2
source

I know this question is really old, but I recently ran into this problem myself, so maybe I can also help someone else.

I wanted to create a TextBox that has the OneWayBinding property by the Text property. I found that this does not work, as shown in the question, because WPF combines the existing metadata and advanced metadata together, mostly ORing flags together. Since BindsTwoWayByDefault is one of these flags, while one of the metadata objects has BindsTwoWayByDefault = true, true remains.

The only way is to change the metadata after the WPF consolidation process takes its place in OverrideMetadata. However, the Metadata object is marked as "Sealed" in the method.

Like any good developer, I would stop here and change my mind ... Naaa, I used reflection to β€œopen” the metadata object and return BindsTwoWayByDefault to true.

If anyone knows a better way to do this, please let me know.

Here is 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(); } } 
0
source

All Articles