Code Snippet
- using System;
- using NLog;
- using NLog.Targets;
- namespace VWBT.Controls.Log
- {
- public class MemoryEventTarget : Target
- {
- public event Action<LogEventInfo> EventReceived;
- /// <summary>
- /// Notifies listeners about new event
- /// </summary>
- /// <param name="logEvent">The logging event.</param>
- protected override void Write(LogEventInfo logEvent)
- {
- if (EventReceived != null) {
- EventReceived(logEvent);
- }
- }
- }
- }
Now we are ready to define our logging control. We will keep last 50 log messages in the ObservableColection, which we will bind to the ListView control. We also register event for our memory target inwhich we update our collection.
Code Snippet
- using System;
- using System.Collections.ObjectModel;
- using System.Windows.Controls;
- using NLog;
- using VWBT.Controls.Log;
- namespace VWBT.Controls
- {
- /// <summary>
- /// Interaction logic for LoggingControl.xaml
- /// </summary>
- public partial class LoggingControl : UserControl
- {
- readonly MemoryEventTarget _logTarget; // My new custom Target (code is attached here MemoryQueue.cs)
- public static ObservableCollection<LogEventInfo> LogCollection { get; set; }
- public LoggingControl()
- {
- LogCollection = new ObservableCollection<LogEventInfo>();
- InitializeComponent();
- // init memory queue
- _logTarget = new MemoryEventTarget();
- _logTarget.EventReceived += EventReceived;
- NLog.Config.SimpleConfigurator.ConfigureForTargetLogging(_logTarget, LogLevel.Debug);
- }
- private void EventReceived(LogEventInfo message)
- {
- Dispatcher.Invoke(new Action(() => {
- if (LogCollection.Count >= 50) LogCollection.RemoveAt(LogCollection.Count - 1);
- LogCollection.Add(message);
- }));
- }
- }
- }
Following is the simple design of the logging control. Please note the binding.
Code Snippet
- <UserControl x:Class="VWBT.Controls.LoggingControl"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:Log="clr-namespace:VWBT.Controls.Log" mc:Ignorable="d"
- d:DesignHeight="230" d:DesignWidth="457"
- DataContext="{Binding RelativeSource={RelativeSource Self}}">
- <UserControl.Resources>
- <Log:LogItemBgColorConverter x:Key="LogItemBgColorConverter" />
- <Log:LogItemFgColorConverter x:Key="LogItemFgColorConverter" />
- </UserControl.Resources>
- <Grid>
- <!--<TextBox IsReadOnly="True" AcceptsReturn="True" Height="Auto" HorizontalAlignment="Stretch" Name="dgLog" VerticalAlignment="Stretch" Width="Auto"/>-->
- <ListView ItemsSource="{Binding LogCollection}" Name="logView">
- <ListView.ItemContainerStyle>
- <Style TargetType="{x:Type ListViewItem}">
- <Setter Property="ToolTip" Value="{Binding FormattedMessage}" />
- <Setter Property="Background" Value="{Binding Level, Converter={StaticResource LogItemBgColorConverter}}" />
- <Setter Property="Foreground" Value="{Binding Level, Converter={StaticResource LogItemFgColorConverter}}" />
- <Style.Triggers>
- <Trigger Property="IsSelected" Value="True">
- <Setter Property="Background" Value="DarkOrange"/>
- <Setter Property="Foreground" Value="black"/>
- </Trigger>
- <Trigger Property="IsMouseOver" Value="True">
- <Setter Property="Background" Value="{Binding RelativeSource={RelativeSource Self}, Path=Background}"/>
- <Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource Self}, Path=Foreground}"/>
- </Trigger>
- </Style.Triggers>
- </Style>
- </ListView.ItemContainerStyle>
- <ListView.View>
- <GridView>
- <GridView.Columns>
- <!--<GridViewColumn DisplayMemberBinding="{Binding LoggerName}" Header="Logger"/>-->
- <GridViewColumn DisplayMemberBinding="{Binding Level}" Header="Level"/>
- <GridViewColumn DisplayMemberBinding="{Binding FormattedMessage}" Width="500" Header="Message"/>
- <GridViewColumn DisplayMemberBinding="{Binding Exception}" Header="Exception"/>
- </GridView.Columns>
- </GridView>
- </ListView.View>
- </ListView>
- <!--<ListBox Height="Auto" HorizontalAlignment="Stretch" Name="dgLog" VerticalAlignment="Stretch" Width="Auto" />-->
- </Grid>
- </UserControl>
Previous XAML code uses couple converters which allow us to display messages in different color.
Code Snippet
- using System;
- using System.Globalization;
- using System.Windows.Data;
- using System.Windows.Media;
- namespace VWBT.Controls.Log
- {
- public class LogItemBgColorConverter : IValueConverter
- {
- public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
- {
- if ("Warn" == value.ToString()) {
- return Brushes.Yellow;
- } else if ("Error" == value.ToString()) {
- return Brushes.Tomato;
- }
- return Brushes.White;
- }
- public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
- {
- throw new NotImplementedException();
- }
- }
- }
Code Snippet
- using System;
- using System.Globalization;
- using System.Windows.Data;
- using System.Windows.Media;
- namespace VWBT.Controls.Log
- {
- public class LogItemFgColorConverter : IValueConverter
- {
- public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
- {
- if ("Error" == value.ToString()) {
- return Brushes.Black;
- }
- return Brushes.Black;
- }
- public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
- {
- throw new NotImplementedException();
- }
- }
- }
That's all folks. With this control you are ready to display your logs directly in your application! Comments welcome!