You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF自定义MyTextBox绑定失效:修改Text未触发AString setter原因?

问题

基于TextBox类创建了派生类MyTextBox,添加了名为AString的依赖属性和名为ContentChangedEvent的路由事件。在XAML代码中,将Text属性绑定到自身的AString属性(已设置TwoWay双向绑定模式),但修改Text属性值时,AString的setter并未触发,绑定未生效,请问这是什么原因?

C#代码:

public class MyTextBox : TextBox
{
    public static readonly RoutedEvent ContentChangedEvent;
    public event RoutedEventHandler ContentChanged
    {
        add { AddHandler(ContentChangedEvent, value); }
        remove { RemoveHandler(ContentChangedEvent, value); }
    }

    public string AString
    {
        get { return (string)GetValue(AStringProperty); }
        set
        {
            SetValue(AStringProperty, value);
            OnContentChanged();
        }
    }

    public static readonly DependencyProperty AStringProperty;

    static MyTextBox()
    {
        ContentChangedEvent = EventManager.RegisterRoutedEvent("ContentChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyTextBox));
        var a = new FrameworkPropertyMetadata("555");
        a.BindsTwoWayByDefault = true;
        AStringProperty = DependencyProperty.Register("AString", typeof(string), typeof(MyTextBox), a);
    }
    private void OnContentChanged()
    {
        RaiseEvent(new RoutedEventArgs(ContentChangedEvent, this));
    }
}

XAML代码:

<local:MyTextBox x:Name="mtb1"
                  ContentChanged="MyTextBox_ContentChanged"
                  Text="{Binding AString,
                                 RelativeSource={RelativeSource Mode=Self},
                                 Mode=TwoWay}" />

已尝试将绑定模式改为双向绑定,但问题仍未解决。

原因分析与解决方案

核心原因

  • WPF依赖属性的CLR包装器(即AString的get/set方法)不会被绑定系统调用。绑定系统直接通过GetValue和SetValue操作依赖属性的底层存储区,完全绕开了手动编写的setter逻辑,所以修改Text触发绑定更新时,AString的setter不会执行,OnContentChanged自然也不会被调用。
  • 另外,TextBox的Text属性默认UpdateSourceTrigger为LostFocus,如果在输入过程中直接查看AString值,可能会误以为绑定未生效,实际只有焦点离开控件后才会同步值到绑定源。

修复步骤

  1. 清理CLR包装器的额外逻辑:依赖属性的CLR包装器应该仅包含GetValue和SetValue,不能添加业务逻辑,因为绑定、动画等WPF内部操作都会跳过包装器。
  2. 用依赖属性元数据回调处理值变更:注册AStringProperty时,给FrameworkPropertyMetadata添加PropertyChangedCallback,通过这个回调响应属性值变化,触发路由事件。
  3. 可选:调整绑定的更新时机:如果需要输入时实时同步Text和AString,将绑定的UpdateSourceTrigger设为PropertyChanged。

修改后的C#代码

public class MyTextBox : TextBox
{
    public static readonly RoutedEvent ContentChangedEvent;
    public event RoutedEventHandler ContentChanged
    {
        add { AddHandler(ContentChangedEvent, value); }
        remove { RemoveHandler(ContentChangedEvent, value); }
    }

    public string AString
    {
        get { return (string)GetValue(AStringProperty); }
        set { SetValue(AStringProperty, value); } // 仅保留基础SetValue操作
    }

    public static readonly DependencyProperty AStringProperty;

    static MyTextBox()
    {
        ContentChangedEvent = EventManager.RegisterRoutedEvent("ContentChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyTextBox));
        
        var metadata = new FrameworkPropertyMetadata(
            defaultValue: "555",
            propertyChangedCallback: OnAStringChanged); // 添加值变更回调
        metadata.BindsTwoWayByDefault = true;
        AStringProperty = DependencyProperty.Register("AString", typeof(string), typeof(MyTextBox), metadata);
    }

    // 依赖属性值变更时触发的静态回调
    private static void OnAStringChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is MyTextBox textBox)
        {
            textBox.OnContentChanged();
        }
    }

    private void OnContentChanged()
    {
        RaiseEvent(new RoutedEventArgs(ContentChangedEvent, this));
    }
}

修改后的XAML(实现实时同步)

<local:MyTextBox x:Name="mtb1"
                  ContentChanged="MyTextBox_ContentChanged"
                  Text="{Binding AString,
                                 RelativeSource={RelativeSource Mode=Self},
                                 Mode=TwoWay,
                                 UpdateSourceTrigger=PropertyChanged}" />

内容的提问来源于stack exchange,提问作者FaGGG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 15:33:51