【问题标题】:WPF: UI not updated on value change in bound objectWPF:UI 未在绑定对象中的值更改时更新
【发布时间】:2014-08-01 21:51:03
【问题描述】:

我对 WPF 比较陌生,并且遇到了数据绑定问题。我将用户控件的依赖属性绑定到后面代码中的类属性。在我的 UI 后面代码中的类实体实例化期间,通过 INotifyPropertyChanged 成功更新。但是,当随后在 OnPropertyChangedEventHandler 触发后更改我的代码中的值时,但 OnPropertyChanged 方法不再对此作出回应。详情如下。如果有人能给我一些提示我做错了什么,那就太好了。

我在后面的代码中实现了一个用户控件,该控件绑定到我的部分类的属性 CurrentAccProp.DiscountRate:

<local:doubleUEdit x:Name="InterestRate" LabelField="Interest rate" MinimumValue="0" MaximumValue="1" FormatStringForNumbers="P2" IncrementSize="0.01" UncertainValue="{Binding ElementName=RibbonWindow, Path=CurrentAccProp.DiscountRate, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

CurrentAccProp 为实例的类实现 INotifyPropertyChanged 以通知 UI 值更改

//Event to inform data grid about changes
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

在 DiscountRate 属性的设置器中调用 OnPropertyChanged:

doubleU discountingrate;
    public doubleU DiscountRate 
    { 
        get {return discountingrate;} 
        set 
        {
            discountingrate = value; 
            OnPropertyChanged("DiscountingRate");
        } 
    }

我绑定的用户控件的属性被实现为依赖属性:

    //Property for data binding to doubleU
    [Description("The formatstring for the double boxes"), Category("Default")]
    public doubleU UncertainValue
    {
        get { return new doubleU(0, 0, (double)doubleUSupremum.Value, (double)doubleUSupremum.Value); }
        set { doubleURangeSlider.LowerValue = value.Interval.Infimum; doubleURangeSlider.HigherValue = value.Interval.Supremum; doubleUInfimum.Value = value.Interval.Infimum; doubleUSupremum.Value = value.Interval.Supremum; }
    }

    public static readonly DependencyProperty UncertainValueProperty =
    DependencyProperty.Register(
        "UncertainValue",
        typeof(doubleU),
        typeof(doubleUEdit),
        new PropertyMetadata(default(doubleU), OnItemsPropertyChanged));

    private static void OnItemsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        doubleUEdit MydblUEdt = d as doubleUEdit;

        MydblUEdt.UncertainValue = e.NewValue as doubleU;
    }

当我在 OnPropertyChanged 后面的代码中实例化 CurrentAccProp 时,会通知 UI 并更新值。

AccountingProperties currentaccprop = new AccountingProperties(new doubleU(0.0));
public AccountingProperties CurrentAccProp { get { return currentaccprop; } set { currentaccprop = value; } }

但是,当我稍后更新 DiscountRate 的值时

CurrentAccProp.DiscountRate = new doubleU(1.0);

OnPropertyChanged 被执行,但 UI 不再更新。有谁知道我在这里做错了什么?

HighCore 和 zaknotzach 指出的错字确实是问题所在。谢谢你的帮助!我在 HighCore 引用的线程中实现了该方法以避免这种情况,它就像一个魅力。在更改后的 AccountingProperties 类下方,从中实例化 CurrentAccProp 以供参考:

public class AccountingProperties : INotifyPropertyChanged
{
    doubleU discountrate;
    public doubleU DiscountRate 
    { 
        get {return discountrate;} 
        set { SetField(ref discountrate, value, () => DiscountRate); }
    }

    //------------------------------------------------
    //constructors
    public AccountingProperties(doubleU discountrate)
    {
        DiscountRate = discountrate;
    }

    //Event to inform data grid about changes
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }


    protected virtual void OnPropertyChanged<T>(Expression<Func<T>> selectorExpression)
    {
        if (selectorExpression == null)
            throw new ArgumentNullException("selectorExpression");
        MemberExpression body = selectorExpression.Body as MemberExpression;
        if (body == null)
            throw new ArgumentException("The body must be a member expression");
        OnPropertyChanged(body.Member.Name);
    }

    protected bool SetField<T>(ref T field, T value, Expression<Func<T>> selectorExpression)
    {
        if (EqualityComparer<T>.Default.Equals(field, value)) return false;
        field = value;
        OnPropertyChanged(selectorExpression);
        return true;
    }


}

【问题讨论】:

  • 我注意到的第一件事是您的财产被称为DiscountRate,但您正在为DiscountingRate 提高财产更改。请参阅this answer 了解避免该问题的明确方法。
  • 哇,谢谢。我在上面培育了两天多,你在 60 秒内就看到了。

标签: c# wpf binding inotifypropertychanged


【解决方案1】:

你需要先改字符串

OnPropertyChanged("DiscountingRate");

到“折扣率”。您为 OnPropertyChanged 函数提供的字符串必须与属性名称匹配。这很可能是您遇到的问题。

【讨论】:

  • 不错,这实际上是可能的问题。
  • 哇,谢谢你的帮助。那成功了。我非常专注于查找代码中的结构缺陷,因为更新第一次起作用,当时我创建了属性后面的成员实例。但显然,似乎有一种机制可以在绑定元素在我还不理解的实例化期间将其值从 null 更改为有效值时通知 UI。
【解决方案2】:

正如已经回答的,问题是OnPropertyChanged("DiscountingRate"); 为事件提供了不正确的属性名称。

为了防止这样的错误,您可以避免一起使用字符串文字。在 OnPropertyChanged 参数中,使用 CallerMemberName。您可以将 OnPropertyChanged 签名修改为

public void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
    // Do your stuff
}

然后在您的二传手中,您只需调用this.OnPropertyChanged();。该方法将被赋予已更改的属性名称。

public doubleU DiscountRate 
{ 
    get {return discountingrate;} 
    set 
    {
        discountingrate = value; 
        OnPropertyChanged();
    } 
}

这样做的好处是您可以重构代码,而不必担心破坏您的属性更改事件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-08
    • 2016-09-08
    相关资源
    最近更新 更多