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;
    }
}