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

自定义控件ControlTemplate中INotifyPropertyChanged绑定不更新问题

问题:WPF自定义控件中,依赖属性更新后计算属性绑定不生效

自定义WPF控件首次加载时,Text属性绑定正常显示,但当Number依赖属性更新后,ControlTemplate内的TextBlock无法同步更新。相关代码如下:

C# 控件代码

public class ExampleControl : Control, INotifyPropertyChanged
{
    public static readonly DependencyProperty NumberProperty =
        DependencyProperty.Register("Number", typeof(int),
        typeof(ExampleControl), new PropertyMetadata(0));
           
    public int Number
    {
        get { return (int)GetValue(NumberProperty); }
        set 
        { 
            SetValue(NumberProperty, value); 
            OnPropertyChanged(nameof(Text));
        }
    }
           
    public string Text
    {
        get
        {
            return (Number * 2).ToString();
        }
    }
            
    public event PropertyChangedEventHandler PropertyChanged;
        
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

XAML 样式代码

<Style TargetType="local:ExampleControl">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:ExampleControl">
                <TextBlock Text="{Binding Text, RelativeSource={RelativeSource AncestorType=local:ExampleControl}}" />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
解决方案

方法1:给依赖属性添加变更回调(推荐)

WPF更新依赖属性时,不一定会调用自定义的Number属性setter(比如绑定更新时会直接调用SetValue),导致setter内的OnPropertyChanged(nameof(Text))逻辑失效。正确做法是在注册依赖属性时,为PropertyMetadata添加属性变更回调:

public static readonly DependencyProperty NumberProperty =
    DependencyProperty.Register("Number", typeof(int),
    typeof(ExampleControl), new PropertyMetadata(0, OnNumberChanged));

private static void OnNumberChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var control = (ExampleControl)d;
    control.OnPropertyChanged(nameof(control.Text));
}

// 简化Number的setter,无需再调用OnPropertyChanged
public int Number
{
    get { return (int)GetValue(NumberProperty); }
    set { SetValue(NumberProperty, value); }
}

方法2:将Text定义为依赖属性

如果Text需要支持外部绑定或设置,可以将其注册为依赖属性,通过Number的变更回调自动更新:

public static readonly DependencyProperty TextProperty =
    DependencyProperty.Register("Text", typeof(string),
    typeof(ExampleControl), new PropertyMetadata(string.Empty));

public string Text
{
    get { return (string)GetValue(TextProperty); }
    private set { SetValue(TextProperty, value); }
}

private static void OnNumberChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var control = (ExampleControl)d;
    control.Text = (control.Number * 2).ToString();
}

方法3:XAML中直接使用转换器,移除Text属性

若Text仅用于显示计算结果,可直接在XAML绑定中通过转换器实现逻辑,无需额外定义Text属性:

首先实现转换器:

public class DoubleNumberConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is int number)
        {
            return (number * 2).ToString();
        }
        return string.Empty;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

然后在XAML中引用并使用:

<Window.Resources>
    <local:DoubleNumberConverter x:Key="DoubleNumberConverter"/>
</Window.Resources>

<Style TargetType="local:ExampleControl">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:ExampleControl">
                <TextBlock Text="{Binding Number, RelativeSource={RelativeSource AncestorType=local:ExampleControl}, Converter={StaticResource DoubleNumberConverter}}" />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 06:10:13