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

flvtvl50  于 2023-06-24  发布在  C#
关注(0)|答案(2)|浏览(348)

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

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

gv8xihay1#

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现在直接绑定到其父ListBoxDataContext和其中的CheckedOrUncheckedCommand
此外,您可以根据您的用例使用IsChecked属性绑定作为替代方案。

ru9i0ody

ru9i0ody2#

目前还不清楚你的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的交互触发器是绝对多余的,应该删除。
为了可读性和可维护性,最好的做法是尽可能地保持代码的简单。冗余只会导致混乱,因为一个人会假设一个更深的含义,而作者只是缺乏知识。
当您发现自己使用交互行为将视图粘合到视图模型时,您通常做错了事情(在某种意义上,您可以做得更好,消除交互行为带来的开销)。
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)
{
}

相关问题