none
WPF - RadioButton - automatically invoke a command

    Question

  • I'm currently using MVVM Light.

    I have a RadioButton that is checked by default, at the same time it is bound to a Command. However, the command doesn't automatically get invoked.

    <RadioButton GroupName="GroupA" Content="Default" Command="{Binding DefaultCommand}" IsChecked="True" />
    <RadioButton GroupName="GroupA" Content="Others" Command="{Binding OthersCommand}"/>
    
    Is there a property that will automatically invoke the Command when Checked is already set in xaml?

    Wednesday, October 06, 2010 2:30 AM

Answers

  • After playing around with this a bit more, and a ton of googling, this is what I came up with that is xaml only... it's a bit bulky for my tastes. if you have a better solution, pls tell me.

    <RadioButton GroupName="GroupA" Content="Default Directory">
     <RadioButton.Triggers>
      <EventTrigger RoutedEvent="ToggleButton.Loaded">
       <BeginStoryboard>
         <Storyboard>
         <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsChecked" >
          <DiscreteBooleanKeyFrame Value="True"/>
         </BooleanAnimationUsingKeyFrames>
        </Storyboard>
       </BeginStoryboard>
      </EventTrigger>
     </RadioButton.Triggers>
     <i:Interaction.Triggers>
      <i:EventTrigger EventName="Checked">
       <cmd:EventToCommand Command="{Binding DefaultCommand}"/>
      </i:EventTrigger>
     </i:Interaction.Triggers>
    </RadioButton>
    

    Wednesday, October 06, 2010 3:36 AM
  • Sound like an attached property would do the trick. This is code for a Command to execute on ListViewDoubleClick... You could adapt this for a RadioButton click.

    XAML USAGE

    <controls:ExListView x:Name="list" Grid.Row="2" Initialized="list_Initialized"
      AlternationCount="2" 
      ItemsSource="{Binding PaginatedPuzzles}" 
      ItemContainerStyle="{StaticResource PuzzleItemStyle}"
      <strong>local:SelectorDoubleClickCommandBehavior.HandleDoubleClick="True"
      local:SelectorDoubleClickCommandBehavior.TheCommandToRun="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.EditPuzzleCommand}"      
      local:SelectorDoubleClickCommandBehavior.CommandParameter="Test"</strong>
      >
    

    C#

    /// <summary>
    /// Selector MouseDoubleClick calling ViewModel ICommand 
    /// </summary>
    public static class SelectorDoubleClickCommandBehavior
    {
      #region Attached DPs
    
      #region CommandParameter
    
      
      // Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
      public static readonly DependencyProperty 
        CommandParameterProperty =
        DependencyProperty.RegisterAttached("CommandParameter", typeof(object), typeof(SelectorDoubleClickCommandBehavior), new UIPropertyMetadata(null));
    
      /// <summary>
      /// Gets the HandleDoubleClick property. 
      /// </summary>
      public static object GetCommandParameter(DependencyObject d)
      {
        return (bool)d.GetValue(CommandParameterProperty);
      }
    
      /// <summary>
      /// Sets the HandleDoubleClick property. 
      /// </summary>
      public static void SetCommandParameter(DependencyObject d,
        object value)
      {
        d.SetValue(CommandParameterProperty, value);
      }
      
      #endregion
    
      #region HandleDoubleClick
    
      /// <summary>
      /// HandleDoubleClick Attached Dependency Property
      /// </summary>
      public static readonly DependencyProperty
        HandleDoubleClickProperty =
        DependencyProperty.RegisterAttached(
        "HandleDoubleClick",
        typeof(bool),
        typeof(SelectorDoubleClickCommandBehavior),
          new FrameworkPropertyMetadata(false,
            new PropertyChangedCallback(
              OnHandleDoubleClickChanged)));
    
      /// <summary>
      /// Gets the HandleDoubleClick property. 
      /// </summary>
      public static bool GetHandleDoubleClick(DependencyObject d)
      {
        return (bool)d.GetValue(HandleDoubleClickProperty);
      }
    
      /// <summary>
      /// Sets the HandleDoubleClick property. 
      /// </summary>
      public static void SetHandleDoubleClick(DependencyObject d,
        bool value)
      {
        d.SetValue(HandleDoubleClickProperty, value);
      }
    
      /// <summary>
      /// Hooks up a weak event against the source Selectors 
      /// MouseDoubleClick if the Selector has asked for 
      /// the HandleDoubleClick to be handled
      /// 
      /// If the source Selector has expressed an interest 
      /// in not having its MouseDoubleClick handled 
      /// the internal reference
      /// </summary>
      private static void OnHandleDoubleClickChanged(
        DependencyObject d,
        DependencyPropertyChangedEventArgs e)
      {
        Selector selector = d as Selector;
    
        if (selector != null)
        {
          if ((bool)e.NewValue)
          {
            selector.MouseDoubleClick -= OnMouseDoubleClick;
            selector.MouseDoubleClick += OnMouseDoubleClick;
            selector.KeyDown -= selector_KeyDown;
            selector.KeyDown += selector_KeyDown;
          }
        }
      }
    
      #endregion
    
      #region TheCommandToRun
    
      /// <summary>
      /// TheCommandToRun : The actual ICommand to run
      /// </summary>
      public static readonly DependencyProperty TheCommandToRunProperty =
        DependencyProperty.RegisterAttached(
          "TheCommandToRun",
          typeof(ICommand),
          typeof(SelectorDoubleClickCommandBehavior),
          new FrameworkPropertyMetadata((ICommand)null));
    
      /// <summary>
      /// Gets the TheCommandToRun property. 
      /// </summary>
      public static ICommand GetTheCommandToRun(DependencyObject d)
      {
        return (ICommand)d.GetValue(TheCommandToRunProperty);
      }
    
      /// <summary>
      /// Sets the TheCommandToRun property. 
      /// </summary>
      public static void SetTheCommandToRun(DependencyObject d,
        ICommand value)
      {
        d.SetValue(TheCommandToRunProperty, value);
      }
      #endregion
      #endregion
    
      #region Private Methods
    
      /// <summary>
      /// Handle Selector.MouseDoubleClick but will 
      /// only fire the associated ViewModel command 
      /// if the MouseDoubleClick occurred over an actual
      /// ItemsControl item. This is nessecary as if we 
      /// are using a ListView we may have clicked the 
      /// headers which are not items, so do not want the
      /// associated ViewModel command to be run
      /// </summary>
      /// 
      static void selector_KeyDown(object sender, KeyEventArgs e)
      {
        if (e.Key == Key.Enter)
        {
          RunCommand(sender, e.OriginalSource);
        }
      }
    
      static void RunCommand(object sender, object originalSource)
      {//Get the ItemsControl and then get the item, and 
        //check there is an actual item, as if we are using 
        //a ListView we may have clicked the
        //headers which are not items
        ItemsControl listView = sender as ItemsControl;
        DependencyObject originalSender =
          originalSource as DependencyObject;
        if (listView == null || originalSender == null) return;
    
        DependencyObject container =
          ItemsControl.ContainerFromElement(sender as ItemsControl, originalSource as DependencyObject);
    
        if (container == null ||
          container == DependencyProperty.UnsetValue) return;
    
        // found a container, now find the item.
        object activatedItem =
          listView.ItemContainerGenerator.
            ItemFromContainer(container);
    
        if (activatedItem != null)
        {
          ICommand command =
            (ICommand)(sender as DependencyObject).
            GetValue(TheCommandToRunProperty);
    
          if (command != null)
          {
            if (command.CanExecute(activatedItem))
              command.Execute(activatedItem);
          }
        }
      }
    
      private static void OnMouseDoubleClick(object sender, MouseButtonEventArgs e)
      {
        RunCommand(sender, e.OriginalSource);
      }
      #endregion
    }
    

    Warm regards,

    Matt

    Wednesday, October 06, 2010 4:52 AM

