2010-03-30 11 views
9

Tengo una lista de ToggleButtons que se utilizan como ItemTemplate en un ListBox similar a this answer usando el modo MultiSelect del Listbox. Sin embargo, necesito asegurarme de que siempre se seleccione al menos un elemento.¿Cómo puedo evitar que un ToggleButton se mueva sin establecer IsEnabled?

Puedo obtener el comportamiento correcto del ListBox simplemente agregando un elemento de nuevo en la colección SelectedItems de ListBox en el evento ListBox.SelectionChanged pero mi ToggleButton aún se mueve fuera de su estado alternado, así que creo que necesito detenerlo antes en el proceso.

Me gustaría hacerlo sin configurar IsEnabled = "False" en el último botón Seleccionado porque prefiero seguir con el estilo visual Habilitado sin tener que volver a hacer las plantillas de mis botones. ¿Algunas ideas?

Respuesta

28

se puede anular el método OnToggle para evitar alternar el estado, por no llamar a la implementación base:

public class LockableToggleButton : ToggleButton 
{ 
    protected override void OnToggle() 
    { 
     if (!LockToggle) 
     { 
      base.OnToggle(); 
     } 
    } 

    public bool LockToggle 
    { 
     get { return (bool)GetValue(LockToggleProperty); } 
     set { SetValue(LockToggleProperty, value); } 
    } 

    // Using a DependencyProperty as the backing store for LockToggle. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty LockToggleProperty = 
     DependencyProperty.Register("LockToggle", typeof(bool), typeof(LockableToggleButton), new UIPropertyMetadata(false)); 
} 
+0

Gracias. Voy a intentarlo. –

+3

Gran solución. – Ross

1

Ésta es hackey, pero si no desea que el código personalizado siempre se puede utilizar la propiedad " IsHitTestVisible ", cuando no desea que lo deseleccionen, simplemente configure IsHitTestVisible igual a falso. Sin embargo, es posible que puedan tabular el control y alternar utilizando la barra espaciadora.

+0

También puede ser deseable hacer que el sonido * ding * suene cuando un usuario intenta alternarlo mientras está bloqueado. Usar IsHitTestVisible no le permitiría a uno lograr esto. – jpierson

+0

Puede usar 'IsTabStop =" False "' para evitar que el usuario toque el botón. Prefiero esta solución que la aceptada, ya que se puede realizar directamente en XAML, es compatible con MVVM y no requiere ningún código personalizado. Se puede usar un estilo si necesita aplicarlo en varios lugares. –

3

¿Ha intentado utilizar RadioButtons en su lugar? Normalmente no se puede deseleccionar sin seleccionar otro. También puede ser de estilo para parecerse a un ToggleButton:

<RadioButton Style="{StaticResource {x:Type ToggleButton}}"/> 

O, si ya tiene una Style por ello, sólo lo hacen BasedOn="{x:Type ToggleButton}". Tenga en cuenta que el Editor de Visual Studio muestra un error en el primer caso, pero se compila y funciona bien.

1

La respuesta de Thomas funciona bien, pero ni siquiera necesita la propiedad de dependencia adicional. Su botón se actualizará correctamente si tiene la clase heredada de ToggleButton para que pueda anular el método OnToggle y cambie la propiedad IsChecked bound en ViewModel.

Xaml:

<myControls:OneWayFromSourceToTargetToggle x:Name="MyCustomToggleButton" 
              Command="{Binding Path=ToggleDoStuffCommand}" 
              CommandParameter="{Binding RelativeSource={RelativeSource Mode=Self}}" 
              IsChecked="{Binding Path=ToggleIsCheckedConditionVar, 
                   Mode=OneWay}" 
              /> 

Agregado ToggleButton Clase:

public class OneWayFromSourceToTargetToggle : ToggleButton 
{ 
    /// <summary> 
    /// Overrides the OnToggle method, so it does not set the IsChecked Property automatically 
    /// </summary> 
    protected override void OnToggle() 
    { 
     // do nothing 
    } 
} 

Luego, en el modelo de vista acaba de establecer ToggleIsCheckedCondition bool a verdadero o falso. Esta es una buena forma de hacerlo porque estás siguiendo buenas prácticas de MVVM.

modelo de vista:

public bool ToggleIsCheckedCondition 
{ 
    get { return _toggleIsCheckedCondition; } 
    set 
    { 
     if (_toggleIsCheckedCondition != value) 
     { 
     _toggleIsCheckedCondition = value; 
     NotifyPropertyChanged("ToggleIsCheckedCondition"); 
     } 
    } 
} 

public ICommand ToggleDoStuffCommand 
{ 
    get { 
     return _toggleDoStuffCommand ?? 
       (_toggleDoStuffCommand = new RelayCommand(ExecuteToggleDoStuffCommand)); 
     } 
} 

private void ExecuteToggleDoStuffCommand(object param) 
{ 
    var btn = param as ToggleButton; 
    if (btn?.IsChecked == null) 
    { 
     return; 
    } 
    // has not been updated yet at this point 
    ToggleIsCheckedCondition = btn.IsChecked == false; 

    // do stuff 

    } 
} 
Cuestiones relacionadas