WPF TextBox:如何将绑定模式默认更改为OneWay?

时间:2011-03-24 02:26:00

标签: wpf binding textbox binding-mode

最初,我有以下代码:

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

我知道我可以定义这样的风格:

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

所以我可以写:

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

因为这个文本框是只读的,所以绑定模式不能是双向的。那么,是否可以使用此样式将OneWay绑定作为我的TextBox的默认值?

编辑:我需要将绑定模式更改为OneWay,因为我的属性是get-only,而不是因为我标记了TextBox只读。但是,如果可能的话,我仍然希望将文本框的默认绑定模式更改为OneWay。


这是我遵循你的建议的代码,但它不起作用。我错过了什么吗?

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;            
    }
}

3 个答案:

答案 0 :(得分:4)

  

因为这个文本框是只读的,所以绑定模式不能是双向的。

为什么不呢? IsReadOnly将阻止用户修改Text,从而修改属性。请确保不要修改代码中的Text属性。

如果您继承TextBox,则可以阻止绑定属性更新。如果这样做,您可以覆盖TextBox.Text依赖项属性元数据。

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 });
    }

}

对于某些原因,将BindsTwoWayByDefault更改为false对我不起作用,但您可以将DefaultUpdateSourceTrigger设置为Explicit,这意味着除非通过代码完成绑定属性,否则不会更新绑定属性,从而有效地进行绑定OneWay。

答案 1 :(得分:2)

样式是一种将同一组自定义应用于UI对象的一个​​或多个属性的方法,例如背景,IsReadOnly等通常是依赖属性。

模式是Binding对象的属性,它不是UI对象。

  

您可以在任何元素上设置样式   派生自FrameworkElement或   FrameworkContentElement上。 - Source (MSDN)

所以这通常不是通过XAML / Styling完成的......我的猜测是你必须为它编写代码。虽然XAML允许您设置嵌套属性Text.Mode =“value”,但它容易出错(因为它假定Text已经设置为绑定对象)。如果Text属性返回一个没有Mode属性的对象,它将导致绑定异常 - 例如如果Text =“一个普通的字符串”。

如果你绝对必须拥有它,那么你需要以编程方式创建绑定。例如,您可以使用命名约定来查看backing属性是否具有setter,如果不是,则添加OneWay绑定。

答案 2 :(得分:2)

我知道这个问题真的很老了,但我最近自己遇到了这个问题,所以也许我也可以帮助其他人。

我想在Text属性上创建一个具有OneWayBinding的TextBox。 我发现这没有问题所示,因为WPF将现有的元数据和覆盖的元数据结合在一起,基本上将标志OR化在一起。 由于BindsTwoWayByDefault是其中一个标志,只要其中一个元数据对象具有BindsTwoWayByDefault = true就保持为真。

唯一的方法是在OverrideMetadata中进行WPF合并过程后更改元数据。 但是,元数据对象在方法中标记为“密封”。

任何优秀的开发者都会在这里停下来重新考虑...... Naaa,我用反射来“解封”元数据对象,并将BindsTwoWayByDefault设置为true。

如果有人知道更好的方法,请告诉我。

这是我的代码:

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