Powstał na podstawie wielu podobnych implementacji znalezionych w sieci.
Większość z nich używa
Invoke() do publikowani danych na kontrolce, co może prowadzić do deadlock-a, w sytuacji gdy wątek GUI i jakiś inny razem starają się coś zalogować. Zastąpienie Invoke() wersją asynchroniczną BeginInvoke rozwiązuje problem.Czemu czegoś takiego nie ma w standardzie log4net, nie wiem. Wersja dla NLog oferuje znacznie więcej od tej tutaj (kolorowanie elementów linii loga, tworzenie osobnego okna z kontrolką, integracja z kontrolką na formatce z poziomu xml).
public class RichTextBoxAppender : AppenderSkeleton
{
private RichTextBox m_rich_text_box = null;
private LevelMapping m_level_mapping = new LevelMapping();
public int MaxLines = 100000;
private delegate void UpdateControlDelegate(LoggingEvent a_logging_event);
public RichTextBoxAppender(RichTextBox a_rich_text_box)
: base()
{
m_rich_text_box = a_rich_text_box;
}
private void UpdateControl(LoggingEvent a_logging_event)
{
LevelTextStyle selectedStyle =
m_level_mapping.Lookup(a_logging_event.Level) as LevelTextStyle;
if (selectedStyle != null)
{
m_rich_text_box.SelectionBackColor = selectedStyle.BackColor;
m_rich_text_box.SelectionColor = selectedStyle.TextColor;
m_rich_text_box.SelectionFont =
new Font(m_rich_text_box.Font, selectedStyle.FontStyle);
}
m_rich_text_box.AppendText(RenderLoggingEvent(a_logging_event));
// Clear if too big.
if (MaxLines > 0)
{
if (m_rich_text_box.Lines.Length > MaxLines)
{
int pos = m_rich_text_box.GetFirstCharIndexFromLine(1);
m_rich_text_box.Select(0, pos);
m_rich_text_box.SelectedText = String.Empty;
}
}
// Autoscroll.
m_rich_text_box.Select(m_rich_text_box.TextLength, 0);
m_rich_text_box.ScrollToCaret();
}
protected override void Append(LoggingEvent a_logging_event)
{
if (m_rich_text_box.InvokeRequired)
{
m_rich_text_box.BeginInvoke(
new UpdateControlDelegate(UpdateControl),
new object[] { a_logging_event });
}
else
{
UpdateControl(a_logging_event);
}
}
public void AddMapping(LevelTextStyle a_mapping)
{
m_level_mapping.Add(a_mapping);
}
public override void ActivateOptions()
{
base.ActivateOptions();
m_level_mapping.ActivateOptions();
}
protected override bool RequiresLayout
{
get
{
return true;
}
}
}
public class LevelTextStyle : LevelMappingEntry
{
public bool Bold;
public bool Italic;
public Color TextColor;
public Color BackColor;
public FontStyle FontStyle { get; private set; }
public override void ActivateOptions()
{
base.ActivateOptions();
if (Bold)
FontStyle |= FontStyle.Bold;
if (Italic)
FontStyle |= FontStyle.Italic;
}
}
Brak komentarzy:
Prześlij komentarz