2011-02-28 13 views
15

Necesito un cuadro de lista que selecciona al hacer clic por primera vez y anular la selección con un segundo clic, de modo que solo se selecciona cero o un elemento en cualquier momento.ListBox con selección simple y también deseleccionar al hacer clic ...?

La selección/deselección se implementa en el cuadro de lista (con SelectionMode = "Single") cuando se mantiene presionado crtl, pero, desafortunadamente, ninguno de mis usuarios puede saberlo.

Con SelectionMode = "múltiple" tenemos la funcionalidad exacta que quiero, excepto que se puede seleccionar más de un elemento ...

Más de fondo: Quiero que el usuario elija en primer lugar, que la instalación para iniciar sesión en , luego para dar credenciales (y algunas otras opciones)

Para lograr esto, he usado un listbox con contenido en expansión. Para ayudar a la expansión que tengo en el lado izquierdo de la lista, formé un triángulo que apunta hacia la derecha cuando está sin expandir, que gira para señalar hacia abajo cuando ha seleccionado el elemento de la lista.

Entonces, primero el usuario ve la lista sobre las instalaciones, y luego, cuando ha elegido el elemento que desea seleccionándolo, el listboxitem se expande al resto de la información que necesita ingresar. Es bastante bueno, y funciona bien, pero los informes de prueba que quieren un segundo clic en el triángulo para deseleccionar (y así colapsar la sección expandida). Y debo admitir que he hecho clic en el ¤% & flecha también, esperando la acción de dar lugar a un colapso ... :-(

Cualquier persona tiene una idea de cómo esto se puede lograr (preferiblemente sin código detrás) ?

Respuesta

11

tratar de que:.

se utiliza un ToggleButton como el "expansor" del contenido detallado el "IsChecked" propiedad del botón de alternancia, se puede unir a la propiedad IsSelected del tema

aquí el código:

<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> 

como funciona: En el cuadro de lista sólo se puede seleccionar un elemento. A medida que seleccionamos un elemento, Toggler se expande porque su IsChecked está vinculado a ListBoxItem.IsSelected (ListBoxItem es un control que se ajusta al contenido de cada elemento) de su elemento principal ListBoxItem. A medida que el SelectionMode es solo tan pronto como otro elemento es seleccionado los siguientes casos:

  • Deseleccionar el elemento que tiene seleccionado
  • A través de la unión del Alternador consigue sin marcar demasiado
  • Seleccione el nuevo elemento
  • la El nuevo toggler de objetos se verifica a través de su encuadernación

y si solo se desactiva el elemento seleccionado, el elemento se anula automáticamente a través del vinculante ...

+0

No tengo un problema con la expansión-en-seleccionar, el problema es hacer la lis tbox selecciona solo un elemento a la vez, y para anular la selección con un segundo clic. –

+0

pero hace exactamente eso. en togglebuttonclick expande y selecciona el elemento. al segundo clic, colapsa y deselecciona el elemento. y hay un máximo de 1 elemento seleccionado. el truco es el enlace bidireccional en la propiedad IsSelected del ListBoxItem. solo inténtalo – fixagon

+0

Me corrigen, tienes razón, y la solución es brillante. ¡Gracias! Debo decir que no estoy seguro de cómo funciona esto en realidad. 1. Se hace clic en togglebutton -> se marca tb -> se selecciona el elemento de vista de lista -> se deselecciona cualquier otra lista de vista 2. se vuelve a hacer clic en tb -> la tb se desmarca -> el elemento de lista de lista no está seleccionado ... ¿Es esto correcto? ¿poner? –

28

La forma más común de hacerlo es establecer el modo SelectionMode en Multiple y luego anular la selección de todos los elementos, excepto el recién seleccionado en el evento SelectionChanged.

Véase el seguimiento vincula

Aquí es un comportamiento adjunto que hace esto que se puede utilizar como esto

<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

Me gusta más esta solución que la aceptada, ya que no implica trucos con los elementos de la interfaz de usuario. –

0

Mi solución se ajusta SelectionMode ListBox múltiple, añadir método forbidSelectionButOne el evento Click y después de que permiten sólo un elemento seleccionado de la siguiente manera:

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 

Y ayudar a la función de encontrar ListViewItem que se hizo clic con el mouse:

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 
Cuestiones relacionadas