2008-09-17 27 views
5

Có cách nào để buộc một điều khiển listview để xử lý tất cả các nhấp chuột như thể chúng đã được thực hiện thông qua phím Control?Listview Multiple Selection

Tôi cần sao chép chức năng của việc sử dụng phím điều khiển (chọn một mục đặt và hủy trạng thái lựa chọn của nó) để cho phép người dùng dễ dàng chọn nhiều mục cùng một lúc.

Cảm ơn bạn trước.

Trả lời

4

Đó không phải là hành vi tiêu chuẩn của điều khiển ListView, ngay cả khi MultiSelect được đặt thành true.

Nếu bạn muốn tạo ra điều khiển tùy chỉnh riêng của bạn, bạn sẽ cần phải làm như sau:

  1. Rút ra một điều khiển từ ListView
  2. thêm một handler cho sự kiện "được chọn".
  3. Trong "OnSelected", hãy duy trì danh sách các mục đã chọn của riêng bạn.
  4. Nếu mục mới được chọn không có trong danh sách của bạn, hãy thêm nó. Nếu có, hãy xóa nó.
  5. Trong mã, hãy chọn tất cả các mục trong danh sách của bạn.

Cần đơn giản, đủ để thực hiện và cảm thấy giống như chọn nhiều mà không cần sử dụng phím điều khiển!

+0

Tôi đã tự mình làm việc theo những dòng này nhưng muốn kiểm tra xem có điều gì dễ dàng hơn không trước khi tôi tiếp tục khắc phục. Cảm ơn câu trả lời của bạn. – Evan

+0

Đảm bảo rằng danh sách các mục đã chọn lưu trữ "nội dung" chứ không phải chỉ mục. Sử dụng chỉ mục dễ dàng hơn nhưng điều đó có nghĩa là bạn cần giữ cho ListBox.ItemsCollection và danh sách của bạn được đồng bộ hóa. Hy vọng rằng đối tượng hoặc chuỗi của bạn là duy nhất đủ để giữ mối quan hệ này! –

-2

Hành vi Ctrl + Nhấp chuột được thực hiện bởi trình duyệt và ít có liên quan đến Điều khiển .NET thực tế. Kết quả bạn đang cố gắng đạt được có thể được mua lại với rất nhiều JavaScript bổ sung - cách dễ nhất có thể là xây dựng một điều khiển JavaScript từ mặc định hoạt động theo cách này, thay vì cố gắng để hack lên listview. Điều này có được mong muốn không? Trong trường hợp đó tôi có thể nhìn vào nó và lấy lại cho bạn một giải pháp.

+0

Không có gì để làm với trình duyệt, anh ấy đang sử dụng C# và WinForms! –

+0

Cảm ơn anyway, Javascript không thể được sử dụng trong môi trường winforms. – Evan

0

Đi sâu vào ListviewItemCollection và bạn có thể đặt thuộc tính Đã chọn cho từng mục là đúng. Điều này, tôi tin rằng, mô phỏng tính năng "đa lựa chọn" mà bạn đang cố gắng tái sản xuất. (Ngoài ra, như bình luận ở trên đã đề cập, hãy chắc chắn có thuộc tính MultiSelect của bộ lisetview được đặt thành true.)

2

Bạn cũng có thể xem xét sử dụng Checkboxes trên chế độ xem danh sách. Đó là một cách rõ ràng để giao tiếp khái niệm đa lựa chọn cho người dùng trung bình của bạn, những người có thể không biết về Ctrl + Nhấp chuột.

Từ trang MSDN:

Khách sạn CheckBoxesfunction cung cấp một cách để chọn nhiều mục trong việc kiểm soát ListView mà không sử dụng phím CTRL. Tùy thuộc vào ứng dụng của bạn, việc sử dụng các hộp kiểm để chọn các mục thay vì phương pháp chọn nhiều tiêu chuẩn có thể dễ dàng hơn cho người dùng. Ngay cả khi thuộc tính MultiSelect của điều khiển ListView được đặt thành false, bạn vẫn có thể hiển thị hộp kiểm và cung cấp nhiều khả năng lựa chọn cho người dùng. Tính năng này có thể hữu ích nếu bạn không muốn nhiều mục được chọn nhưng vẫn muốn cho phép người dùng chọn nhiều mục từ danh sách để thực hiện thao tác trong ứng dụng của bạn.

