【问题标题】:uwp inherited property data binding not updating the UIuwp 继承的属性数据绑定不更新 UI
【发布时间】:2021-04-06 04:27:42
【问题描述】:

3 步嵌套字符串属性未更新 UI。当我更新 EvidenceName 属性时,它不会立即反映在 UI 上,直到我返回并再次访问此页面,在这种情况下视图模型会再次初始化。

我有一个带有以下代码的 xaml 页面:

<TextBlock Text="{x:Bind ViewModel.SelectedEvidence.EvidenceName, Mode=OneWay}" />

后面代码中的 ViewModel 属性:

public EvidenceViewModel ViewModel { get; } = new EvidenceViewModel();

EvidenceViewModel 中的 Selected Evidence 属性:

    public Evidence SelectedEvidence
    {
        get => _selectedEvidence;
        set => Set(ref _selectedEvidence, value); //this calls for RaisePropertyChanged
    }

EvidenceViewModel 派生自 Observable 类,用于引发属性更改。

public class Observable : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void Set<T>(ref T storage, T value, [CallerMemberName]string propertyName = null)
    {
        if (Equals(storage, value))
        {
            return;
        }

        storage = value;
        OnPropertyChanged(propertyName);
    }

    protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

Evidence 类中的 EvidenceName 属性

    public string EvidenceName
    {
        get { return _evidenceName; }
        set 
        {
            if (_evidenceName != value)
            {
                _evidenceName = value; 
                RaisePropertyChanged();
            }
        }
    }

更新 1

如果我直接在 EvidenceViewModel 中放置一个简单的字符串属性并将 UI 文本块绑定到该字符串属性,则更改会按预期实时反映。

更新 2

经过进一步调试,我发现类从父类继承的任何属性在绑定中都不能正常工作,因此 EvidenceName 属性实际上来自父类 EvidenceBase 并被继承到子类 Evidence

更新 3

Nswagger 为客户端生成的文件中的证据类代码

EvidenceBase 类的代码

EvidenceName 属性,实际存在于 EvidenceBase 类中

EvidenceBase中的

RasiePropertyChanged代码

【问题讨论】:

  • 能否提供RaisePropertyChanged的源码?代码中包含SetOnPropertyChangedRaisePropertyChanged有点奇怪,它们都来自同一个MVVM工具包吗?
  • @MartinZikmund raise 属性更改机制来自生成的 nswag 文件,因为这些模型类实际上是 dotnetcore 中的 db 表,并且 nswagger 用于将其与客户端应用程序链接。
  • @MartinZikmund 请参阅我的问题的更新 3,这可能有助于澄清您关于 PropertyChanged 的​​问题,并且此 propertyChanged 事件适用于所有属性,除非它们是从像这种情况下的抽象类继承的。

标签: c# xaml uwp binding


【解决方案1】:

您可以让Evidence 类继承自Observable 类并在EvidenceName 中调用OnPropertyChanged 方法。

例如:

public class Evidence:Observable
{
    private string _evidenceName;
    public string EvidenceName
    {
        get { return _evidenceName; }
        set
        {
            if (_evidenceName != value)
            {
                _evidenceName = value;
                OnPropertyChanged("EvidenceName");
            }
        }
    }
}

更新: 我测试了您的 Update 3 中的代码,发现问题出在 Evidence 类中的覆盖。 请检查以下代码:

private void Button_Click(object sender, RoutedEventArgs e)
{
    ViewModel.SelectedEvidence.EvidenceName = "testName";
}


public abstract partial class EvidenceBase : System.ComponentModel.INotifyPropertyChanged
{        
    private string _evidenceName;
    [Newtonsoft.Json.JsonProperty("evidenceName",Required =Newtonsoft.Json.Required.Default,NullValueHandling =Newtonsoft.Json.NullValueHandling.Ignore)]
    public string EvidenceName
    {
        get { return _evidenceName; }
        set
        {
            if(_evidenceName!=value)
            {
                _evidenceName = value;
                RaisePropertyChanged("EvidenceName");
            }
        }
    }
    protected virtual void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
    public event PropertyChangedEventHandler PropertyChanged;
}

public partial class Evidence : EvidenceBase, System.ComponentModel.INotifyPropertyChanged
{

//Remove the override of PropertyChanged property and RaisePropertyChanged method to avoid hide the ones inherited from base class.
}

public class Observable : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void Set<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
    {
        if (Equals(storage, value))
        {
            return;
        }

        storage = value;
        OnPropertyChanged(propertyName);
    }
    protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

public class EvidenceViewModel:Observable
{
    private Evidence _selectedEvidence;
    public Evidence SelectedEvidence
    {
        get { return _selectedEvidence; }
        set
        {
            Set(ref _selectedEvidence, value);
        }
    }
    public EvidenceViewModel()
    {
        _selectedEvidence = new Evidence();
    }
}

如果代码无法准确说明您关于 PropertyChanged 的​​代码,请随时与我联系。

【讨论】:

  • 不能这样做,因为 raise 属性更改机制来自生成的 nswag 文件,因为这些模型类实际上是 dotnetcore 中的 db 表,并且 nswagger 用于将其与客户端应用程序链接。请参阅我的问题的更新 3,这可能有助于澄清 PropertyChanged,并且此 propertyChanged 事件适用于所有属性,除非它们是从本例中的抽象类继承的。
  • 我已经更新了我的答案,你可以查看更新看看它是否能满足你的要求。
  • 是的,您更新的解决方案似乎有效,我刚刚在“证据”类中注释掉了 Propertychanged 事件和 RaisePrpertyChanged。但问题是这个文件是由 nswag 文件自动生成的,所以我不确定如何配置 nswag 文件或模型类,所以每次生成 nswag_Generated 文件时,它都不包括子类中的 propertyChanged 事件,如果子类也有它自己的一些财产不知道如何处理。
  • 但无论如何你的回答解决了核心问题,所以我将其标记为完成:)
  • 我想我应该只是制作接口并在类中手动添加所有子属性,并完全删除父抽象类?
猜你喜欢
  • 1970-01-01
  • 2018-08-10
  • 2019-09-08
  • 2016-08-07
  • 2021-05-19
  • 1970-01-01
  • 2020-10-27
  • 2015-12-16
  • 1970-01-01
相关资源
最近更新 更多