假设我有一个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
唯一实例由更多线程更新,因此每当模型(TextBox
时,我都会更新MainWindow
上的Logger
单身类)改变。
如何在它们之间连接Model和ViewModel?我强调模型仅由少数应用程序线程更改,因此从UI的角度来看它是只读的。
我在LoggerText
类中提供了LoggerViewModel
属性,因为我认为有以下工作机制。
1。当模型(Logger
实例)发生更改时,它会通知 ViewModel 。
2。 ViewModel 通过模型接收通知,并创建一个新的string
,其中包含来自记录器的所有消息。
3。 ViewModel 通知查看。
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 如何拦截模型发送的通知?
答案 0 :(得分:1)
首先,我不喜欢你使用单身人士。使用单例模式时,在测试或重用视图控制器时,您自己很难。我会将Logger
依赖项注入您的LoggerViewModel
类。
除此之外,解决问题的一种方法是在PropertyChanged
上为Logger
事件注册处理程序,并在事件触发Entries
属性时构建文本。< / p>
在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;
}
}
免责声明:上述代码是在没有编译器的情况下编写的。