WPF log4netのログをWindowに出力する

ここの改変 stackoverflow.com

log4netの設定

    <appender name="TextBoxAppender" type="{NameSpace}.{AppenderName}, {NameSpace}">
      <windowName value={Name}/> //xamlのWindow x:Name="Name"
      <textBoxName value="{UiItemName}"/> //TextBoxとかのx:Name="UiItemName"
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date %-5level %logger - %message" />
      </layout>      
    </appender>

リンク先ではTextBoxを使用しているが、ここではListboxを使用
最初WidowNameはClassNameだと勘違いしていた... vsが作成するxamlはWindowNameが設定されていないので注意

xaml

<Window x:Class="LogViewer.MainWindow" x:Name="{Name}"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:LogViewer"
        mc:Ignorable="d"
        Title="ViewerWindow" Height="450" Width="800">
    <Grid>
        <ListBox x:Name="LogTextBox"></ListBox>
    </Grid>
</Window>
using log4net.Appender;
using log4net.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

namespace LogViewer
{
    class WindowLogAppender : AppenderSkeleton
    {
        private ListBox AppenderTextBox { get; set; }
        private Window window;

        public string WindowName { get; set; }
        public string TextBoxName { get; set; }

        private T FindControl<T>(Control root, string textBoxName) where T : class
        {
            if (root.Name == textBoxName)
            {
                return root as T;
            }

            return root.FindName(textBoxName) as T;
        }

        protected override void Append(log4net.Core.LoggingEvent loggingEvent)
        {
            if (window == null || AppenderTextBox == null)
            {
                if (string.IsNullOrEmpty(WindowName) ||
                    string.IsNullOrEmpty(TextBoxName))
                    return;

                foreach (Window window in Application.Current.Windows)
                {
                    if (window.Name == WindowName)
                    {
                        this.window = window;
                    }
                }
                if (window == null)
                    return;

                AppenderTextBox = FindControl<ListBox>(window, TextBoxName);
                if (AppenderTextBox == null)
                    return;

                window.Closing += (s, e) => AppenderTextBox = null;
            }
            window.Dispatcher.BeginInvoke(new Action(delegate
            {
                AppenderTextBox.Items.Add(RenderLoggingEvent(loggingEvent));
            }));
        }
    }
}