2009-03-20 7 views
5

Tôi có một lớp con của System.Windows.Forms.TreeView được gắn "thủ công" theo cách thủ công vào một tập hợp dữ liệu phân cấp. Tôi muốn người dùng có thể chỉnh sửa nhãn của cây và thay đổi được phản ánh lại dữ liệu. Vì vậy, tôi đặt LabelEdit true và overrode OnAfterLabelEdit theo giai điệu của:Tôi có thể chèn các nút vào một TreeView trong AfterLabelEdit mà không cần chỉnh sửa chúng không?

protected override void OnAfterLabelEdit(NodeLabelEditEventArgs e) 
{ 
    base.OnAfterLabelEdit(e); 

    TreeNode node = e.Node; 

    if (PassesSomeValidation(e.Label)) 
    { 
     MyDataNode dataNode = node.Tag as MyDataNode; 
     dataNode.SomeBoundValue = e.Label; 

     int oldIndex = node.Index; 
     int newIndex = RepositionChangedDataNode(dataNode); 

     TreeNode parent = node.Parent; 
     parent.Nodes.RemoveAt(oldIndex); 
     parent.Nodes.Insert(newIndex, node); 
    } 
    else 
    { 
     e.CancelEdit = true; 
    } 
} 

RepositionChangedDataNode() tái sắp xếp các dữ liệu và trả về chỉ số vào mà nút thay đổi di chuyển sau khi phân loại. Tôi đã hy vọng tôi chỉ có thể di chuyển nút đã chỉnh sửa để phản ánh động thái này.

Vấn đề là điều này làm cho nút thành ở chế độ chỉnh sửa! Tôi đã thử gọi số EndEdit(), nhân bản nút trước khi chèn, thiết lập LabelEdit thành sai và trả về true, gói thay đổi trong BeginUpdate()/EndUpdate() và các kết hợp khác nhau của những ý tưởng này, nhưng không có ý tưởng nào có hiệu lực.

Thủ phạm có vẻ là sự chèn. Ngay cả khi tôi cố gắng chèn một nút hoàn toàn mới mới, nút này sẽ chuyển sang chế độ chỉnh sửa ngay lập tức.

Vì vậy, có cách nào để làm cho TreeView không hoạt động theo cách này không? Và nếu không, liệu có cách giải quyết tốt không?

Một số ý tưởng tôi đã xem xét:

  1. Đặt một TreeViewNodeSorter tùy chỉnh. Tuy nhiên, không muốn phải sắp xếp dữ liệu của tôi hai lần.
  2. Đặt cờ và trì hoãn bước xóa-chèn cho đến một số điểm sau AfterLabelEdit. Nó hoạt động để làm điều đó trong WndProc, nhưng điều này cảm thấy giống như một kludge lớn có khả năng thất bại bằng cách nào đó.
  3. Sử dụng BeginInvoke() để đẩy bước remove-chèn lại vào hàng đợi thông báo như vậy:

    BeginInvoke(new MethodInvoker(delegate(
    { 
        parent.Nodes.RemoveAt(oldIndex); 
        parent.Nodes.Insert(newIndex, node); 
    })); 
    

    này hoạt động và có vẻ sạch hơn với tôi hơn # 2, nhưng tôi biết điều này có lẽ không phải là cách BeginInvoke() được dự định được sử dụng, và nó có thể có hậu quả mà kiến ​​thức rất hạn chế của tôi về máy bơm tin nhắn không thể dự đoán được.

+0

Tôi gặp vấn đề tương tự - bạn đã làm gì? – Handleman

+0

Đã quen với ý tưởng số 3 trong thời gian này. Dường như làm việc tốt cho đến nay. –

+0

Tôi chỉ có một vấn đề tương tự khi cố gắng sắp xếp TreeView trong sự kiện AfterLabelEdit. Tôi đã sử dụng một giải pháp tương tự như của bạn, và nó hoạt động tốt. Đó có thể là một lỗi trong TreeView ... –

Trả lời

0

Nếu bạn đang sử dụng databinding, không nên cập nhật nguồn dữ liệu (SomeBoundValue) kích hoạt làm mới các nút? Nếu bạn lo lắng về hiệu suất, bạn có thể sử dụng một trong các thuật toán sắp xếp hoạt động tốt với dữ liệu gần như đã được sắp xếp (ví dụ, NOT quicksort - merge hoặc heapsort đến để nhớ)

Hoặc bạn có thể phân phối với ràng buộc dữ liệu hoàn toàn và xử lý thủ công việc định vị lại vì bạn đã ở nửa đường với RepositionChangedDataNode() ....

+0

TreeView không tự hỗ trợ dữ liệu, đó là lý do tại sao tôi sao chép giá trị đã thay đổi thành nguồn sao lưu theo cách thủ công. Xử lý thủ công việc định vị lại chính xác là những gì tôi đang cố gắng làm, nhưng nó gây ra hành vi không thể ngừng chỉnh sửa. –

1

thử tạo một biến toàn cầu, chúng ta hãy nói:

private bool _allowEdit; 

khởi tạo nó để true,

trong phương pháp OnAfterLabelEdit bạn đặt nó vào false sau khi thay đổi của bạn:

... int oldIndex = node.Index; 
    int newIndex = RepositionChangedDataNode(dataNode); 

    TreeNode parent = node.Parent; 
    parent.Nodes.RemoveAt(oldIndex); 
    parent.Nodes.Insert(newIndex, node); 
    **_allowEdit = false;** 
} 
else ... 

sau đó chụp sự kiện OnBeforeLabelEdit như sau:

protected override void OnBeforeLabelEdit(NodeLabelEditEventArgs e) 
    { 
     base.OnBeforeLabelEdit(e); 
     e.CancelEdit = !_allowEdit; 
     _allowEdit = true; 
    } 

Tôi nhận thấy rằng ngay sau khi 'AfterLabelEdit' được kích hoạt, 'BeforeLabelEdit' bị từ chối. Đó là lý do tại sao bạn phải dừng nó ngay tại đó.

+0

Đã thử điều này; nó không hoạt động. Nút được chèn vẫn chuyển sang chế độ chỉnh sửa. –

0

Bạn có thể thử mở trình xử lý OnEdit của mình trước khi thêm nút mới và gắn lại sau. Tôi đã nhìn thấy hành vi đó trước đây và đó là cách tôi xử lý nó.

+0

Nhưng vấn đề không phải là bất kỳ người xử lý nào của tôi đều được gọi khi không được. Điều này sẽ không giúp được gì. –

3

Nếu bạn đặt LabelEdit cho TreeView thành false, các nút mới được thêm sẽ không ở chế độ chỉnh sửa.

Bạn chỉ cần xử lý trường hợp người dùng muốn chỉnh sửa nhãn: Tạo trình xử lý cho sự kiện MouseClick của TreeView, nơi bạn nhận được nút được nhấp theo vị trí. Đặt LabelEdit thành true và gọi BeginEdit(). Vào cuối trình xử lý của bạn cho sự kiện AfterLabelEdit (và sau khi gọi số EndEdit(...) tại một điểm thích hợp), hãy đặt lại LabelEdit thành false.

Điều này phù hợp với tôi, trong khi giải pháp với BeginInvoke chỉ thay đổi nút nào ở chế độ chỉnh sửa ở cuối.