2015-08-06 2 views
0

Я строю регистратор. Пользовательский интерфейс (LoggerView) связывается с тремя свойствами LogItem: DateTime, Status и Message. Когда я запускаю программу, события регистрации создаются и регистрируются в пользовательском интерфейсе должным образом. Однако, когда я закрываю пользовательский интерфейс, регистрирую дополнительные события и снова открываю пользовательский интерфейс, дополнительные события регистрируются в events, но они не отображаются в пользовательском интерфейсе.MVVM: Уведомление об изменении свойства в пользовательском интерфейсе

Проблема заключается в том, что пользовательский интерфейс не уведомляется, когда в коллекцию добавляются новые LogItems. Как я могу уведомить пользовательский интерфейс при добавлении дополнительных LogItems?

LoggerViewModel:

[Export] 
[PartCreationPolicy(System.ComponentModel.Composition.CreationPolicy.Shared)] 
public class LoggerViewModel : ViewModelBase 
{ 
    protected static readonly ILog log = LogManager.GetLogger(typeof(LoggerViewModel)); 
    private Hierarchy h = LogManager.GetRepository() as Hierarchy; 

    [ImportingConstructor] 
    public LoggerViewModel() 
    { 
     LogItems = new ObservableCollection<LogItem>(); 
     foreach (var customLog in CustomLogger.GetLogItems()) 
     { 
      var logItem = new LogItem(customLog.TimeStamp, customLog.Status, customLog.Message); 
      LogItems.Add(logItem); 
     } 
    } 

    private ObservableCollection<LogItem> _logItems; 
    public ObservableCollection<LogItem> LogItems 
    { 
     get { return _logItems; } 
     set { _logItems = value; } 
    } 

    private DateTime _timeStamp; 
    public DateTime TimeStamp 
    { 
     get { return _timeStamp; } 
     set 
     { 
      if (value == _timeStamp) 
       return; 
      _timeStamp = value; 
      NotifyPropertyChanged("TimeStamp"); 
     } 
    } 

    private Level _status; 
    public Level Status 
    { 
     get { return _status; } 
     set 
     { 
      if (value == _status) 
       return; 
      _status = value; 
      NotifyPropertyChanged("Status"); 
     } 
    } 

    private string _message; 
    public string Message 
    { 
     get { return _message; } 
     set 
     { 
      if (value == _message) 
       return; 
      _message = value; 
      NotifyPropertyChanged("Message"); 
     } 
    } 
} 

LoggerView XAML:

<ListView Grid.Row="1" ScrollViewer.HorizontalScrollBarVisibility="Visible" ScrollViewer.VerticalScrollBarVisibility="Visible" VerticalContentAlignment="Bottom" ItemsSource="{Binding LogItems}"> 
     <ListView.View> 
      <GridView> 
       <GridViewColumn Width="150" Header="Date And Time" DisplayMemberBinding="{Binding Path=DataContext.TimeStamp, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"> 
        <GridViewColumn.CellTemplate> 
         <DataTemplate> 
          <TextBlock TextWrapping="WrapWithOverflow" TextAlignment="Center"/> 
         </DataTemplate> 
        </GridViewColumn.CellTemplate> 
       </GridViewColumn> 
       <GridViewColumn Width="50" Header="Status" DisplayMemberBinding="{Binding Path=DataContext.Status, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"> 
        <GridViewColumn.CellTemplate> 
         <DataTemplate> 
          <TextBlock TextWrapping="WrapWithOverflow" TextAlignment="Center"/> 
         </DataTemplate> 
        </GridViewColumn.CellTemplate> 
       </GridViewColumn> 
       <GridViewColumn Width="1800" Header="Message"> 
        <GridViewColumn.CellTemplate> 
         <DataTemplate> 
          <TextBlock TextWrapping="WrapWithOverflow" Text="{Binding Path=DataContext.Message, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"/> 
         </DataTemplate> 
        </GridViewColumn.CellTemplate> 
       </GridViewColumn> 
      </GridView> 
     </ListView.View> 
    </ListView> 

LoggerView Логика:

[Export] 
[PartCreationPolicy(System.ComponentModel.Composition.CreationPolicy.NonShared)] 
public partial class LoggerView : Window 
{ 
    private LoggerViewModel _viewModel; 
    protected static readonly ILog log = LogManager.GetLogger(typeof(LoggerView)); 
    private Hierarchy h = LogManager.GetRepository() as Hierarchy; 

    [ImportingConstructor] 
    public LoggerView(LoggerViewModel viewModel) 
    { 
     _viewModel = viewModel; 
     this.DataContext = _viewModel; 
     InitializeComponent(); 
    } 

CustomLogger: LogItems создается из events

public class CustomLogger 
{ 
    protected static readonly ILog log = LogManager.GetLogger(typeof(CustomLogger)); 
    static MemoryAppender memoryAppender = new MemoryAppender(); 
    private Hierarchy h = LogManager.GetRepository() as Hierarchy; 

    public CustomLogger() 
    { 
     log4net.Config.XmlConfigurator.Configure(new System.IO.FileInfo(@"C:\Users\username\Documents\GitHub\MassSpecStudio\MassSpecStudio 2.0\source\MassSpecStudio\Core\app.config")); 
     memoryAppender = h.Root.GetAppender("MemoryAppender") as MemoryAppender; 
    } 