2

Đây là giải pháp hoàn chỉnh mà tôi đã sử dụng để giải quyết vấn đề này bằng cách sử dụng WndProc. Về cơ bản, nó thực hiện kiểm tra hit khi chuột được bấm .. sau đó nếu MutliSelect bật, nó sẽ tự động bật/tắt mục [.Selected] và không lo lắng về việc duy trì bất kỳ danh sách nào khác hoặc gây rối với chức năng ListView.

Tôi chưa thử nghiệm điều này trong mọi tình huống, ... nó đã hiệu quả đối với tôi. YMMV.

public class MultiSelectNoCTRLKeyListView : ListView { 
    public MultiSelectNoCTRLKeyListView() { 

    } 

    public const int WM_LBUTTONDOWN = 0x0201; 
    protected override void WndProc(ref Message m) { 
    switch (m.Msg) { 
     case WM_LBUTTONDOWN: 
     if (!this.MultiSelect) 
      break; 

     int x = (m.LParam.ToInt32() & 0xffff); 
     int y = (m.LParam.ToInt32() >> 16) & 0xffff; 

     var hitTest = this.HitTest(x, y); 
     if (hitTest != null && hitTest.Item != null) 
      hitTest.Item.Selected = !hitTest.Item.Selected; 

     return; 
    } 

    base.WndProc(ref m); 
    } 
} 
2

Đây là giải pháp hoàn chỉnh thay đổi giải pháp được cung cấp bởi Matthew M. ở trên.

Nó cung cấp cải tiến cũng như một chút chức năng bổ sung.

Cải thiện: - nhấp chuột trái vào điều khiển để tập trung vào điều khiển. - hành vi nhấp chuột phải là nhất quán (chọn một lần)

Chức năng được thêm: - điều khiển có thuộc tính (MultiSelectionLimit) cho phép bạn đặt giới hạn số lượng mục có thể được chọn cùng một lúc.

Sau lần đăng đầu tiên, tôi đã nhận ra một vấn đề nhỏ với mã. Việc xóa nhiều lựa chọn sẽ dẫn đến sự kiện ItemSelectionChanged được gọi nhiều lần. Tôi không thể tìm ra cách nào để tránh điều này với thừa kế hiện tại, vì vậy thay vào đó tôi đã sử dụng một giải pháp mà thuộc tính bool SelectionsBeingCleared sẽ đúng trong khi cho đến khi tất cả các mục đã chọn đã được bỏ chọn. Bằng cách này, một cuộc gọi đơn giản đến thuộc tính đó sẽ làm cho nó có thể tránh được việc cập nhật hiệu ứng cho đến khi tất cả các lựa chọn đã được xóa.

public class ListViewMultiSelect : ListView 
{ 
    public const int WM_LBUTTONDOWN = 0x0201; 
    public const int WM_RBUTTONDOWN = 0x0204; 

    private bool _selectionsBeingCleared; 
    /// <summary> 
    /// Returns a boolean indicating if multiple items are being deselected. 
    /// </summary> 
    /// <remarks> This value can be used to avoid updating through events before all deselections have been carried out.</remarks> 
    public bool SelectionsBeingCleared 
    { 
     get 
     { 
      return this._selectionsBeingCleared; 
     } 
     private set 
     { 
      this._selectionsBeingCleared = value; 
     } 
    } 
    private int _multiSelectionLimit; 
    /// <summary> 
    /// The limit to how many items that can be selected simultaneously. Set value to zero for unlimited selections. 
    /// </summary> 
    public int MultiSelectionLimit 
    { 
     get 
     { 
      return this._multiSelectionLimit; 
     } 
     set 
     { 
      this._multiSelectionLimit = Math.Max(value, 0); 
     } 
    } 

