c# WPF MVVM:复选框不会触发事件“已选中”或“未选中”

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

我是 MVVM 模式的新手,我遇到了列表视图内复选框的问题。 当我将复选框作为项目放入列表视图时,事件“已选中”和“未选中”不会触发。 但是当我在列表视图之外添加一个复选框时,例如在堆栈面板中,事件触发。

有人能解释一下这个问题吗?

提前谢谢您。

这是我使用的代码:

xmlns:behav="http://schemas.microsoft.com/xaml/behaviors"
<Border Grid.Row="1" Grid.Column="0" BorderThickness="2" Grid.RowSpan="3" BorderBrush="{StaticResource MainMenuColor}">
  <ListBox ItemsSource="{Binding ListBoxItems}" Background="Transparent" Foreground="{StaticResource MainMenuColor}">
    <ListBox.ItemTemplate>
      <DataTemplate>
        <CheckBox FontFamily="{StaticResource FontProtokoll}" IsChecked="{Binding IsChecked}" Content="{Binding Path=Text}" Foreground="{StaticResource MainMenuColor}">
          <behav:Interaction.Triggers>
            <behav:EventTrigger EventName="Checked">
              <behav:InvokeCommandAction Command="{Binding CheckedOrUncheckedCommand}"/>
            </behav:EventTrigger>
          </behav:Interaction.Triggers>
        </CheckBox>
      </DataTemplate>
    </ListBox.ItemTemplate>
  </ListBox>
</Border>

c# wpf mvvm checkbox binding
3个回答
0
投票

CheckBox
继承了
DataContext
绑定的
ListBox.ItemsSource
,即
ListBoxItems
。您可能正在尝试调用主
Command
中的
ViewModel
。假设,为了正确绑定到
ViewModel
,您需要执行类似的操作。

xmlns:behav="http://schemas.microsoft.com/xaml/behaviors"
<Border Grid.Row="1" Grid.Column="0" BorderThickness="2" Grid.RowSpan="3" BorderBrush="{StaticResource MainMenuColor}">
  <ListBox ItemsSource="{Binding ListBoxItems}" Background="Transparent" Foreground="{StaticResource MainMenuColor}">
    <ListBox.ItemTemplate>
      <DataTemplate>
        <CheckBox FontFamily="{StaticResource FontProtokoll}" IsChecked="{Binding IsChecked}" Content="{Binding Path=Text}" Foreground="{StaticResource MainMenuColor}">
          <behav:Interaction.Triggers>
            <behav:EventTrigger EventName="Checked">
              <behav:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType=ListBox}, Path=DataContext.CheckedOrUncheckedCommand}"/>
            </behav:EventTrigger>
          </behav:Interaction.Triggers>
        </CheckBox>
      </DataTemplate>
    </ListBox.ItemTemplate>
  </ListBox>
</Border>

CheckBox
现在直接绑定到它的父级
ListBox
s
DataContext
以及其中的
CheckedOrUncheckedCommand

此外,您还可以根据您的用例使用

IsChecked
属性绑定作为替代方案。


0
投票

尚不清楚您的

DataContext
实际上是什么样子(即
CheckedOrUncheckedCommand
的定义位置)。因为您编写的命令在
DataTemplate
之外的元素上设置绑定时会正确调用,所以看起来您绑定到了错误的
DataContext

DataContext
DataTemplate
always 模板化数据项本身。就您而言,它是
ItemsSource
内的项目。
您可以通过设置
Binding.RelativeSource
属性来修复绑定,也可以在元素树中查找公开正确
DataContext
的元素。在你的情况下,该元素应该是父元素
ListBox
:

<DataTempate>

  <!-- DataContext is the templated data item.
       In this case its the item inside the `ListBoxItems` source collection that is bound to the ItemsSource. -->
  <CheckBox>
    <behav:Interaction.Triggers>
      <behav:EventTrigger EventName="Checked">
        <behav:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType=ListBox}, Path=DataContext.CheckedOrUncheckedCommand}"/>
      </behav:EventTrigger>
    </behav:Interaction.Triggers>
  </CheckBox>
</DataTemplate>

但是,

CheckedOrUncheckedCommand
的交互触发器绝对是多余的,应该删除。
为了可读性和可维护性,最好让代码尽可能简单。冗余只会导致混乱,因为人们会假设作者缺乏知识而具有更深层次的含义。
当您发现自己使用交互行为将视图粘合到其视图模型时,您通常会做错一些事情(从某种意义上说,您可以做得更好并消除交互行为带来的开销)。

CheckBox
ButtonBase
,因此也是
ICommandSource
。只需将命令绑定到
CheckBox.Command
属性即可:

<CheckBox Command="{Binding CheckedOrUncheckedCommand}" />

并且由于您已经将

CheckBox.IsChecked
属性绑定到同一数据源,因此您可以完全删除该命令(或
IsChecked
绑定)。 仅使用其中之一,
CheckBox.IsChecked
CheckBox.Command

使用

CheckBox.Command
:

<CheckBox Command="{Binding CheckedOrUncheckedCommand}" />
private bool IsEnabled { get; set; }

private void ExecuteCheckedOrUncheckedCommand(object commandParameter)
{
  // Optionally set a property using the XOR operator to toggle it 
  // (CheckBox is a ToggleButton)
  this.IsEnabled ^= true;
}

或者使用

CheckBox.IsChecked
属性:

<CheckBox IsChecked="{Binding IsEnabled}" />
// TODO::Property must raise the INotifyPropertyChanged.PropertyChanged event
private bool isEnabled;
public bool IsEnabled 
{ 
  get => this.isEnabled; 
  set 
  {
    this.isEnabled = value;
    OnPropertyChanged(nameof(this.IsEnabled));
    OnIsEnabledChanged();
}

private void OnIsEnabledChanged()
{
  ExecuteCheckedOrUncheckedCommand(null);
}

private void ExecuteCheckedOrUncheckedCommand(object commandParameter)
{
}

0
投票

我在WinUI3中遇到了类似的问题,没错,我们需要定义控件的DataContext。就我而言,我在 DataGrid 的分组标题中定义了一个复选框。我需要的是,当单击组标题中的复选框时,可以选择该组中的所有复选框项目。

                                            <Interactions:EventTriggerBehavior EventName="Checked"
                                                                               SourceObject="{Binding ElementName=_groupCheckBox}">
                                                <Interactions:InvokeCommandAction Command="{Binding ElementName=_dataGrid, Path=DataContext.GroupCheckedCommand}"
                                                                                  CommandParameter="{x:Bind PropertyValue}" />
                                            </Interactions:EventTriggerBehavior>
© www.soinside.com 2019 - 2024. All rights reserved.