    public static ObservableCollection<LogItem> GetLogItems() 
    { 
     var events = memoryAppender.GetEvents(); 
     ObservableCollection<LogItem> LogItems = new ObservableCollection<LogItem>(); 
     foreach (LoggingEvent loggingEvent in events) 
     { 
      DateTime TimeStamp = loggingEvent.TimeStamp; 
      Level Status = loggingEvent.Level; 
      string Message = loggingEvent.RenderedMessage; 

      LogItems.Add(new LogItem(TimeStamp, Status, Message)); 
     } 
     return LogItems; 
    } 
} 

LogItem:

public class LogItem : INotifyPropertyChanged 
    { 

     private DateTime _datetime; 
     private Level _status; 
     private string _message; 

     public LogItem(DateTime datetime, Level status, string message) 
     { 
      this._datetime = datetime; 
      this._status = status; 
      this._message = message; 
     } 

     public enum LogLevel 
     { 
      Debug = 0, 
      Info = 1, 
      Warn = 2, 
      Error = 3, 
      Fatal = 4, 
     } 

     public DateTime TimeStamp 
     { 
      get 
      { 
       return _datetime; 
      } 
      set 
      { 
       if (_datetime != value) 
       { 
        _datetime = value; 
        RaisePropertyChanged("DateTime"); 
       } 
      } 
     } 

     public Level Status 
     { 
      get 
      { 
       return _status; 
      } 
      set 
      { 
       if (_status != value) 
       { 
        _status = value; 
        RaisePropertyChanged("Status"); 
       } 
      } 
     } 

     public string Message 
     { 
      get 
      { 
       return _message; 
      } 
      set 
      { 
       if (_message != value) 
       { 
        _message = value; 
        RaisePropertyChanged("Error"); 
       } 
      } 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 
     private void RaisePropertyChanged(string info) 
     { 
      if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(info)); } 
     } 
    } 

LoggerMenuItem:

[Export] 
public partial class LoggerMenuItem : MenuItem 
{ 
    protected static readonly ILog log = LogManager.GetLogger(typeof(LoggerMenuItem)); 
    private readonly IServiceLocator _serviceLocator; 

    [ImportingConstructor] 
    public LoggerMenuItem(IServiceLocator serviceLocator) 
    { 
     _serviceLocator = serviceLocator; 
     InitializeComponent(); 
    } 

    private void MenuItem_Click(object sender, RoutedEventArgs e) 
    { 
     LoggerView window = _serviceLocator.GetInstance<LoggerView>(); 
     window.Owner = Application.Current.MainWindow; 
     window.Show(); 
    } 
} 

UPDATE:

я заметил, что мой статический метод GetLogItems() из CustomLogger будет выполняться только при открытии UI в течение первого времени , GetLogItems() не выполняется после того, как обновление events.

Есть ли способ сообщить об изменении свойств событий?

Чтобы решить эту проблему, я думаю, что лучше всего будет создавать сеттеры для LogItems, DateTime, Status и Message для запуска при каждом запуске пользовательского интерфейса. Метод MenuItem_Click отвечает за запуск пользовательского интерфейса. Можно ли позвонить NotifyPropertyChanged прямо до window.Show()?

ответ

2

Я думаю, что вы заменяете LogItems ObservableCollection после того, как привязка была разрешена и вы не вызываете NotifyPropertyChanged, чтобы сообщить об этом пользовательскому интерфейсу.

Попробуйте изменить LogItems свойство вызывать NotifyPropertyChanged:

private ObservableCollection<LogItem> _logItems; 
public ObservableCollection<LogItem> LogItems 
{ 
    get { return _logItems; } 
    set 
    { 
     _logItems = value; 
     NotifyPropertyChanged("LogItems"); 
    } 
} 

Я думаю, что вам нужно изменить столбцы так:

<GridView> 
    <GridViewColumn Width="150" Header="Date And Time" DisplayMemberBinding="{Binding TimeStamp}"> 
     <GridViewColumn.CellTemplate> 
      <DataTemplate> 
       <TextBlock TextWrapping="WrapWithOverflow" TextAlignment="Center" Text="{Binding}"/> 
      </DataTemplate> 
     </GridViewColumn.CellTemplate> 
    </GridViewColumn> 
    <GridViewColumn Width="50" Header="Status" DisplayMemberBinding="{Binding Status}"> 
     <GridViewColumn.CellTemplate> 
      <DataTemplate> 
       <TextBlock TextWrapping="WrapWithOverflow" TextAlignment="Center" Text="{Binding}"/> 
      </DataTemplate> 
     </GridViewColumn.CellTemplate> 
    </GridViewColumn> 
    <GridViewColumn Width="1800" Header="Message" DisplayMemberBinding="{Binding Message}"> 
     <GridViewColumn.CellTemplate> 
      <DataTemplate> 
       <TextBlock TextWrapping="WrapWithOverflow" Text="{Binding}"/> 
      </DataTemplate> 
     </GridViewColumn.CellTemplate> 
    </GridViewColumn> 
</GridView> 
+0

Пожалуйста, смотрите обновление. – DanCode

+0

Нужно ли вызывать метод GetItems для получения новых элементов журнала, и поэтому в коллекцию не добавляются новые элементы? –

+0

Да, метод 'GetLogItems()' должен вызываться всякий раз, когда что-то регистрируется. Поскольку, если к событиям добавляются новые события, это означает, что что-то записывается в журнал. В этом случае следует вызвать 'GetLogItems()'. Другая проблема заключается в том, что в моем дизайне пользовательский интерфейс связывается с 'DateTime',' Status' и 'Message', что означает, что в пользовательском интерфейсе в настоящее время ничего не отображается, потому что вся информация регистратора находится в объекте' LogItems' , – DanCode

Смежные вопросы