在 Checkbox.Checked 或 Unchecked 上执行命令

问题描述 投票:0回答:7

我的窗口上有一个复选框控件。我想执行一个命令来调用关联视图模型中的方法。我还需要复选框的值。我似乎找不到将命令与复选框关联起来的方法。有人做过吗?

wpf mvvm checkbox command
7个回答
96
投票
<CheckBox Content="CheckBox"
          Command="{Binding YourCommand}"
          CommandParameter="{Binding IsChecked, RelativeSource={RelativeSource Self}}" />

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>


15
投票

这将满足您的要求 -

<CheckBox CommandParameter="{Binding}"
          Command="{Binding DataContext.YourCommand,
          RelativeSource={RelativeSource FindAncestor,
                           AncestorType={x:Type UserControl}}}"
          Content="{Binding Path=Name}">

5
投票
  • System.Windows.Interactivity
    添加到您的项目参考中。
  • xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    添加到您的 XAML 命名空间。
<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://stackoverflow.com/a/22286816/336753

我的 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
投票

该示例是一个工作代码摘录,它只是为了帮助理解各个方面。它是一个图钉,可以是活动的也可以是非活动的,并且它使用 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; }

委托命令:

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



0
投票

这是我根据 Microsoft 文档和其他 SO 问题尝试过的东西:

    事件触发器
  • 属性触发器
  • ,因为我将复选框的 IsChecked 属性绑定到视图模型中的
    ObservableProperty
  • 复选框状态改变事件
  • 这些都没有达到我想要的效果,与您类似,根据 Checkbox 属性更改来调用方法/命令,因为这些要么混乱且令人费解,要么违反了 MVVM 原则,因为它们仅限于 View 而不是 View型号.

与单独问题的

这个答案

这个答案类似,我最终使用了 .NET MAUI 社区工具包中的EventToCommandBehavior行为。我不知道这是否适用于 WPF,抱歉。 这是我针对此示例的简化代码。

MainPage.xaml

<ContentPage
        x:Class="MyProject.Views.MainPage"
        xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
        xmlns:viewmodel="clr-namespace:MyProject.ViewModels"
        x:DataType="viewmodel:MainPageViewModel">
 
        <CheckBox x:Name="WholeNameCheckbox"
              IsChecked="{Binding IsExactMatch}"
              HorizontalOptions="Center">
              <CheckBox.Behaviors>
                    <toolkit:EventToCommandBehavior
                               EventName="CheckedChanged"
                               Command="{Binding ExactMatchCheckedCommand}"
                               CommandParameter="{Binding IsChecked, Source={x:Reference WholeNameCheckbox}}"/>
             </CheckBox.Behaviors>
        </CheckBox>
</ContentPage>

MainPage.xaml.cs

namespace MyProject.Views;

public partial class MainPage : ContentPage
{
    public MainPage(MainPageViewModel viewModel)
    {
        InitializeComponent();
        BindingContext = viewModel;
    }
}

MainPageViewModel.cs

using MyProject.Services;
using MvvmHelpers;   // For [RelayCommand]

namespace MyProject.ViewModels;

public partial class MainPageViewModel : BaseViewModel 
{
  // ObservableProperty gives the variable a public property and
  // all the NotifyChanges interfaces and gives the properties
  // OnPropertyChanged() methods.
  [ObservableProperty]
  bool _returnsPartialMatch;

  [ObservableProperty]
  bool _returnsPartialMatchWithSpace;

  [ObservableProperty]
  public bool _isExactMatch;

  [RelayCommand]
  async Task ExactMatchCheckedAsync(bool isChecked_p)
  {
       // Offload processing to thread pool.
       await Task.Run(() =>
       {
           // Do stuff in your view model using your properties or whatever
       }
  }
}

按预期工作 - 当选中“精确匹配”复选框时,
IsExactMatch

属性为

True
,无论哪种方式,当选中状态更改时,它都会调用视图模型中的异步方法并将其 IsChecked 属性值传递给该方法。由于此命令是在 IsExactMatch 属性更改后调用的,因此该值更改或需要验证它的时间并不奇怪。
    


-2
投票

CheckBox box = e.OriginalSource as CheckBox; if(box.IsChecked.Value) DoThis(); else DoAnotherMethod();

“e”是命令中的 ExecutedRoulatedEventArgs 参数。您需要 box.IsChecked.Value,因为 box.IsChecked 来自类型 bool?.

© www.soinside.com 2019 - 2024. All rights reserved.