4

I'm trying to add a few more icons to elements of a standard System.Windows.Forms.TreeView control.

My plan was to only change the label area of the treeview control, but it shows a strange behaviour. If I click a node to select it, when the mouse button is depressed the background is draw correctly with the highlight color. However, the text is the wrong unselected color until I release the mouse button. It's as if e.State contains the wrong state between when the mouse button is pressed and released.

Here is what I'm doing: I init with this.DrawMode = TreeViewDrawMode.OwnerDrawText and then register my event handler with this.DrawNode += LayoutTreeView_DrawNode. Here is the handler:

void LayoutTreeView_DrawNode(object sender, DrawTreeNodeEventArgs e)
{

    Color color = (e.State & TreeNodeStates.Selected) != 0 ?
        SystemColors.HighlightText : SystemColors.WindowText;

    TextFormatFlags flags = TextFormatFlags.Left | TextFormatFlags.SingleLine |
       TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis;

    TextRenderer.DrawText(e.Graphics, e.Node.Text, Font, e.Bounds, color, flags);
}

If I set the handler to its default case...

void LayoutTreeView_DrawNode(object sender, DrawTreeNodeEventArgs e)
{
    e.DefaultDraw = true;
}

...the same thing happens, which is weird since windows is actually drawing it now. This behaviour is in Windows XP with .Net 3.5.

Is there any way to work around this strange behaviour?

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Coincoin
  • 27,880
  • 7
  • 55
  • 76
  • FYI, it's always useful to include the .Net version you're dealing with. I'll give your sample a try to see if I fully comprehend what you're seeing. If I think I do I'll tell you what I think is going on. – Jason D Mar 10 '10 at 21:07
  • Also, I'm never a fan of doing drawing in the consumer of a control. I always push to have it done in a derived class, that way if the same behavior is needed on another form or application it's easier to do. – Jason D Mar 10 '10 at 21:08
  • I am unable to reproduce the described behavior with the draw default, but can with the custom code. I am running Vista x64; VS 2008. .Net 3.5. Could you add the OS, Visual Studio and .Net version that you're using to the question. (I've heard rumors that Vista and Windows 7 have some differences vs XP for how TreeViews work within the OS.) – Jason D Mar 10 '10 at 21:13
  • Well, actually it is a derived control consuming its own events. The behaviour is in Windows XP with .Net 3.5 – Coincoin Mar 11 '10 at 16:38

1 Answers1

3

Change

Color color = (e.State & TreeNodeStates.Selected) != 0 ?
    SystemColors.HighlightText : SystemColors.WindowText;

to

Color color = (e.State & TreeNodeStates.Focused) != 0 ?
    SystemColors.HighlightText : SystemColors.WindowText;

This worked on Vista x64 and VS 2008 with .Net 3.5. Let me know if it works for you.

What I observed when watching the default windows behavior was that the text and highlight weren't drawn until the node was selected and had focus. So I checked for the focused condition in order to change the text color. However this doesn't precisely mimic the Widows behavior where the new colors aren't used until the mouse is released. It appears the point when it chooses to draw the blue highlight status changes when in ownerdrawn mode versus windows drawing it... Which admittedly is confusing.

EDIT However, when you create your own derived treeview you have full control over when everything is drawn.

public class MyTreeView : TreeView
{
    bool isLeftMouseDown = false;
    bool isRightMouseDown = false;
    public MyTreeView()
    {
        DrawMode = TreeViewDrawMode.OwnerDrawText;
    }

    protected override void OnMouseDown(MouseEventArgs e)
    {
        TrackMouseButtons(e);
        base.OnMouseDown(e);
    }

    protected override void OnMouseUp(MouseEventArgs e)
    {
        TrackMouseButtons(e);
        base.OnMouseUp(e);
    }
    protected override void OnMouseMove(MouseEventArgs e)
    {
        TrackMouseButtons(e);
        base.OnMouseMove(e);
    }

    private void TrackMouseButtons(MouseEventArgs e)
    {
        isLeftMouseDown = e.Button == MouseButtons.Left;
        isRightMouseDown = e.Button == MouseButtons.Right;
    }

    protected override void OnDrawNode(DrawTreeNodeEventArgs e)
    {
        // don't call the base or it will goof up your display!
        // capture the selected/focused states
        bool isFocused = (e.State & TreeNodeStates.Focused) != 0;
        bool isSelected = (e.State & TreeNodeStates.Selected) != 0;
        // set up default colors.
        Color color = SystemColors.WindowText;
        Color backColor = BackColor;

        if (isFocused && isRightMouseDown)
        {
            // right clicking on a 
            color = SystemColors.HighlightText;
            backColor = SystemColors.Highlight;
        }
        else if (isSelected && !isRightMouseDown)
        {
            // if the node is selected and we're not right clicking on another node.
            color = SystemColors.HighlightText;
            backColor = SystemColors.Highlight;
        }

        using (Brush sb = new SolidBrush(backColor))
            e.Graphics.FillRectangle(sb,e.Bounds);

        TextFormatFlags flags = TextFormatFlags.Left | TextFormatFlags.SingleLine |
           TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis;

        TextRenderer.DrawText(e.Graphics, e.Node.Text, Font, e.Bounds, color, backColor, flags);
    }
}
Jason D
  • 2,303
  • 14
  • 24
  • Also, capturing mouse buttons with mouseup and down doesn't work. This might be XP specific but the control is already processing selection and redrawing BEFORE the mosue events are raised in the control. – Coincoin Mar 11 '10 at 16:42
  • I tried something similar and it works fine.... until you scroll and drag and drop. I resigned myself to drawing the whole item myself and now at least the text is synchronised with the back ground color even though the behaviour is a little strange. I will accept your answer as it is, I guess, the nearest we can get to the original XP behaviour without glitch. – Coincoin Mar 11 '10 at 16:44
  • OOf. I guess I didn't bother with scroll and drag and drop. I've done the whole draw it yourself bit. It's a lot of code, but worthwhile if needed. (I believe my code was ~1000 LOC as I needed to draw check boxes, plus minus and the lines... ) – Jason D Mar 12 '10 at 00:14