All replies

  • After playing around with this a bit more, and a ton of googling, this is what I came up with that is xaml only... it's a bit bulky for my tastes. if you have a better solution, pls tell me.

    <RadioButton GroupName="GroupA" Content="Default Directory">
     <RadioButton.Triggers>
      <EventTrigger RoutedEvent="ToggleButton.Loaded">
       <BeginStoryboard>
         <Storyboard>
         <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsChecked" >
          <DiscreteBooleanKeyFrame Value="True"/>
         </BooleanAnimationUsingKeyFrames>
        </Storyboard>
       </BeginStoryboard>
      </EventTrigger>
     </RadioButton.Triggers>
     <i:Interaction.Triggers>
      <i:EventTrigger EventName="Checked">
       <cmd:EventToCommand Command="{Binding DefaultCommand}"/>
      </i:EventTrigger>
     </i:Interaction.Triggers>
    </RadioButton>
    

    Wednesday, October 06, 2010 3:36 AM
  • Why not bind the IsChecked property to a ViewModel property and call DefaultCommand/OthersCommand when the value changes?
    Wednesday, October 06, 2010 3:41 AM
  • Why not bind the IsChecked property to a ViewModel property and call DefaultCommand/OthersCommand when the value changes?
    Because I don't want my ViewModel to be "aware" of the controls on the UI. If in case there is a change in specs (like switching from radio buttons to combo boxes or listboxes), the ViewModel doesn't need to be changed.
    Wednesday, October 06, 2010 3:59 AM
  • Sound like an attached property would do the trick. This is code for a Command to execute on ListViewDoubleClick... You could adapt this for a RadioButton click.

    XAML USAGE

    <controls:ExListView x:Name="list" Grid.Row="2" Initialized="list_Initialized"
      AlternationCount="2" 
      ItemsSource="{Binding PaginatedPuzzles}" 
      ItemContainerStyle="{StaticResource PuzzleItemStyle}"
      <strong>local:SelectorDoubleClickCommandBehavior.HandleDoubleClick="True"
      local:SelectorDoubleClickCommandBehavior.TheCommandToRun="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.EditPuzzleCommand}"      
      local:SelectorDoubleClickCommandBehavior.CommandParameter="Test"</strong>
      >
    

    C#

    /// <summary>
    /// Selector MouseDoubleClick calling ViewModel ICommand 
    /// </summary>
    public static class SelectorDoubleClickCommandBehavior
    {
      #region Attached DPs
    
      #region CommandParameter
    
      
      // Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
      public static readonly DependencyProperty 
        CommandParameterProperty =
        DependencyProperty.RegisterAttached("CommandParameter", typeof(object), typeof(SelectorDoubleClickCommandBehavior), new UIPropertyMetadata(null));
    
      /// <summary>
      /// Gets the HandleDoubleClick property. 
      /// </summary>
      public static object GetCommandParameter(DependencyObject d)
      {
        return (bool)d.GetValue(CommandParameterProperty);
      }
    
      /// <summary>
      /// Sets the HandleDoubleClick property. 
      /// </summary>
      public static void SetCommandParameter(DependencyObject d,
        object value)
      {
        d.SetValue(CommandParameterProperty, value);
      }
      
      #endregion
    
      #region HandleDoubleClick
    
      /// <summary>
      /// HandleDoubleClick Attached Dependency Property
      /// </summary>
      public static readonly DependencyProperty
        HandleDoubleClickProperty =
        DependencyProperty.RegisterAttached(
        "HandleDoubleClick",
        typeof(bool),
        typeof(SelectorDoubleClickCommandBehavior),
          new FrameworkPropertyMetadata(false,
            new PropertyChangedCallback(
              OnHandleDoubleClickChanged)));
    
      /// <summary>
      /// Gets the HandleDoubleClick property. 
      /// </summary>
      public static bool GetHandleDoubleClick(DependencyObject d)
      {
        return (bool)d.GetValue(HandleDoubleClickProperty);
      }
    
      /// <summary>
      /// Sets the HandleDoubleClick property. 
      /// </summary>
      public static void SetHandleDoubleClick(DependencyObject d,
        bool value)
      {
        d.SetValue(HandleDoubleClickProperty, value);
      }
    
      /// <summary>
      /// Hooks up a weak event against the source Selectors 
      /// MouseDoubleClick if the Selector has asked for 
      /// the HandleDoubleClick to be handled
      /// 
      /// If the source Selector has expressed an interest 
      /// in not having its MouseDoubleClick handled 
      /// the internal reference
      /// </summary>
      private static void OnHandleDoubleClickChanged(
        DependencyObject d,
        DependencyPropertyChangedEventArgs e)
      {
        Selector selector = d as Selector;
    
        if (selector != null)
        {
          if ((bool)e.NewValue)
          {
            selector.MouseDoubleClick -= OnMouseDoubleClick;
            selector.MouseDoubleClick += OnMouseDoubleClick;
            selector.KeyDown -= selector_KeyDown;
            selector.KeyDown += selector_KeyDown;
          }
        }
      }
    
      #endregion
    
      #region TheCommandToRun
    
      /// <summary>
      /// TheCommandToRun : The actual ICommand to run
      /// </summary>
      public static readonly DependencyProperty TheCommandToRunProperty =
        DependencyProperty.RegisterAttached(
          "TheCommandToRun",
          typeof(ICommand),
          typeof(SelectorDoubleClickCommandBehavior),
          new FrameworkPropertyMetadata((ICommand)null));
    
      /// <summary>
      /// Gets the TheCommandToRun property. 
      /// </summary>
      public static ICommand GetTheCommandToRun(DependencyObject d)
      {
        return (ICommand)d.GetValue(TheCommandToRunProperty);
      }
    
      /// <summary>
      /// Sets the TheCommandToRun property. 
      /// </summary>
      public static void SetTheCommandToRun(DependencyObject d,
        ICommand value)
      {
        d.SetValue(TheCommandToRunProperty, value);
      }
      #endregion
      #endregion
    
      #region Private Methods
    
      /// <summary>
      /// Handle Selector.MouseDoubleClick but will 
      /// only fire the associated ViewModel command 
      /// if the MouseDoubleClick occurred over an actual
      /// ItemsControl item. This is nessecary as if we 
      /// are using a ListView we may have clicked the 
      /// headers which are not items, so do not want the
      /// associated ViewModel command to be run
      /// </summary>
      /// 
      static void selector_KeyDown(object sender, KeyEventArgs e)
      {
        if (e.Key == Key.Enter)
        {
          RunCommand(sender, e.OriginalSource);
        }
      }
    
      static void RunCommand(object sender, object originalSource)
      {//Get the ItemsControl and then get the item, and 
        //check there is an actual item, as if we are using 
        //a ListView we may have clicked the
        //headers which are not items
        ItemsControl listView = sender as ItemsControl;
        DependencyObject originalSender =
          originalSource as DependencyObject;
        if (listView == null || originalSender == null) return;
    
        DependencyObject container =
          ItemsControl.ContainerFromElement(sender as ItemsControl, originalSource as DependencyObject);
    
        if (container == null ||
          container == DependencyProperty.UnsetValue) return;
    
        // found a container, now find the item.
        object activatedItem =
          listView.ItemContainerGenerator.
            ItemFromContainer(container);
    
        if (activatedItem != null)
        {
          ICommand command =
            (ICommand)(sender as DependencyObject).
            GetValue(TheCommandToRunProperty);
    
          if (command != null)
          {
            if (command.CanExecute(activatedItem))
              command.Execute(activatedItem);
          }
        }
      }
    
      private static void OnMouseDoubleClick(object sender, MouseButtonEventArgs e)
      {
        RunCommand(sender, e.OriginalSource);
      }
      #endregion
    }
    

    Warm regards,

    Matt

    Wednesday, October 06, 2010 4:52 AM