2011-01-28 35 views
19

Tôi muốn loại bỏ CheckBoxesfunction nơi Node.Type là 5 hoặc 6. Tôi sử dụng mã này:TreeView Di CheckBox bởi một số nút

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

Vấn đề là sau đó các hình ảnh và Line để Root Node là không có ở đó. Làm cách nào để xóa Hộp kiểm và để Hình ảnh và Dòng ở đó?

This is wrong!

+0

thể trùng lặp của [Tôi đang tìm kiếm một nguồn lực tốt trên treeviews ownerdrawn ] (http://stackoverflow.com/questions/4179522/i-am-looking-for-a-good-resource-on-ownerdrawn-treeviews) –

+0

Tôi đồng ý với Hans; chủ sở hữu-vẽ nói chung là cực kỳ khó khăn. Nếu bạn nhấn mạnh, tôi đã tìm thấy một mẫu hoàn chỉnh hơn về hình ảnh thu nhỏ của chủ sở hữu được đưa ra làm câu trả lời cho [câu hỏi này] (http://stackoverflow.com/questions/1003459/c-treeview-owner-drawing-with-ownerdrawtext- và-the-weird-black-highlighting-wh/1004087), hoàn chỉnh với các dòng nút. –

Trả lời

63

Trong đoạn code bạn đã hiển thị, bạn đang xử lý các bản vẽ chính mình cho tất cả các nút có loại là một trong hai 5 hoặc 6. Đối với phần còn lại của các loại, bạn chỉ cần cho phép hệ thống để vẽ các nút theo cách mặc định. Đó là lý do tại sao tất cả họ đều có những dòng như mong đợi, nhưng những người bạn đang sở hữu vẽ không: Bạn quên vẽ trong các dòng! Bạn thấy đấy, khi bạn nói e.DrawDefault = false; nó giả định rằng bạn thực sự có nghĩa là nó. Không có bản vẽ thông thường nào được thực hiện, bao gồm các dòng tiêu chuẩn.

Bạn sẽ cần phải tự mình vẽ các đường đó hoặc tìm hiểu cách thức mà không cần chủ bản vẽ.

Từ mã bạn hiện có, có vẻ như bạn đang cố gắng mô phỏng kiểu bản vẽ gốc của hệ thống nhiều nhất có thể trong mã chủ sở hữu của bạn, vì vậy không rõ chính xác bạn thực hiện bằng cách vẽ chủ sở hữu ngay từ đầu. Nếu bạn đang cố giữ các hộp kiểm không hiển thị cho các nút loại 5 và 6 (mà, giống như các dòng, đơn giản là không bị rút ra vì bạn không vẽ chúng!), Có một cách đơn giản hơn để thực hiện điều đó mà không cần liên quan đến chủ sở hữu bản vẽ.


Vì vậy, bạn hỏi, cách đơn giản hơn để ẩn hộp kiểm cho từng nút là gì? Vâng, nó chỉ ra rằng kiểm soát TreeView chính nó thực sự hỗ trợ này, nhưng chức năng đó không được tiếp xúc trong các.NET Framework. Bạn cần phải P/Gọi và gọi Windows API để có được nó. Thêm đoạn mã sau vào lớp mẫu của bạn (chắc chắn rằng bạn đã thêm một tuyên bố using cho 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); 
} 

Tất cả những thứ lộn xộn ở trên cùng là P/Gọi tờ khai của bạn. Bạn cần một số ít các hằng số, TVITEM structure mô tả các thuộc tính của mục treeview và SendMessage function. Ở dưới cùng là chức năng bạn thực sự sẽ gọi để thực hiện hành động (HideCheckBox). Bạn chỉ cần vượt qua trong điều khiển TreeView và mục TreeNode cụ thể mà từ đó bạn muốn xóa dấu kiểm.

Vì vậy, bạn có thể loại bỏ các dấu chọn từ mỗi nút con để có được cái gì đó trông như thế này:

      TreeView with checkmarks hidden for child nodes

+0

@Werewolve: Vâng, có lẽ tôi đã bỏ lỡ nó "đơn giản hơn". Cá nhân tôi nghĩ nó đơn giản hơn vì tôi quen thuộc hơn với nó và vì việc vẽ chủ sở hữu rất khó để có được quyền. Về cơ bản, chính điều khiển 'TreeView' hỗ trợ ẩn các hộp kiểm cho các nút riêng lẻ, nhưng chức năng đó không được hiển thị trong .NET Framework. Bạn cần phải P/Gọi để nhận được nó. Tôi sẽ cập nhật câu trả lời của tôi với codez, nếu bạn muốn. –

+0

@Charith: Có, ngoài chủ sở hữu-vẽ (mà bạn chắc chắn không muốn làm, cả vì công việc liên quan và vì nó sẽ không bao giờ trông giống như/cư xử chính xác như kiểm soát TreeView bản địa), đây là cách duy nhất để làm đi. Nó có vẻ kỳ lạ và phức tạp bởi vì bạn đang sử dụng P/Gọi để gọi hàm từ API Win32 gốc, nhưng đó là phần lạ duy nhất về nó. Nó chính xác như thế nào một lập trình viên C hoặc C++ sẽ làm điều đó, họ sẽ không cần các quy ước .NET kỳ lạ để làm cho mọi việc xảy ra. Nhưng bạn không nên lo lắng về việc sử dụng P/Invoke - nó được xây dựng trong khung vì một lý do. –

+5

Kiểm tra câu trả lời này cho giải pháp cho chế độ lỗi của mã này: http://stackoverflow.com/questions/7308238/treeview-problem-with-treenode-handle-not-returning/7308950#7308950 –

4

này là rất tốt! Sửa đổi duy nhất tôi muốn thực hiện là chỉ vượt qua TreeNode chứ không phải là TreeView theo phương pháp HideCheckBox. Các TreeView có thể được lấy từ TreeNode bản thân:

TreeView tvw = node.TreeView; 
13

Sử dụng TreeViewExtensions.

mẫu Cách sử dụng:

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

Đây là mã của câu trả lời như một phương pháp mở rộng, sử dụng này, bạn có thể làm:

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); 
    } 
} 
Các vấn đề liên quan