2011-02-28 46 views
15

Tôi cần một hộp danh sách chọn lần nhấp đầu tiên và bỏ chọn trên lần nhấp thứ hai, do đó chỉ có 0 hoặc một mục được chọn bất kỳ lúc nào.ListBox với một lựa chọn duy nhất và cũng không được chọn trên nhấp chuột ...?

Chọn/bỏ chọn được triển khai trong hộp danh sách (với SelectionMode = "Single") khi bạn nhấn giữ crtl, nhưng rất tiếc, không người dùng nào của tôi có thể được mong đợi biết điều đó.

Với SelectionMode = "Nhiều" chúng tôi có các chức năng chính xác tôi muốn, ngoại trừ việc bạn có thể chọn nhiều hơn một mục ...

More nền: tôi muốn người dùng đầu tiên chọn cài đặt để đăng nhập vào , sau đó cung cấp thông tin xác thực (và một số lựa chọn khác)

Để đạt được điều này, tôi đã sử dụng hộp danh sách có nội dung mở rộng. Để hỗ trợ việc mở rộng mà tôi có ở phía bên trái của listboxitem đã tạo một hình tam giác trỏ ngay khi chưa được mở rộng, nó sẽ chuyển xuống khi bạn đã chọn mục danh sách. Vì vậy, trước tiên, người dùng sẽ thấy danh sách trên các cài đặt, và sau đó, khi anh ta đã chọn mục mình muốn bằng cách chọn nó, listboxitem sẽ mở rộng đến phần còn lại của thông tin mà anh ta cần để nhập vào. Nó khá đẹp, và hoạt động tốt, nhưng kiểm tra báo cáo rằng họ muốn nhấp chuột thứ hai vào tam giác để bỏ chọn (và do đó thu gọn phần mở rộng). Và tôi phải thừa nhận rằng tôi đã nhấp vào ¤% & mũi tên quá, mong các hành động dẫn đến sự sụp đổ ... :-(

Bất cứ ai có một ý tưởng thế nào điều này có thể đạt được (tốt mà không cần mã sau) ?

Trả lời

11

thử rằng:.

bạn sử dụng một ToggleButton là "Expander" của nội dung chi tiết các "IsChecked" Tài sản của nút bật tắt bạn có thể liên kết với IsSelected tài sản của mục

ở đây mã:

<ListBox SelectionMode="Single"> 
    <ListBox.ItemsSource> 
     <x:Array Type="{x:Type sys:String}"> 
     <sys:String>test1</sys:String> 
     <sys:String>test2</sys:String> 
     <sys:String>test3</sys:String> 
     <sys:String>test4</sys:String> 
     <sys:String>test5</sys:String> 
     <sys:String>test6</sys:String> 
     </x:Array> 
    </ListBox.ItemsSource> 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
     <StackPanel Orientation="Horizontal"> 
      <ToggleButton IsChecked="{Binding 
          RelativeSource={RelativeSource FindAncestor, 
          AncestorType={x:Type ListBoxItem}}, 
          Path=IsSelected}" 
      >btn</ToggleButton> 
     </StackPanel> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

cách hoạt động: Trong hộp danh sách, chỉ có thể chọn một mục. Khi chúng ta chọn một mục mà Toggler được mở rộng gây ra IsChecked của anh ta bị ràng buộc với ListBoxItem.IsSelected (ListBoxItem là một điều khiển được bao quanh nội dung của mỗi Item) của ListBoxItem cha của anh ta. Khi selectionMode là đơn càng sớm càng mục khác được lựa chọn sau đây xảy ra:

  • Bỏ chọn mục thực sự chọn
  • Qua ràng buộc Toggler bị bỏ chọn quá
  • Chọn mục mới
  • sự Các mục mới toggler được kiểm tra thông qua các ràng buộc

và nếu chỉ người chuyển đổi mục thực sự được bỏ chọn, mục này sẽ tự bỏ chọn thông qua ràng buộc ...

+0

Tôi không gặp vấn đề với việc mở rộng lựa chọn, vấn đề là làm cho lis tbox chỉ chọn một mục tại một thời điểm và để bỏ chọn trên lần nhấp thứ hai. –

+0

nhưng nó thực hiện chính xác điều đó. trên togglebuttonclick nó mở rộng và chọn mục. vào lần nhấp thứ hai, nó thu gọn và bỏ chọn mục đó. và có tối đa 1 mục được chọn. trick là liên kết 2 chiều trên thuộc tính IsSelected của ListBoxItem. chỉ cần thử nó – fixagon

