2010-03-13 5 views
6

Hiện tại, tôi biết cách thực hiện lười biếng quy trình tải của các nút trong điều khiển treeview và đọc các câu hỏi liên quan trong stackoverflow, nhưng tôi cũng đọc về các giao diện IHierarchyData và IHierarchicalEnumerable asp.net (Tôi không biết mã asp.net) cho phép liên kết một bộ sưu tập với một số lần xem trang để hiển thị các mục tự động.IHierarchyData và IHierarchicalEnumerable trong Winforms

Tôi muốn biết tôi có thể làm tương tự trong winforms và C# hay không. Tôi nghĩ rằng các giao diện được đề cập trước đó không có sẵn trong winforms.

Cảm ơn.

Trả lời

3

Biểu mẫu Windows TreeView không biết cách liên kết với phiên bản IHierarchyData, điều này không có gì đáng ngạc nhiên khi giao diện có liên quan dành cho tiêu thụ bằng điều khiển web (đặc biệt là bản đồ trang web).

Tuy nhiên, thực sự không quá khó để xây dựng lớp ràng buộc dữ liệu của riêng bạn. Điều này có vẻ như một vấn đề thú vị vì vậy tôi đã ném một cái với nhau chỉ để cho vui. Tôi sẽ hướng dẫn bạn qua các hoạt động bên trong.

Đầu tiên, tạo một lớp thành phần cơ bản. Visual Studio sẽ bạn bắt đầu với mã như thế này:

public partial class TreeViewHierarchyBinding : Component 
{ 
    public TreeViewHierarchyBinding() 
    { 
     InitializeComponent(); 
    } 

    public TreeViewHierarchyBinding(IContainer container) 
    { 
     container.Add(this); 
     InitializeComponent(); 
    } 
} 

Một mảnh rõ ràng của "nhà nước" thành phần này cần phải có là một ánh xạ từ mỗi TreeNode-IHierarchyData của nó. Bây giờ chúng ta có thể hack xung quanh điều này bằng cách ném nó vào thuộc tính Tag của TreeNode, nhưng chúng ta hãy cố gắng làm cho thành phần này trở nên không xâm lấn nhất có thể và theo dõi trạng thái riêng của nó. Do đó, chúng tôi sẽ sử dụng một từ điển. Thêm lĩnh vực này vào trong lớp:

private Dictionary<TreeNode, IHierarchyData> nodeDictionary = new 
    Dictionary<TreeNode, IHierarchyData>(); 

Bây giờ, ở mức tối thiểu, thành phần này cần phải biết làm thế nào để cư cha mẹ cụ TreeNode của một lớp TreeView từ của nó tương ứng với ràng buộc IHierarchyData, vì vậy chúng ta hãy viết mã tiếp theo:

private void PopulateChildNodes(TreeNodeCollection parentCollection, 
    IHierarchicalEnumerable children) 
{ 
    parentCollection.Clear(); 
    foreach (object child in children) 
    { 
     IHierarchyData childData = children.GetHierarchyData(child); 
     TreeNode childNode = new TreeNode(childData.ToString()); 
     if (childData.HasChildren) 
     { 
      childNode.Nodes.Add("Dummy"); // Make expandable 
     } 
     nodeDictionary.Add(childNode, childData); 
     parentCollection.Add(childNode); 
    } 
} 

private void UpdateRootNodes(TreeView tv, IHierarchyData hierarchyData) 
{ 
    if (tv == null) 
    { 
     return; 
    } 
    tv.Nodes.Clear(); 
    if (hierarchyData != null) 
    { 
     IHierarchicalEnumerable roots = hierarchyData.GetChildren(); 
     PopulateChildNodes(tv.Nodes, roots); 
    } 
} 

