模型更改后如何更新视图?

时间:2014-08-18 13:23:32

标签: c# .net wpf silverlight mvvm

假设我有一个Logger课程,一个LoggerViewModel课程和一个MainWindow TextBoxLogger类是一个线程安全的单例,所以我在应用程序域中只有它的一个实例。

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 如何拦截模型发送的通知?

1 个答案:

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

免责声明:上述代码是在没有编译器的情况下编写的。