【发布时间】:2021-07-01 05:27:47
【问题描述】:
您好,我知道有关于此主题的帖子,但我无法解决我的问题。
我想了解并学习一种简单的方法来获取可以在我的视图中订阅的 ViewModelBase,以便强制进行 UI 刷新。
我已经编写了一个 Windows 控制台示例。结构是 Class Customer(string Name, MyAddress Address),其中 MyAddress 是 Class(string StreetName)。在 Main 我有一个客户列表。现在我想在每次列表或客户属性发生变化时收到一条消息,包括街道名称的变化。 我不能让它工作。如果我更改客户的名称,它会起作用,但不适用于“巢”地址。如果我更改 StreetName,我不会收到通知事件。我不知道如何为列表中的所有客户订阅 ViewModelBase。 控制台程序可以在 VisulaStudio 中复制/粘贴并运行:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace CS_MVVM_NotifyFromNestedClass
{
class Program
{
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected void SetValue<T>(ref T backingFiled, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(backingFiled, value)) return;
backingFiled = value;
OnPropertyChanged(propertyName);
}
}
public class Customer : ViewModelBase
{
private string _name;
public string Name
{
get => _name;
set { SetValue(ref _name, value); }
}
public MyAddress Address { get; set; }
public Customer(string name, MyAddress address)
{
Name = name;
Address = address;
}
}
public class MyAddress : ViewModelBase
{
private string _street;
public string Street
{
get => _street;
set { SetValue(ref _street, value); }
}
public MyAddress(string street)
{
Street = street;
}
}
public static BindingList<Customer> MyCustomers = new BindingList<Customer>
{
new Customer("John", new MyAddress("JoStreet")),
new Customer("Susi", new MyAddress("SeaStreet")),
};
static void Main(string[] args)
{
//BindingList Event
MyCustomers.ListChanged += OnBindingListChanged;
// 1) Change Name <-- THIS FIRES THE 'OnBindingListChanged' EVENT
MyCustomers[0].Name = "Rick";
// 2) Change Street <-- THIS DOESN'T FIRE A CHANGE-EVENT
MyCustomers[0].Address.Street = "Rockyroad";
//I dont know how to hook up the 'property change event' from ViewModelBase for all obj. of MyCustomer-List
//MyCustomers[0].Address.PropertyChanged += OnSingleObjPropChanged; // <--doesn't work
Console.ReadLine();
}
private static void OnBindingListChanged(object sender, ListChangedEventArgs e)
{
Console.WriteLine("1) BindingList was changed");
foreach (var c in MyCustomers)
{
Console.WriteLine($"{c.Name} {c.Address.Street}");
}
}
private static void OnSingleObjPropChanged(object sender, PropertyChangedEventArgs e)
{
//Never reached --> how to 'hook'
Console.WriteLine("2) Property of List Item was changed");
foreach (var c in MyCustomers)
{
Console.WriteLine($"{c.Name} {c.Address.Street}");
}
}
}
}
第一次编辑:CustomerClass 中的内部 BindingList 加上 ViewModelBase @Karoshee
为了简化,我确实把 MyAdresse 的事情留了下来。我向我的 CustomerClass 添加了一个 BindingList 'MyTelNrs' 并订阅了 ListChanged 事件。我没有从执行的答案中更改 ViewModelBase。我确实在我的 UI 中收到通知,但我不知道我是否以保存/正确的方式进行操作。只是为了让下面的读者知道......(如果下面的方式是“好的”,也许比我更好的人会回答)
public class Customer: ViewModelBase
{
private string _name;
public string Name
{
get => _name;
set => SetValue(ref _name, value);
}
public BindingList<string> MyTelNrs = new();
private void OnLstChanged(object sender, ListChangedEventArgs e)
{
OnPropertyChanged(nameof(MyTelNrs));
}
public Customer(string name, BindingList<string> myTelNrs)
{
Name = name;
MyTelNrs = myTelNrs;
MyTelNrs.ListChanged += OnLstChanged;
}
}
【问题讨论】:
-
我建议您将
ViewModelBase重命名为ObservableObject或类似名称。 -
好的,这不是问题,但这对这里有什么帮助?
-
这是一个评论 不是一个答案
标签: c# mvvm inotifypropertychanged