2008-09-17 7 views
5

리스트 뷰 컨트롤이 모든 클릭을 컨트롤 키를 통해 처리 한 것처럼 처리하도록하는 방법이 있습니까?리스트 뷰 다중 선택

사용자가 여러 항목을 동시에 선택할 수 있도록하기 위해 컨트롤 키 (항목 선택 및 선택 상태 해제) 기능을 복제해야합니다.

미리 감사드립니다.

답변

4

MultiSelect가 true로 설정된 경우에도 ListView 컨트롤의 표준 동작은 아닙니다. 당신이 당신의 자신의 사용자 지정 컨트롤을 만들고 싶었 경우

다음을 수행해야합니다 :

  1. 리스트 뷰
  2. 에서 컨트롤을 파생 "선택한"이벤트에 핸들러를 추가합니다.
  3. "OnSelected"에서 선택한 항목의 고유 목록을 유지 관리하십시오.
  4. 새로 선택한 항목이 목록에없는 경우 추가하십시오. 그럴 경우 제거하십시오.
  5. 코드에서 목록의 모든 항목을 선택하십시오.

컨트롤 키를 사용하지 않고도 다중 선택이 가능하고 구현하기에 충분히 간단해야합니다!

+0

나는이 선을 따라 일해 왔지만 문제가 더 쉬운지 확인하고보고자 함으로서 문제를 해결하기를 원했습니다. 답변을 주셔서 감사합니다. – Evan

+0

선택한 항목의 목록에 색인이 아닌 "내용"이 저장되어 있는지 확인하십시오. 이 인덱스를 사용하는 것이 더 쉬울지라도 ListBox.ItemsCollection과 목록을 동기화 된 상태로 유지해야한다는 의미입니다. 다행히도 당신의 객체 또는 문자열은이 관계를 유지할만큼 충분히 독특합니다! –

-2

Ctrl + 클릭 동작은 브라우저에서 구현 한 동작이며 실제 .NET 컨트롤과는 거의 관계가 없습니다. 달성하고자하는 결과는 많은 추가 JavaScript로 얻을 수 있습니다. 가장 쉬운 방법은 목록보기를 해킹하려고 시도하는 대신이 방법으로 작동하는 기본 JavaScript 컨트롤을 작성하는 것입니다. 이것이 바람직한 것이겠습니까? 이 경우 나는 그것을 들여다보고 해결책을 가지고 다시 당신에게 돌아갈 수 있습니다.

+0

그는 브라우저와 관련이 없으며 C#과 WinForms를 사용하고 있습니다! –

+0

어쨌든 Javascript는 winforms 환경에서 사용할 수 없습니다. – Evan

0

ListviewItemCollection을 드릴 다운하여 개별 항목의 Selected 속성을 true로 설정할 수 있습니다. 이것은 내가 재현하려는 "다중 선택"기능을 모방 한 것입니다. (위의 주석자가 언급했듯이, lisetview의 MultiSelect 속성을 true로 설정해야합니다.)

2

목록보기에서 Checkboxes을 사용하는 것도 좋습니다. Ctrl + 클릭에 대해 알지 못할 수도있는 일반 사용자에게 다중 선택 개념을 전달하는 것은 분명한 방법입니다. 은 MSDN 페이지에서

:

체크 박스 속성은 Ctrl 키를 사용하지 않고 ListView 컨트롤에서 여러 항목을 선택하는 방법을 제공합니다. 응용 프로그램에 따라 표준 다중 선택 방법 대신 항목을 선택하기 위해 확인란을 사용하면 사용자가 더 쉽게 수행 할 수 있습니다. ListView 컨트롤의 MultiSelect 속성이 false로 설정된 경우에도 확인란을 표시하고 여러 선택 기능을 사용자에게 제공 할 수 있습니다. 이 기능은 여러 항목을 선택하지 않고 사용자가 응용 프로그램 내에서 작업을 수행하기 위해 목록에서 여러 항목을 선택할 수 있도록하려는 경우 유용 할 수 있습니다.

2

여기 WndProc을 사용하여이 문제를 해결하는 데 사용한 완전한 해결책이 있습니다. 기본적으로 마우스를 클릭하면 히트 테스트가 수행됩니다. MutliSelect가 켜져 있으면 항목이 자동으로 켜기/끄기 [.Selected]로 전환되며 다른 목록을 유지하거나 ListView 기능을 사용하는 것을 걱정하지 않아도됩니다.

모든 시나리오에서 이것을 테스트하지는 않았지만, 저에게 효과적이었습니다. 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

위의 Matthew M.에서 제공 한 솔루션을 수정 한 완전한 솔루션입니다.

개선 된 기능과 약간의 추가 기능을 제공합니다.

향상 : - 컨트롤을 왼쪽 클릭하면 컨트롤에 포커스가 있습니다. - 오른쪽 마우스 클릭 동작이 일관성이 있습니다 (단일 선택)

추가 기능 : - 컨트롤에 한 번에 선택할 수있는 항목의 수를 제한 할 수있는 속성 (MultiSelectionLimit)이 있습니다.

처음 게시 한 후 코드에 사소한 문제점이 있음을 알게되었습니다. 여러 선택을 지우면 ItemSelectionChanged 이벤트가 여러 번 호출됩니다. 현재 상속으로이 문제를 피할 수있는 방법이 없었기 때문에 선택한 모든 항목이 선택 취소 될 때까지 bool 속성 SelectionsBeingCleared가 true가되는 솔루션을 채택했습니다. 이렇게하면 해당 속성을 간단하게 호출하면 여러 선택 항목 모두가 지워질 때까지 효과 업데이트를 피할 수 있습니다.

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

다른 사람이이 기사를 검색하여 발견 한 경우, 허용 된 솔루션은 더 이상 유효하지 않습니다. (실제로 나는 그것이 이제까지 있었다라고 확신하지 않는다). 원하는 것을 수행하려면 (수정 자 키없이 다중 선택) 간단히 목록보기 선택 유형을 확장하지 않고 다중으로 설정하십시오. 다중은 클릭 할 때마다 하나의 항목을 선택하고, 확장 키를 먼저 눌러야합니다.

+0

이 질문에 대한 답을 제공하지 않습니다. 충분한 [평판] (http://stackoverflow.com/help/whats-reputation)이 있으면 [모든 게시물에 댓글을 달 수 있습니다] (http://stackoverflow.com/help/privileges/comment); 대신에 [질문자의 설명이 필요없는 답변을 제공하십시오] (http://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can- i-do- 대신). - [검토 중] (검토 중/리뷰/저품목/13911675) –

+0

질문에 대한 답변을 제공하지 않는 방법을 잘 모릅니다. 질문은 "목록보기 컨트롤이 모든 클릭을 Ctrl 키를 통해 처리 된 것처럼 취급하도록 할 수있는 방법이 있습니까?" 내가 준 응답은 "다중 선택 속성을 확장되지 않은 다중 값으로 설정"했습니다. 원래의 질문에 대한 정확하고 올바른 답변입니다. 오, 그게 내가 맹세코 오래된 해결책을 통해 다른 사람들을 도우려는 마지막 시도입니다. – kamikazi