Ошибка рисования владельца TreeView при выборе

Я пытаюсь добавить еще несколько значков к элементам стандартного элемента управления System.Windows.Forms.TreeView.

Мой план состоял в том, чтобы изменить только область метки элемента управления древовидной структуры, но это показывает странное поведение. Если я щелкну узел, чтобы выбрать его, когда кнопка мыши нажата, фон будет отображаться правильно с цветом выделения. Однако текст имеет неправильный невыбранный цвет, пока я не отпущу кнопку мыши. Как будто e.State содержит неправильное состояние между нажатием и отпусканием кнопки мыши.

Вот что я делаю: я инициализирую с помощью this.DrawMode = TreeViewDrawMode.OwnerDrawText, а затем регистрирую свой обработчик событий с помощью this.DrawNode += LayoutTreeView_DrawNode. Вот обработчик:

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);
}

Если я установлю обработчик в его случае по умолчанию...

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

... происходит то же самое, что странно, поскольку Windows фактически рисует это сейчас. Такое поведение характерно для Windows XP с .Net 3.5.

Есть ли способ обойти это странное поведение?


person Coincoin    schedule 09.03.2010    source источник
comment
К вашему сведению, всегда полезно указывать версию .Net, с которой вы имеете дело. Я попробую ваш образец, чтобы увидеть, полностью ли я понимаю то, что вы видите. Если я думаю, что знаю, я скажу вам, что, по моему мнению, происходит.   -  person Jason D    schedule 11.03.2010
comment
Кроме того, я никогда не был поклонником рисования потребителя элемента управления. Я всегда настаиваю на том, чтобы это было сделано в производном классе, таким образом, если такое же поведение требуется в другой форме или приложении, это проще сделать.   -  person Jason D    schedule 11.03.2010
comment
Я не могу воспроизвести описанное поведение с отрисовкой по умолчанию, но могу с пользовательским кодом. Я использую Vista x64; VS 2008. .Net 3.5. Не могли бы вы добавить версию ОС, Visual Studio и .Net, которую вы используете, к вопросу. (До меня доходили слухи, что Vista и Windows 7 имеют некоторые отличия от XP в том, как TreeView работает в ОС.)   -  person Jason D    schedule 11.03.2010
comment
Ну, на самом деле это производный элемент управления, потребляющий свои собственные события. Поведение в Windows XP с .Net 3.5   -  person Coincoin    schedule 11.03.2010


Ответы (1)


Изменять

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

to

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

Это работало на Vista x64 и VS 2008 с .Net 3.5. Дайте мне знать, если это работает для вас.

Что я заметил, наблюдая за поведением окон по умолчанию, так это то, что текст и подсветка не рисовались, пока узел не был выбран и не получил фокус. Поэтому я проверил состояние фокусировки, чтобы изменить цвет текста. Однако это не совсем точно имитирует поведение Widows, где новые цвета не используются до тех пор, пока мышь не будет отпущена. Похоже, что момент, когда он выбирает отрисовку состояния синего выделения, изменяется в режиме нарисованного владельцем по сравнению с рисованием в окнах ... Что, по общему признанию, сбивает с толку.

РЕДАКТИРОВАТЬ Однако, когда вы создаете собственное производное древовидное представление, у вас есть полный контроль над тем, когда все рисуется.

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);
    }
}
person Jason D    schedule 10.03.2010
comment
Кроме того, захват кнопок мыши с помощью mouseup и down не работает. Это может быть специфично для XP, но элемент управления уже обрабатывает выделение и перерисовку ДО того, как в элементе управления возникнут события mosue. - person Coincoin; 11.03.2010
comment
Я пробовал что-то подобное, и он отлично работает .... пока вы не прокрутите и не перетащите. Я смирился с тем, что рисую весь элемент самостоятельно, и теперь, по крайней мере, текст синхронизирован с фоновым цветом, хотя поведение немного странное. Я приму ваш ответ таким, какой он есть, я думаю, это самое близкое к исходному поведению XP без сбоев. - person Coincoin; 11.03.2010
comment
Оф. Думаю, я не стал возиться с прокруткой и перетаскиванием. Я сделал весь рисунок сам немного. Это много кода, но стоит, если это необходимо. (Я полагаю, что мой код был ~ 1000 LOC, так как мне нужно было нарисовать флажки, плюс минус и линии...) - person Jason D; 12.03.2010