Phần này khá đơn giản. Phương thức đầu tiên chỉ điền một số TreeNodeCollection (tức làtài sản Nodes của số TreeNode) với cấu trúc phân cấp thu được từ cá thể IHierarchyData, sử dụng giao diện IHierarchyEnumerable. Những điều chỉ thực sự hấp dẫn phương pháp này không bao gồm:

  1. Thêm một nút giả khi thể hiện IHierarchyData có trẻ em; điều này làm cho dấu "+" hiển thị trong chế độ xem dạng cây, nếu không chúng tôi sẽ không thể mở rộng thêm bất kỳ thứ gì; và

  2. Thêm nút mới được thêm vào từ điển với ví dụ IHierarchyData khớp với.

Phương pháp thứ hai thậm chí còn đơn giản hơn, nó sẽ thực hiện "công việc ràng buộc" ban đầu, thay thế bất cứ thứ gì trong gốc của cây với dụ top-level IHierarchyData của chúng tôi.

Điều tiếp theo mà thành phần của chúng tôi cần thực hiện là móc sự kiện tải từ số TreeView để thực hiện tải chậm. Đây là mã để làm điều đó:

private void RegisterEvents(TreeView tv) 
{ 
    tv.BeforeExpand += TreeViewBeforeExpand; 
} 

private void UnregisterEvents(TreeView tv) 
{ 
    tv.BeforeExpand -= TreeViewBeforeExpand; 
} 

private void TreeViewBeforeExpand(object sender, TreeViewCancelEventArgs e) 
{ 
    if (e.Node.Checked) 
    { 
     return; 
    } 
    IHierarchyData hierarchyData; 
    if (nodeDictionary.TryGetValue(e.Node, out hierarchyData)) 
    { 
     PopulateChildNodes(e.Node.Nodes, hierarchyData.GetChildren()); 
     e.Node.Checked = true; 
    } 
} 

Hai phương pháp đầu tiên phải tự giải thích và phương pháp thứ ba là mã tải xuống thực tế. Chúng tôi đang gian lận một chút ở đây, sử dụng thuộc tính TreeNode.Checked để phân định liệu các nút con đã được tải sao cho chúng tôi không thực hiện bất kỳ tải lại không cần thiết nào. Tôi luôn làm điều này khi tôi thực hiện những cây lười biếng vì trong kinh nghiệm của tôi, tôi hầu như không bao giờ sử dụng tài sản TreeNode.Checked. Tuy nhiên, nếu bạn cần sử dụng thuộc tính này cho cái gì khác, bạn có thể sử dụng thuộc tính khác (như Tag), tạo một từ điển khác để giữ trạng thái mở rộng hoặc sửa đổi từ điển hiện tại để giữ lớp tổng hợp (chứa IHierarchyData là cũng như tài sản Expanded). Tôi vẫn giữ nó đơn giản bây giờ.

Phần còn lại sẽ có ý nghĩa với bạn nếu bạn đã triển khai tải chậm trong cây trước, vì vậy, hãy bỏ qua. Thực sự là điều duy nhất còn lại để làm vào thời điểm này là thực hiện một số thuộc tính/người sử dụng thiết kế mà thực sự sẽ dây lên cây và dữ liệu:

private IHierarchyData dataSource; 
private TreeView treeView; 

[Browsable(false)] 
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
public IHierarchyData DataSource 
{ 
    get { return dataSource; } 
    set 
    { 
     if (value != dataSource) 
     { 
      dataSource = value; 
      nodeDictionary.Clear(); 
      UpdateRootNodes(treeView, value); 
     } 
    } 
} 

[Category("Behavior")] 
[DefaultValue(null)] 
[Description("Specifies the TreeView that the hierarchy should be bound to.")] 
public TreeView TreeView 
{ 
    get { return treeView; } 
    set 
    { 
     if (value != treeView) 
     { 
      if (treeView != null) 
      { 
       UnregisterEvents(treeView); 
      } 
      treeView = value; 
      nodeDictionary.Clear(); 
      RegisterEvents(value); 
      UpdateRootNodes(treeView, dataSource); 
     } 
    } 
} 