+0

Tôi đứng sửa chữa, bạn là đúng, và giải pháp là rực rỡ. Cảm ơn bạn! Tôi phải nói rằng tôi là một chút không chắc chắn để làm thế nào điều này thực sự hoạt động? 1. Nút togglebutton được nhấp -> tb được chọn -> listviewitem được chọn -> bất kỳ listviewitem nào khác không được chọn 2. tb được nhấn lần nữa -> tb được bỏ chọn -> listviewitem không được chọn ... Đây có phải là chính xác không đặt? –

28

Cách thông thường để thực hiện việc này là đặt chế độ SelectionMode thành Multiple và sau đó bỏ chọn tất cả các mục trừ mục mới được chọn trong sự kiện SelectionChanged.

Xem theo liên kết

Dưới đây là một hành vi đính kèm mà thực hiện điều này có thể được sử dụng như thế này

<ListBox local:ListBoxSelectionBehavior.ClickSelection="True" 
     ...> 

ListBoxSelectionBehavior

public static class ListBoxSelectionBehavior 
{ 
    public static readonly DependencyProperty ClickSelectionProperty = 
     DependencyProperty.RegisterAttached("ClickSelection", 
              typeof(bool), 
              typeof(ListBoxSelectionBehavior), 
              new UIPropertyMetadata(false, OnClickSelectionChanged)); 
    public static bool GetClickSelection(DependencyObject obj) 
    { 
     return (bool)obj.GetValue(ClickSelectionProperty); 
    } 
    public static void SetClickSelection(DependencyObject obj, bool value) 
    { 
     obj.SetValue(ClickSelectionProperty, value); 
    } 
    private static void OnClickSelectionChanged(DependencyObject dpo, 
                  DependencyPropertyChangedEventArgs e) 
    { 
     ListBox listBox = dpo as ListBox; 
     if (listBox != null) 
     { 
      if ((bool)e.NewValue == true) 
      { 
       listBox.SelectionMode = SelectionMode.Multiple; 
       listBox.SelectionChanged += OnSelectionChanged; 
      } 
      else 
      { 
       listBox.SelectionChanged -= OnSelectionChanged; 
      } 
     } 
    } 
    static void OnSelectionChanged(object sender, SelectionChangedEventArgs e) 
    { 
     if (e.AddedItems.Count > 0) 
     { 
      ListBox listBox = sender as ListBox; 
      var valid = e.AddedItems[0]; 
      foreach (var item in new ArrayList(listBox.SelectedItems)) 
      { 
       if (item != valid) 
       { 
        listBox.SelectedItems.Remove(item); 
       } 
      } 
     } 
    } 
} 
+1

Tôi thích giải pháp này tốt hơn so với một trong những chấp nhận, vì nó không liên quan đến thủ thuật với các yếu tố giao diện người dùng. –

0

Giải pháp của tôi được thiết lập ListBox SelectionMode để Nhiều, thêm phương pháp forbidSelectionButOne vào sự kiện Click và sau đó cho phép chỉ có một mục được lựa chọn như sau:

Private Sub forbidSelectionButOne(sender As Object, e As MouseButtonEventArgs) 
    Dim lv As ListView = TryCast(sender, ListView) 
    If lv IsNot Nothing Then 
     If lv.SelectedIndex <> getCausesListViewItemIndex(sender, e) Then 
      lv.SelectedIndex = getCausesListViewItemIndex(sender, e) 
      e.Handled = True 
     End If 
     lv.Focus() 
    End If 
End Sub 

Và giúp chức năng để tìm ListViewItem rằng đã được nhấp chuột:

Private Function getCausesListViewItemIndex(ByVal sender As Object, e As RoutedEventArgs) As Integer 
    Dim dep As DependencyObject = TryCast(e.OriginalSource, DependencyObject) 
    Do While dep IsNot Nothing AndAlso Not TypeOf (dep) Is ListViewItem 
     dep = VisualTreeHelper.GetParent(dep) 
    Loop 
    If dep Is Nothing Then 
     Return -1 
    Else 
     Dim lv As ListView = TryCast(sender, ListView) 
     If lv IsNot Nothing Then 
      Dim i As Integer = lv.ItemContainerGenerator.IndexFromContainer(dep) 
      Return i 
     Else 
      Return -1 
     End If 
    End If 
End Function 
Các vấn đề liên quan