wpf 复选框不触发事件“取消”或“未选中”

ct3nt3jp  于 2023-10-22  发布在  其他
关注(0)|答案(3)|浏览(291)

我是MVVM模式的新手,我在列表视图中的复选框方面遇到了问题。当我把一个复选框作为一个项目放入一个列表视图时,“checked”和“unchecked”事件不会触发。但是当我在列表视图之外添加一个复选框时,例如。在堆栈面板中,事件将触发。
有人能解释一下这个问题吗?
先谢谢你了。
这是我使用的代码:

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

ewm0tg9j1#

CheckBox继承了ListBox.ItemsSource绑定的DataContext,即ListBoxItems。您可能正在尝试调用主ViewModel中的Command。假设,为了正确地绑定到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属性绑定作为替代方案。

wwodge7n

wwodge7n2#

目前还不清楚您的DataContext实际上是什么样子(即其中CheckedOrUncheckedCommand被定义)。因为你写的命令是正确的调用时,绑定设置在DataTemplate外部的元素,使它看起来像你绑定到错误的DataContext
DataTemplateDataContext * 总是 * 模板化的数据项本身。在您的情况下,它的项目内的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的交互触发器绝对是多余的,应该删除。
出于可读性和可维护性的考虑,最好的做法总是让代码尽可能简单。Redundancy只会导致混乱,因为一个人会假设一个更深的含义,作者只是缺乏知识,而不是。
当您发现自己使用交互行为将视图粘合到其视图模型时,您通常做错了什么(在某种意义上,您可以做得更好并消除交互行为引入的开销)。
CheckBoxButtonBase,因此是ICommandSource。只需将命令绑定到CheckBox.Command属性:

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

而且,由于您已经将CheckBox.IsChecked属性绑定到同一数据源,因此可以完全删除命令(或IsChecked绑定)。只能使用CheckBox.IsCheckedCheckBox.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)
{
}
kknvjkwl

kknvjkwl3#

我在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>

相关问题