    public ListViewMultiSelect() 
    { 
     this.ItemSelectionChanged += this.multiSelectionListView_ItemSelectionChanged; 
    } 

    public ListViewMultiSelect(int selectionsLimit) 
     : this() 
    { 
     this.MultiSelectionLimit = selectionsLimit; 
    } 

    private void multiSelectionListView_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e) 
    { 
     if (e.IsSelected) 
     { 
      if (this.MultiSelectionLimit > 0 && this.SelectedItems.Count > this.MultiSelectionLimit) 
      { 
       this._selectionsBeingCleared = true; 

       List<ListViewItem> itemsToDeselect = this.SelectedItems.Cast<ListViewItem>().Except(new ListViewItem[] { e.Item }).ToList(); 

       foreach (ListViewItem item in itemsToDeselect.Skip(1)) { item.Selected = false; } 

       this._selectionsBeingCleared = false; 

       itemsToDeselect[0].Selected = false; 
      } 

     } 

    } 

    protected override void WndProc(ref Message m) 
    { 
     switch (m.Msg) 
     { 
      case WM_LBUTTONDOWN: 
       if (this.SelectedItems.Count == 0 || !this.MultiSelect) { break; } 

       if (this.MultiSelectionLimit > 0 && this.SelectedItems.Count > this.MultiSelectionLimit) { this.ClearSelections(); } 

       int x = (m.LParam.ToInt32() & 0xffff); 
       int y = (m.LParam.ToInt32() >> 16) & 0xffff; 

       ListViewHitTestInfo hitTest = this.HitTest(x, y); 

       if (hitTest != null && hitTest.Item != null) { hitTest.Item.Selected = !hitTest.Item.Selected; } 

       this.Focus(); 

       return; 
      case WM_RBUTTONDOWN: 
       if (this.SelectedItems.Count > 0) { this.ClearSelections(); } 
       break; 
     } 

     base.WndProc(ref m); 
    } 

    private void ClearSelections() 
    { 
     this._selectionsBeingCleared = true; 

     SelectedListViewItemCollection itemsToDeselect = this.SelectedItems; 

     foreach (ListViewItem item in itemsToDeselect.Cast<ListViewItem>().Skip(1)) { item.Selected = false; } 

     this._selectionsBeingCleared = false; 

     this.SelectedItems.Clear(); 
    } 
} 
0

Chỉ trong trường hợp bất kỳ ai khác đã tìm kiếm và tìm thấy bài viết này, giải pháp được chấp nhận không còn giá trị. (trên thực tế tôi không chắc chắn nó bao giờ là). Để thực hiện những gì bạn muốn (chọn nhiều mà không có phím bổ trợ), chỉ cần đặt loại lựa chọn chế độ xem danh sách thành nhiều, thay vì mở rộng. Nhiều lựa chọn một mục khác nhau khi nhấp vào, và mở rộng yêu cầu phím bổ trợ được nhấn đầu tiên.

+0

Điều này không cung cấp câu trả lời cho câu hỏi. Khi bạn có đủ [danh tiếng] (http://stackoverflow.com/help/whats-reputation), bạn sẽ có thể [nhận xét về bất kỳ bài đăng nào] (http://stackoverflow.com/help/privileges/comment); thay vào đó, [cung cấp câu trả lời không yêu cầu làm rõ từ người hỏi] (http://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can- i-do-thay thế). - [Từ đánh giá] (/ đánh giá/bài đăng chất lượng thấp/13911675) –

+0

Không chắc chắn cách thức nó không cung cấp câu trả lời cho câu hỏi. Câu hỏi đặt ra là "Có cách nào để buộc một điều khiển listview để xử lý tất cả các nhấp chuột như thể chúng đã được thực hiện thông qua phím Control?" và câu trả lời tôi đưa ra là "đặt thuộc tính đa lựa chọn thành nhiều, không được mở rộng". Đó là câu trả lời hợp lệ, chính xác và được kiểm tra đối với câu hỏi ban đầu. Ồ, đó là lần cuối cùng tôi thử và giúp những người khác đi qua một câu hỏi cũ với một giải pháp cũ. – kamikazi