2012-02-16

RichTextBoxAppender

Jak w tytule, appender dla RichTextBox-a. W NLog dostępny w standardzie.

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