我正在建立一个记录器。 UI(LoggerView)绑定到LogItem的三个属性:DateTime
,Status
和Message
。当我运行程序时,会创建日志记录事件并正确登录到UI。但是,当我关闭UI,记录更多其他事件并再次打开UI时,其他事件会记录到events
,但它们不会出现在UI中。
问题是,当新的LogItems
被添加到集合时,不会通知UI。如何在添加其他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 Logic:
[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();
}
}
更新:
我注意到CustomLogger中的静态方法GetLogItems()
仅在第一次打开UI时执行。在GetLogItems()
更新后,events
不会执行。
有没有办法在事件中通知财产变更?
要解决这个问题,我认为最好在触发UI时触发LogItems,DateTime,Status和Message的setter。 MenuItem_Click
方法负责触发UI。是否可以在NotifyPropertyChanged
之前调用window.Show()
?
答案 0 :(得分:2)
我认为您在解析绑定后正在替换LogItems ObservableCollection,并且您没有调用NotifyPropertyChanged来通知UI。
尝试更改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>