2010-03-30 3 views
9

J'ai une liste de ToggleButtons utilisés comme ItemTemplate dans un ListBox similaire à this answer en utilisant le mode MultiSelect de la Listbox. Cependant, je dois m'assurer qu'au moins un élément est toujours sélectionné.Comment puis-je empêcher un ToggleButton de basculer sans définir IsEnabled

Je peux obtenir le bon comportement de la ListBox en ajoutant simplement un élément dans la collection SelectedItems de la ListBox sur l'événement ListBox.SelectionChanged mais mon ToggleButton sort toujours de son état basculé, donc je pense que je dois l'arrêter plus tôt le processus.

Je voudrais le faire sans définir IsEnabled = "False" sur le dernier bouton sélectionné parce que je préfère rester avec le style visuel Enabled sans avoir à refaire mes modèles de boutons. Des idées?

Répondre

28

Vous pouvez remplacer la méthode OnToggle pour éviter de basculer l'état, en ne demandant pas la mise en œuvre de 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

Merci. Je vais essayer. –

+3

Excellente solution. – Ross

1

Ceci est hackey, mais si vous ne le code voulez pas personnalisé vous pouvez toujours utiliser la propriété " IsHitTestVisible ", lorsque vous ne souhaitez pas qu'ils soient décochés, définissez simplement IsHitTestVisible sur false. Cependant, ils peuvent être en mesure d'onglet au contrôle et basculer à l'aide de la barre d'espace.

+0

Il peut aussi être souhaitable de faire entendre le son * ding * lorsqu'un utilisateur essaie de le basculer pendant qu'il est verrouillé. L'utilisation de IsHitTestVisible ne permettrait pas d'y parvenir. – jpierson

+0

Vous pouvez utiliser 'IsTabStop =" False "' pour empêcher l'utilisateur de tabuler sur le bouton. Je préfère cette solution à la réponse acceptée car elle peut être accomplie directement dans le XAML, est conviviale MVVM, et ne nécessite aucun code personnalisé. Un style peut être utilisé si vous devez l'appliquer à plusieurs endroits. –

3

Avez-vous essayé d'utiliser RadioButtons à la place? Il ne peut normalement pas être désélectionné sans en sélectionner un autre. Il peut également être dessiné pour ressembler à un ToggleButton:

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

Ou, si vous avez déjà un Style pour elle, juste faire BasedOn="{x:Type ToggleButton}". Notez que l'éditeur Visual Studio affiche une erreur dans le premier cas, mais il compile et fonctionne correctement.

1

La réponse de Thomas fonctionne très bien, mais vous n'avez même pas besoin de la propriété de dépendance supplémentaire. Votre bouton sera mis à jour correctement si la classe hérite de ToggleButton afin que vous puissiez substituer la méthode OnToggle et que vous modifiez la propriété bound IsChecked sur ViewModel.

Xaml:

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

Ajouté ToggleButton Classe:

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

Ensuite, dans le ViewModel vient de mettre bool ToggleIsCheckedCondition true ou false. C'est une bonne façon de le faire parce que vous suivez de bonnes pratiques MVVM.

ViewModel:

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 

    } 
} 
Questions connexes