如何在模型更改后更新视图
本文关键字:更新 新视图 模型 | 更新日期: 2023-09-27 18:18:34
假设我有一个Logger
类,一个LoggerViewModel
类和一个MainWindow
与一个TextBox
。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;
}
Logger
唯一实例在应用程序运行时由更多线程更新,因此每当模型(即Logger
单例类)更改时,我会在MainWindow
上更新TextBox
。
如何在它们之间连接模型和ViewModel ?我要强调的是,Model只会被几个应用程序线程修改,所以从UI的角度来看,它是只读的。
我在LoggerViewModel
类中提供了LoggerText
属性,因为我认为下面的工作机制。 1。当模型 (Logger
实例)改变时,它通知ViewModel。 2。ViewModel接收Model发出的通知,并创建一个包含来自记录器的所有消息的新string
。 3。ViewModel通知View。
public class LoggerViewModel : INotifyPropertyChanged
{
Logger _LoggerModel;
/// <summary>
///
/// </summary>
public LoggerViewModel()
{
_LoggerModel = Logger.Instance;
}
/// <summary>
///
/// </summary>
public string LoggerText
{
get
{
string text = "";
List<LogEntry> entries = new List<LogEntry>(_LoggerModel.Entries);
foreach (LogEntry entry in entries)
{
text += entry.ToString();
text += "'n";
}
return text;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
// take a copy to prevent thread issues
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
ViewModel如何拦截由Model发送的通知?
首先,我不喜欢你使用单例。当使用单例模式时,你在测试或重用视图控制器时就会变得很困难。相反,我将把Logger
依赖注入到你的LoggerViewModel
类中。
除此之外,解决问题的一种方法是在Logger
上注册PropertyChanged
事件的处理程序,并在事件为Entries
属性触发时构建文本。
在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;
}
}
免责声明:上面的代码没有编译器。