在复选框被选中或取消选中时执行命令

54

我在窗口上有一个复选框控件。我想执行一个命令,调用相关视图模型中的方法。我还需要复选框的值。我无法找到一种将命令与复选框关联的方法。 有人做过这个吗?


请看这个链接:https://dev59.com/q0fSa4cB1Zd3GeqPA-RR - Kishore Kumar
6个回答

96
<CheckBox Content="CheckBox"
          Command="{Binding YourCommand}"
          CommandParameter="{Binding IsChecked, RelativeSource={RelativeSource Self}}" />

10
使用RelativeSource.Self将CommandParameter绑定到CheckBox的值。 - Marat Khasanov
30
使用 CommandParameter="{Binding IsChecked, RelativeSource={RelativeSource Self}, Mode=OneWay} 将 CommandParameter 绑定到 CheckBox 的值。 - Wallace Kelly
1
我假设该命令必须实现ICommand接口?这对我有效(我没有尝试其他任何东西)。 - Stephen Hosking
@Wally 在你的评论中,你忘记了结尾的双引号 :) - Vijay Chavda
1
@MaratKhasanov和我需要将对象转换为复选框类型以获取Checked的值?或者将绑定设置为Self会给我Checked的值? - John Demetriou
显示剩余4条评论

32
如果您使用MVVM,可以像这样使用事件触发器:
<CheckBox IsChecked="{Binding ServiceOrderItemTask.IsCompleted, Mode=TwoWay}" Content="{Binding ServiceOption.Name}">

    <i:Interaction.Triggers>
          <i:EventTrigger EventName="Checked">
                 <i:InvokeCommandAction Command="{Binding DataContext.IsCompletedCheckedCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type t:RadGridView}}}" CommandParameter="{Binding}"/>
           </i:EventTrigger>

           <i:EventTrigger EventName="Unchecked">
                 <i:InvokeCommandAction Command="{Binding DataContext.IsCompletedUncheckedCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type t:RadGridView}}}" CommandParameter="{Binding}"/>
           </i:EventTrigger>
    </i:Interaction.Triggers>


4
优秀,但是为了使用它,你需要在你的 XAML 文件中添加以下命名空间: xmlns:t="http://schemas.telerik.com/2008/xaml/presentation" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" - jo_dman
2
那在视图模型中如何实现呢? - gts13
@gts13 在虚拟机中,您有两个命令'IsCompletedCheckedCommand'和'IsCompletedUncheckedCommand',它们指向相关的方法。 - mcalex
这种方法需要 Microsoft.Xaml.Behaviors.Wpf (.NET Framework 4.5,VS2019+)。 - AntonK

15
这将按照您的要求正常工作-
<CheckBox CommandParameter="{Binding}"
          Command="{Binding DataContext.YourCommand,
          RelativeSource={RelativeSource FindAncestor,
                           AncestorType={x:Type UserControl}}}"
          Content="{Binding Path=Name}">

不错的技巧!即使这样的 CheckBox 具有到模型的 IsChecked 绑定,它也可以工作,因此您可以跟踪模型更改而无需挂钩 INotifyPropertyChanged,当您在集合中有很多复选框时非常方便。 - AntonK

5
  • System.Windows.Interactivity添加到项目的引用中。
  • 在你的XAML命名空间中添加 xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
<CheckBox IsChecked="{Binding SomeBoolProperty, Mode=OneWay}" Content="Check Meee!">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Checked">
            <i:InvokeCommandAction Command="{Binding MyOnCheckedCommand}"/>
        </i:EventTrigger>
        <i:EventTrigger EventName="Unchecked">
            <i:InvokeCommandAction Command="{Binding MyOnUncheckedCommand}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</CheckBox>

我在ViewModel上实现INotifyPropertyChanged如下:

public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));

我的 ViewModel 的 SomeBoolProperty 现在看起来像这样:

private bool _SomeBoolProperty = false;
public bool SomeBoolProperty { 
    get => _SomeBoolProperty;
    set { 
        _SomeBoolProperty = value; 
        OnPropertyChanged(nameof(SomeBoolProperty)); 
    } 
}

我使用RelayCommand作为命令实现,从这里获得:https://dev59.com/dGEh5IYBdhLWcg3wjEDn#22286816

我的ViewModel上的命令看起来像这样:

public ICommand MyOnCheckedCommand { get; } = new RelayCommand(o => {
    // Do something here.
    SomeBoolProperty = true;
});
public ICommand MyOnUncheckedCommand { get; } = new RelayCommand(o => {
    // Do something else here.
    SomeBoolProperty = false;
});

我遇到这个问题是因为想要找到一种方法重用我已经在ViewModel中拥有的两个命令。其中一个在选中时调用,另一个在取消选中时调用。我还在一些按钮上使用它们,所以不想添加额外的参数化命令。人们在这里问有关ViewModel实现的问题,因此添加了这个答案以补充Igor_S的答案。希望有所帮助。


0