Peasy dễ dàng. Chúng tôi có một tài sản DataSource chấp nhận thư mục gốc IHierarchyData và thuộc tính TreeView mà bạn có thể truy cập từ nhà thiết kế. Một lần nữa, các công cụ đơn giản ở đây, khi thuộc tính DataSource được cập nhật, chúng tôi chỉ cần đặt lại tra cứu và điền lại gốc. Khi thuộc tính TreeView được cập nhật, chúng tôi phải thực hiện thêm một chút công việc, đăng ký các sự kiện, đảm bảo hủy đăng ký sự kiện khỏi chế độ xem dạng cây cũ và thực hiện tất cả những việc mà chúng tôi thực hiện khi nguồn dữ liệu thay đổi.

Đó thực sự là tất cả với nó! Mở trình thiết kế Windows Forms, thả một TreeView, sau đó thả một TreeViewHierarchyBinding và đặt thuộc tính TreeView của nó vào chế độ xem dạng cây bạn vừa bỏ. Cuối cùng, trong mã của bạn ở đâu đó (ví dụ trong trường hợp), cung cấp cho nó một nguồn dữ liệu:.

private void Form1_Load(object sender, EventArgs e) 
{ 
    DirectoryInfo dir = new DirectoryInfo("C:\\"); 
    treeViewHierarchyBinding1.DataSource = new FileSystemHierarchyData(dir); 
} 

(Lưu ý - này sử dụng ví dụ FileSystemHierarchyData đó là trên MSDN page for IHierarchyData Ví dụ không phải là rất mạnh mẽ, nó doesn 't kiểm tra cho UnauthorizedAccessException hoặc bất cứ điều gì, nhưng nó là đủ tốt để chứng minh điều này).

Và đó là nó. Chạy ứng dụng của bạn và xem nó ràng buộc.Bây giờ bạn có thể sử dụng lại thành phần TreeViewHierarchyBinding ở bất kỳ đâu - chỉ cần thả nó vào một biểu mẫu, gán cho nó một TreeView và cung cấp cho nó một cá thể IHierarchyData làm nguồn dữ liệu.

Tôi đã đặt complete code on PasteBin nếu bạn muốn có phiên bản sao chép và dán.

Hãy vui vẻ!

+0

Thay vì sử dụng thuộc tính Đã kiểm tra, bạn cũng có thể sử dụng tên nút con giả không thể hoặc không thể xảy ra (như có \ trong cây hệ thống tệp). Bằng cách này, xác thực IsLoaded có thể là Nếu TreeNodeCollection.Nodes.Count == 1 và TreeNodeCollection.Nodes [0] .Text == "\ MyDummyValue /" – bkqc

1

Các giao diện có sẵn, nhưng sẽ yêu cầu bạn thêm tham chiếu vào System.Web.UI. (Nó cũng có thể yêu cầu bạn sử dụng toàn bộ .NET Framework redistributable thay vì Hồ sơ Khách hàng, mặc dù tôi không chắc chắn về điều đó.)

Câu hỏi lớn hơn là: Kiểm soát WinForms TreeView có tự động hiểu cách làm việc với các giao diện này? Tôi tin rằng câu trả lời cho câu hỏi đó là "Không", nhưng bạn sẽ cần phải kiểm tra/xác minh điều đó.

1

Có một bài viết thú vị here cho bạn thấy cách xây dựng các phương pháp mở rộng để đạt được những gì tôi nghĩ rằng bạn đang tìm kiếm. Không có sẵn có sẵn trong System.Windows.Forms.TreeView để liên kết với một bộ sưu tập từ những gì tôi có thể tìm thấy.

Bạn có thể bao gồm System.Web.UI trong dự án của mình để làm cho IHierarchyData và IHierarchicalEnumerable interfaces có sẵn, nhưng TreeView sẽ không thể đính kèm vào chúng mà không có các phương thức mở rộng.

Mã nguồn mẫu từ trang web sẽ cho phép bạn liên kết bất kỳ bộ sưu tập IDictionary nào với TreeView.