Подтвердить что ты не робот

TreeView Удалить CheckBox некоторыми узлами

Я хочу удалить CheckBoxes, где Node.Type - 5 или 6. Я использую этот код:

private void TvOne_DrawNode(object sender, DrawTreeNodeEventArgs e)
{
    int type = (e.Node as Node).typ;
    if (type == 5 || type == 6)
    {
        Color backColor, foreColor;
        if ((e.State & TreeNodeStates.Selected) == TreeNodeStates.Selected)
        {
            backColor = SystemColors.Highlight;
            foreColor = SystemColors.HighlightText;
        }
        else if ((e.State & TreeNodeStates.Hot) == TreeNodeStates.Hot)
        {
            backColor = SystemColors.HotTrack;
            foreColor = SystemColors.HighlightText;
        }
        else
        {
            backColor = e.Node.BackColor;
            foreColor = e.Node.ForeColor;
        }
        using (SolidBrush brush = new SolidBrush(backColor))
        {
            e.Graphics.FillRectangle(brush, e.Node.Bounds);
        }
        TextRenderer.DrawText(e.Graphics, e.Node.Text, this.TvOne.Font,
            e.Node.Bounds, foreColor, backColor);

        if ((e.State & TreeNodeStates.Focused) == TreeNodeStates.Focused)
        {
            ControlPaint.DrawFocusRectangle(e.Graphics, e.Node.Bounds,
                foreColor, backColor);
        }
        e.DrawDefault = false;
    }
    else
    {
        e.DrawDefault = true;
    }
}

Проблема заключается в том, что тогда изображения и линии к корню Node нет. Как удалить флажок и оставить изображение и строку там?

Это неправильно!

4b9b3361

Ответ 1

В коде, который вы указали, вы сами обрабатываете чертеж для всех узлов с типом 5 или 6. Для остальных типов вы просто позволяете системе рисовать узлы в по умолчанию. Вот почему у всех есть линии, как ожидалось, но те, которые вы рисуете владельцем, не делают: вы забыли рисовать линии! Видите ли, когда вы говорите e.DrawDefault = false;, это предполагает, что вы действительно это имеете в виду. Ни один обычный рисунок не выполняется, включая стандартные строки.

Вам нужно либо нарисовать эти строки самостоятельно, либо выяснить, как обойтись без рисования владельца.

Из кода, который у вас есть сейчас, похоже, что вы пытаетесь имитировать собственный стиль рисования системы в максимально возможной степени в коде вашего владельца-рисования, поэтому мне не ясно, что именно вы выполняете с помощью рисования владельца первое место. Если вы просто пытаетесь сохранить флажки для узлов типа 5 и 6 (которые, как и строки, просто не рисуются, потому что вы их не рисуете!), Есть более простой способ сделать это без привлечения владельца рисунок.


Итак, вы спрашиваете, что это более простой способ скрыть флажки для отдельных узлов? Ну, оказывается, что сам контроль TreeView фактически поддерживает это, но эта функциональность не раскрывается в .NET Framework. Вам нужно P/Invoke и вызвать Windows API, чтобы получить от него. Добавьте следующий код в класс формы (убедитесь, что вы добавили объявление using для System.Runtime.InteropServices):

private const int TVIF_STATE = 0x8;
private const int TVIS_STATEIMAGEMASK = 0xF000;
private const int TV_FIRST = 0x1100;
private const int TVM_SETITEM = TV_FIRST + 63;

[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Auto)]
private struct TVITEM
{
    public int mask;
    public IntPtr hItem;
    public int state;
    public int stateMask;
    [MarshalAs(UnmanagedType.LPTStr)]
    public string lpszText;
    public int cchTextMax;
    public int iImage;
    public int iSelectedImage;
    public int cChildren;
    public IntPtr lParam;
}

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam,
                                         ref TVITEM lParam);

/// <summary>
/// Hides the checkbox for the specified node on a TreeView control.
/// </summary>
private void HideCheckBox(TreeView tvw, TreeNode node)
{
    TVITEM tvi = new TVITEM();
    tvi.hItem = node.Handle;
    tvi.mask = TVIF_STATE;
    tvi.stateMask = TVIS_STATEIMAGEMASK;
    tvi.state = 0;
    SendMessage(tvw.Handle, TVM_SETITEM, IntPtr.Zero, ref tvi);
}

Все беспорядочные вещи вверху - это ваши объявления P/Invoke. Вам нужно несколько констант, структура TVITEM, которая описывает атрибуты элемента treeview, и SendMessage. В нижней части находится функция, которую вы на самом деле вызываете для совершения действия (HideCheckBox). Вы просто передаете элемент управления TreeView и конкретный элемент TreeNode, из которого вы хотите удалить галочку.

Итак, вы можете удалить галочки с каждого из дочерних узлов, чтобы получить что-то похожее на это:

    TreeView with checkmarks hidden for child nodes

Ответ 2

Использование TreeViewExtensions.

Пример использования:

private void MyForm_Load(object sender, EventArgs e)
{
     this.treeview1.DrawMode = TreeViewDrawMode.OwnerDrawText;
     this.treeview1.DrawNode += new DrawTreeNodeEventHandler(arbolDependencias_DrawNode);
}

void treeview1_DrawNode(object sender, DrawTreeNodeEventArgs e)
{
    if (e.Node.Level == 1) e.Node.HideCheckBox();
    e.DrawDefault = true;
}

Вот код ответа как метод расширения, с помощью которого вы можете:

public static class TreeViewExtensions
{
    private const int TVIF_STATE = 0x8;
    private const int TVIS_STATEIMAGEMASK = 0xF000;
    private const int TV_FIRST = 0x1100;
    private const int TVM_SETITEM = TV_FIRST + 63;

    [StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Auto)]
    private struct TVITEM
    {
        public int mask;
        public IntPtr hItem;
        public int state;
        public int stateMask;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string lpszText;
        public int cchTextMax;
        public int iImage;
        public int iSelectedImage;
        public int cChildren;
        public IntPtr lParam;
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam,
                                             ref TVITEM lParam);

    /// <summary>
    /// Hides the checkbox for the specified node on a TreeView control.
    /// </summary>
    public static void HideCheckBox(this TreeNode node)
    {
        TVITEM tvi = new TVITEM();
        tvi.hItem = node.Handle;
        tvi.mask = TVIF_STATE;
        tvi.stateMask = TVIS_STATEIMAGEMASK;
        tvi.state = 0;
        SendMessage(node.TreeView.Handle, TVM_SETITEM, IntPtr.Zero, ref tvi);
    }
}

Ответ 3

Это очень хорошо! Единственное, что я сделал бы, это передать только TreeNode, а не TreeView методу HideCheckBox. TreeView можно извлечь из самого TreeNode:

TreeView tvw = node.TreeView;