How do I attach commands to the checking and unche

2020-07-09 03:23发布

In my ViewModel I have two commands:

ICommand ExecuteMeOnCheck { get; }
ICommand ExecuteMeOnUncheck { get; }

I wish to attach these commands to a CheckBox and have one of them execute when it is checked and the other execute when it is unchecked. What's the best way to achieve this without cluttering the View with code-behind?

5条回答
Lonely孤独者°
2楼-- · 2020-07-09 03:32

The simplest way I have found to do this involves borrowing a bunch of code. I also think that you do not want to expose two events for the state change. Make your command CheckedChangedCommand instead of Checked and Unchecked. Bind the CheckBox.IsChecked dependency property to a property on your ViewModelClass. That way when your command gets executed, you just check that value in your ViewModel.

First, start using DelegateCommand from the WPF ViewModel toolkit. It isn't clear from your post whether you are or not.

Next, download the .zip archive from the Downloads tab at this link.

The archive has a class called EventBehaviourFactory that makes setting the DependencyProperty easier. Back on the Home tab at the above link, Samuel tells you how to wire up the Command in your XAML to the ViewModel. Here it is:

<TextBox ff:TextBoxBehaviour.TextChangedCommand="{Binding TextChanged}"/>

I used the three classes (DelegateCommand, EventBehaviourFactory and TextBoxBehaviour) line for line and had the TextChanged event working in my project in about five minutes.

The pattern for extending it to other controls like you need to do is easy too. I managed to wire up ListBox.SelectionChanged the same way. Create a new ControlBehaviour class and substitute "Control" for "TextBox" in all the instances and attach the DependencyProperty to the new event.

It is a beautiful thing when your code behind is empty!

查看更多
爷的心禁止访问
3楼-- · 2020-07-09 03:39

I did this with a Trigger on "IsChecked" that sets the Command.

e.g.

<Style x:Key="checkBoxStyle" TargetType="{x:Type CheckBox}">
      <Style.Triggers>
        <Trigger Property="IsChecked" Value="True">
          <Setter Property="Command"
                  Value="{Binding AddThingCommand}" />
        </Trigger>
        <Trigger Property="IsChecked" Value="False">
          <Setter Property="Command"
                  Value="{Binding RemoveThingCommand}" />
        </Trigger>
      </Style.Triggers>
    </Style>
查看更多
放我归山
4楼-- · 2020-07-09 03:43

This relates to Eddie's answer.

I played around with it a bit and it is great I also created a little template for creating new commands. I'm using it with Sharpdevelop as a code snippet. Just paste the following into your code (e.g.via a snippet):

#region $nameCommand

    public static readonly DependencyProperty $nameCommand =
        EventBehaviourFactory.CreateCommandExecutionEventBehaviour(
            Control.$nameEvent, "$nameCommand", typeof (ControlBehavior));

    public static void Set$nameCommand(DependencyObject o, ICommand value)
    {
        o.SetValue($nameCommand, value);
    }

    public static ICommand Get$nameCommand(DependencyObject o)
    {
        return o.GetValue($nameCommand) as ICommand;
    }

    #endregion 

Then do a search replace for "$name" with the name of the Event/Command e.g. MouseEnter

ote, it is importand, that you make sure you pick the right classname for the owner (in my case ControlBehavior.

I am attaching a class I created for common Mouse commands in the hopes that other people share as well and we don't just implement the same thing over and over, where we could have saved a lot of time by sharing. Here my complete ControlBehavior class (I did only implement the events that I needed so far):

public static class ControlBehavior
    {
        #region MouseEnterCommand

        public static readonly DependencyProperty MouseEnterCommand =
            EventBehaviourFactory.CreateCommandExecutionEventBehaviour(
                Control.MouseEnterEvent, "MouseEnterCommand", typeof (ControlBehavior));

        public static void SetMouseEnterCommand(DependencyObject o, ICommand value)
        {
            o.SetValue(MouseEnterCommand, value);
        }

        public static ICommand GetMouseEnterCommand(DependencyObject o)
        {
            return o.GetValue(MouseEnterCommand) as ICommand;
        }

        #endregion

        #region MouseLeaveCommand

        public static readonly DependencyProperty MouseLeaveCommand =
            EventBehaviourFactory.CreateCommandExecutionEventBehaviour(
                Control.MouseLeaveEvent, "MouseLeaveCommand", typeof (ControlBehavior));

        public static void SetMouseLeaveCommand(DependencyObject o, ICommand value)
        {
            o.SetValue(MouseLeaveCommand, value);
        }

        public static ICommand GetMouseLeaveCommand(DependencyObject o)
        {
            return o.GetValue(MouseLeaveCommand) as ICommand;
        }

        #endregion


        #region MouseDoubleClickCommand

        public static readonly DependencyProperty MouseDoubleClickCommand = 
            EventBehaviourFactory.CreateCommandExecutionEventBehaviour(
            Control.MouseDoubleClickEvent, "MouseDoubleClickCommand", typeof (ControlBehavior));

        public static void SetMouseDoubleClickCommand(Control o, ICommand command)
        {
            o.SetValue(MouseDoubleClickCommand, command);
        }

        public static void GetMouseDoubleClickCommand(Control o)
        {
            o.GetValue(MouseDoubleClickCommand);
        }

        #endregion

        #region MouseLeftButtonDownCommand

        public static readonly DependencyProperty MouseLeftButtonDownCommand =
            EventBehaviourFactory.CreateCommandExecutionEventBehaviour(
                Control.MouseLeftButtonDownEvent, "MouseLeftButtonDownCommand", typeof (ControlBehavior));

        public static void SetMouseLeftButtonDownCommand(DependencyObject o, ICommand value)
        {
            o.SetValue(MouseLeftButtonDownCommand, value);
        }

        public static ICommand GetMouseLeftButtonDownCommand(DependencyObject o)
        {
            return o.GetValue(MouseLeftButtonDownCommand) as ICommand;
        }

        #endregion

    }

By using above template it took me only a few seconds for each command.

查看更多
干净又极端
5楼-- · 2020-07-09 03:47

Another solution, similar to Eddie's : the Attached Command Behaviours by Marlon Grech

You could also use the CheckBox's Command property to attach only one command, in which you test whether the checkbox is checked...

Or you could bind the IsChecked property to a property of your ViewModel, and react to the change in the setter of that property.

查看更多
▲ chillily
6楼-- · 2020-07-09 03:58

well you can inherit from the checkBox control, add the two commands as properties (Dependency Propertiess) and then override the OnChecked and OnUnchecked methods and trigger each command in the appropriate place

查看更多
登录 后发表回答