我来晚了... 我使用了Rohit Vats的答案,然后写出了这段代码。

这个例子是一个可工作的代码片段,它只是为了帮助理解每个方面。它是一个可以是活动或非活动状态的图钉,并且它使用了DelegateCommand。你也可以使用RelayCommand或任何其他类似的类来完成同样的工作。

命令:

using System.Windows.Input;

namespace HQ.Wpf.Util.Command
{
    public class StandardCommand
    {
        public static RoutedUICommand PinPropertyGrid = new RoutedUICommand("Pin property grid", "PinPropertyGrid", typeof(StandardCommand));

Xaml:

                            <CheckBox HorizontalAlignment="Right" 
                                      VerticalAlignment="Top"
                                      Margin="2,0,3,0" 
                                      Command="{Binding CommandPinPropertyGrid}"
                                      CommandParameter="{Binding IsChecked, RelativeSource={RelativeSource Self}}">
                                <CheckBox.Template>
                                    <ControlTemplate TargetType="{x:Type CheckBox}">
                                        <Grid>
                                            <Image x:Name="ImagePushpin" Width="16" Height="16" Source="pack://application:,,,/WpfUtil;component/Images/PushpinUnpinned16x16.png" />
                                        </Grid>
                                        <ControlTemplate.Triggers>
                                            <Trigger Property="IsChecked" Value="True">
                                                <Setter TargetName="ImagePushpin" Property="Source" Value="pack://application:,,,/WpfUtil;component/Images/PushpinPinned16x16.png" />
                                            </Trigger>
                                        </ControlTemplate.Triggers>
                                    </ControlTemplate>
                                </CheckBox.Template>
                            </CheckBox>

模型:

public MainWindowViewModel()
{
    CommandPinPropertyGrid = new DelegateCommand<bool>(PinPropertyGrid);

...

// ******************************************************************
public DelegateCommand<bool> CommandPinPropertyGrid { get; private set; }

public void PinPropertyGrid(bool pinned)
{
    this.IsPropertyGridPinned = pinned;
}

DelegateCommand:

using System;
using System.Windows.Input;

namespace HQ.Wpf.Util.Command
{

    /// <summary>
    /// Represents a command that forwards the <c>Execute</c> and <c>CanExecute</c> calls to specified delegates.
    /// </summary>
    public class DelegateCommand<T> : ICommand
    {

        private readonly Action<T> _executeCallback;
        private readonly Predicate<T> _canExecuteCallback;

        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // OBJECT
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Initializes a new instance of the <see cref="DelegateCommand<T>"/> class.
        /// </summary>
        /// <param name="executeCallback">The execute callback delegate.</param>
        public DelegateCommand(Action<T> executeCallback)
            : this(executeCallback, null)
        {
            // No-op
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="DelegateCommand<T>"/> class.
        /// </summary>
        /// <param name="executeCallback">The execute callback delegate.</param>
        /// <param name="canExecuteCallback">The can execute callback delegate.</param>
        public DelegateCommand(Action<T> executeCallback, Predicate<T> canExecuteCallback)
        {
            if (executeCallback == null)
                throw new ArgumentNullException("executeCallback");

            this._executeCallback = executeCallback;
            this._canExecuteCallback = canExecuteCallback;
        }

        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // INTERFACE IMPLEMENTATION
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        #region ICommand Members

        /// <summary>
        /// Defines the method that determines whether the command can execute in its current state.
        /// </summary>
        /// <param name="parameter">Data used by the command.  If the command does not require data to be passed, this object can be set to <see langword="null"/>.</param>
        /// <returns>
        /// <c>true</c> if this command can be executed; otherwise, <c>false</c>.
        /// </returns>
        public bool CanExecute(object parameter)
        {
            return (this._canExecuteCallback == null) ? true : this._canExecuteCallback((T)parameter);
        }

        /// <summary>
        /// Occurs when changes occur that affect whether or not the command should execute.
        /// </summary>
        public event EventHandler CanExecuteChanged
        {
            add
            {
                if (this._canExecuteCallback != null)
                    CommandManager.RequerySuggested += value;
            }
            remove
            {
                if (this._canExecuteCallback != null)
                    CommandManager.RequerySuggested -= value;
            }
        }

        /// <summary>
        /// Defines the method to be called when the command is invoked.
        /// </summary>
        /// <param name="parameter">Data used by the command.  If the command does not require data to be passed, this object can be set to <see langword="null"/>.</param>
        public void Execute(object parameter)
        {
            this._executeCallback((T)parameter);
        }

        #endregion // ICommand Members

    }
}

-2

当您仅需要复选框的状态(已选或未选)时,您不需要参数。当您使用以下代码时,您可以检测复选框的状态:

CheckBox box = e.OriginalSource as CheckBox;

if(box.IsChecked.Value)
    DoThis();
else
    DoAnotherMethod();

"e" 是 Command 中的 ExecutedRoutedEventArgs 参数。你需要使用 box.IsChecked.Value,因为 box.IsChecked 的类型是 bool?。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接