C# 模型更改后如何更新视图?
假设我有一个C# 模型更改后如何更新视图?,c#,.net,wpf,silverlight,mvvm,C#,.net,Wpf,Silverlight,Mvvm,假设我有一个Logger类、一个LoggerViewModel类和一个带有文本框的main窗口。Logger类是线程安全的单例,因此我在应用程序域中只有它的一个实例 public sealed class Logger : INotifyPropertyChanged { private static readonly Logger _Instance = new Logger(); private static readonly object _SyncLock = new
Logger
类、一个LoggerViewModel
类和一个带有文本框的main窗口
。Logger
类是线程安全的单例,因此我在应用程序域中只有它的一个实例
public sealed class Logger : INotifyPropertyChanged
{
private static readonly Logger _Instance = new Logger();
private static readonly object _SyncLock = new object();
private static List<LogEntry> _Data = new List<LogEntry>();
/// <summary>
///
/// </summary>
private Logger() { ; }
/// <summary>
///
/// </summary>
public static Logger Instance
{
get { return _Instance; }
}
/// <summary>
///
/// </summary>
/// <param name="entry"></param>
public void Write(LogEntry entry)
{
lock (_SyncLock)
{
_Data.Add(entry);
}
this.RaiseNotifyPropertyChanged("Entries");
}
/// <summary>
///
/// </summary>
/// <param name="component"></param>
/// <param name="message"></param>
public void Write(string component, string message)
{
LogEntry entry = LogEntry.Create(component, message);
Write(entry);
}
/// <summary>
///
/// </summary>
public IList<LogEntry> Entries
{
get
{
lock (_SyncLock)
{
return new ReadOnlyCollection<LogEntry>(_Data);
}
}
}
/// <summary>
///
/// </summary>
/// <param name="property"></param>
private void RaiseNotifyPropertyChanged(string property)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(property));
}
}
/// <summary>
///
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
}
ViewModel如何拦截模型发送的通知?首先,我不喜欢您使用单例。当使用单例模式时,在测试或重用视图控制器时,会给自己带来困难。相反,我会将Logger
依赖项注入到LoggerViewModel
类中
除此之外,解决问题的一种方法是在记录器
上注册属性更改
事件的处理程序,并在事件触发条目
属性时生成文本
然后在LoggerViewModel
中添加属性处理程序,并根据需要更新LoggerText
属性
public LoggerViewModel(Logger loggerModel /* Dependency injection*/)
{
_LoggerModel = loggerModel;
_LoggerModel.PropertyChanged += this.LoggerModel_PropertyChanged;
}
private void LoggerModel_PropertyChanged(object sender, PropertyChangedEventArgs args)
{
if (args.PropertyName == "Entries")
{
StringBuilder text = new StringBuilder(); // Use StringBuilder for performance
List<LogEntry> entries = new List<LogEntry>(_LoggerModel.Entries);
foreach (LogEntry entry in entries)
{
text.AppendLine(entry.ToString());
}
this.LoggerText = text.ToString();
}
}
private string _loggerText;
public string LoggerText
{
set
{
_loggerText = value;
RaisePropertyChanged("LoggerText");
}
get
{
return _loggerText;
}
}
公共LoggerViewModel(Logger loggerModel/*依赖项注入*/)
{
_LoggerModel=LoggerModel;
_LoggerModel.PropertyChanged+=this.LoggerModel_PropertyChanged;
}
私有void LoggerModel_PropertyChanged(对象发送方,PropertyChangedEventArgs参数)
{
如果(args.PropertyName==“条目”)
{
StringBuilder text=new StringBuilder();//使用StringBuilder提高性能
列表条目=新列表(_LoggerModel.entries);
foreach(条目中的日志条目)
{
text.AppendLine(entry.ToString());
}
this.LoggerText=text.ToString();
}
}
私有字符串_loggerText;
公共字符串LoggerText
{
设置
{
_loggerText=值;
RaisePropertyChanged(“LoggerText”);
}
得到
{
返回loggerText;
}
}
免责声明:上述代码是在没有编译器的情况下编写的。在UI方法中,向视图模型中添加类型为Logger
的属性,并将数据绑定到条目
属性有什么问题?如果static
类给您带来了问题,那么只需将属性添加到普通类中,并使用Singleton类更新普通类即可。我添加了LoggerViewModel
类的代码示例。当模型更改时,我会在UI中绑定LoggerText
属性。使用WPF(以及大多数编程语言),您将从数据访问代码中分离数据中获益。您最好使用普通集合属性(数据)并使用从视图模型访问的外部类填充它。@Sheridan:您能告诉我一个例子吗?视图模型如何拦截模型发送的通知?
-在您的VM中添加一个PropertyChanged
处理程序。因此,在VM的ctor中,您有\u LoggerModel=Logger.Instance代码>添加到下一行\u LoggerModel.PropertyChanged+=(发送方,args)=>Debug.WriteLine(args.PropertyName)代码>。现在,当您的模型的“Entries”属性通过Write
方法更改时,这个处理程序将在您的VM中被调用。现在它会将条目打印到输出窗口,您可以将其更改为\u LoggerModel.PropertyChanged+=(发送方,args)=>RaiseNotifyPropertyChanged(“LoggerText”)代码>太好了!感谢您的代码示例,现在只要模型发生更改,ViewModel就会正确更新。
public LoggerViewModel(Logger loggerModel /* Dependency injection*/)
{
_LoggerModel = loggerModel;
_LoggerModel.PropertyChanged += this.LoggerModel_PropertyChanged;
}
private void LoggerModel_PropertyChanged(object sender, PropertyChangedEventArgs args)
{
if (args.PropertyName == "Entries")
{
StringBuilder text = new StringBuilder(); // Use StringBuilder for performance
List<LogEntry> entries = new List<LogEntry>(_LoggerModel.Entries);
foreach (LogEntry entry in entries)
{
text.AppendLine(entry.ToString());
}
this.LoggerText = text.ToString();
}
}
private string _loggerText;
public string LoggerText
{
set
{
_loggerText = value;
RaisePropertyChanged("LoggerText");
}
get
{
return _loggerText;
}
}