Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I prevent a ToggleButton from being Toggled without setting IsEnabled

I have a list of ToggleButtons being used as the ItemTemplate in a ListBox similar to this answer using the MultiSelect mode of the Listbox. However I need to make sure at least one item is always selected.

I can get the proper behavior from the ListBox by just adding an item back into the ListBox's SelectedItems collection on the ListBox.SelectionChanged event but my ToggleButton still moves out of its toggled state so I think I need to stop it earlier in the process.

I would like to do it without setting IsEnabled="False" on the last button Selected because I'd prefer to stay with the Enabled visual style without having to redo my button templates. Any ideas?

like image 664
Bryan Anderson Avatar asked Mar 30 '10 21:03

Bryan Anderson


2 Answers

You can override the OnToggle method to prevent toggling the state, by not calling the base implementation :

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));
}
like image 186
Thomas Levesque Avatar answered Oct 19 '22 07:10

Thomas Levesque


Thomas's answer works fine, but you don't even need the extra dependency property. Your button will update correctly if you have the class inherit from ToggleButton so you can override the OnToggle method, and you change the IsChecked bound property on the ViewModel.

Xaml:

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

Added ToggleButton Class:

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

Then in the ViewModel just set bool ToggleIsCheckedCondition to true or false. This is a nice way to do it because you are following good MVVM practices.

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

   }
}
like image 42
Jim Kniest Avatar answered Oct 19 '22 05:10

Jim Kniest