Как обновить вид после изменения модели?

1

Скажем, у меня есть класс 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).

Как подключить модель и ViewModel между ними? Я подчеркиваю, что модель изменена только несколькими потоками приложений, поэтому она доступна только для чтения с точки зрения пользовательского интерфейса.

Я предоставил LoggerText имущество в LoggerViewModel класса, так как я думал, что следующий рабочий механизм. 1. Когда модель (экземпляр Logger) изменяется, она уведомляет ViewModel. 2. ViewModel получает уведомление с помощью модели и создает новую 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 может перехватывать уведомления, отправленные моделью?

  • 0
    Что не так с обычным Добавьте свойство типа Logger в модель представления и привязку данных к свойству Entries в подходе пользовательского интерфейса ? Если static класс вызывает у вас проблемы, просто добавьте свойство в обычный класс и просто используйте ваш класс Singleton для обновления нормального класса.
  • 0
    Я добавил пример LoggerViewModel класса LoggerViewModel . Я бы LoggerText свойство LoggerText в пользовательском интерфейсе при изменении модели.
Показать ещё 5 комментариев
Теги:
wpf
mvvm
silverlight

1 ответ

1
Лучший ответ

Прежде всего мне не нравится, что вы используете синглтон. При использовании одноэлементного шаблона вы усложняете себя при тестировании или повторном использовании контроллеров представлений. Вместо этого я бы LoggerViewModel зависимость Logger в ваш класс LoggerViewModel.

Помимо этого один из способов решения вашей проблемы - зарегистрировать обработчик события PropertyChanged в вашем Logger и построить текст, когда событие запускается для свойства " 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;
    }
}

Отказ от ответственности: приведенный выше код написан без компилятора.

  • 0
    Большой! Благодаря вашему примеру кода, теперь ViewModel корректно обновляется при каждом изменении модели.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню