C# 为什么我的WPF复选框绑定不起作用?

C# 为什么我的WPF复选框绑定不起作用?,c#,wpf,data-binding,mvvm,C#,Wpf,Data Binding,Mvvm,我使用的是MVVM、VS2008和.NET3.5SP1。我有一个项目列表,每个项目都显示一个IsSelected属性。我添加了一个复选框来管理列表中所有项目的选择/取消选择(更新每个项目的IsSelected属性)。当为复选框的绑定控件触发PropertyChanged事件时,除IsChecked属性未在视图中更新外,所有操作都正常 <CheckBox Command="{Binding SelectAllCommand}" IsChecked="{Binding Path=Are

我使用的是MVVM、VS2008和.NET3.5SP1。我有一个项目列表,每个项目都显示一个IsSelected属性。我添加了一个复选框来管理列表中所有项目的选择/取消选择(更新每个项目的IsSelected属性)。当为复选框的绑定控件触发PropertyChanged事件时,除IsChecked属性未在视图中更新外,所有操作都正常

<CheckBox
  Command="{Binding SelectAllCommand}"
  IsChecked="{Binding Path=AreAllSelected, Mode=OneWay}"
  Content="Select/deselect all identified duplicates"
  IsThreeState="True" />
我没有在这里展示SelectAllCommand或单项选择的实现,但它似乎并不相关。当用户选择列表中的单个项目(或单击“问题”复选框选择/取消选择所有项目)时,我已验证OnPropertyChanged(“AreAllSelected”)代码行是否已执行,并且在调试器中进行跟踪,可以看到PropertyChanged事件已订阅,并且确实按预期触发。但是AreaAllSelected属性的get仅在视图实际渲染时执行一次。VisualStudio的输出窗口不报告任何数据绑定错误,因此从我所知,复选框的IsSelected属性已正确绑定

如果我用按钮替换复选框:

<Button Content="{Binding SelectAllText}" Command="{Binding SelectAllCommand}"/>
一切按预期运行-按钮的文本在选中/取消选中所有项目时更新。复选框的IsSelected属性上的绑定是否缺少某些内容


谢谢你的帮助

我发现了问题。似乎WPF3.0中存在一个错误,在IsChecked上有单向绑定,导致绑定被删除。感谢您的帮助,听起来这个bug在WPF4.0中已经修复了

要复制,请创建一个新的WPF项目

添加FooViewModel.cs:

using System;
using System.ComponentModel;
using System.Windows.Input;

namespace Foo
{
  public class FooViewModel : INotifyPropertyChanged
  {
    private bool? _isCheckedState = true;

    public FooViewModel()
    {
      ChangeStateCommand = new MyCmd(ChangeState);
    }

    public bool? IsCheckedState
    {
      get { return _isCheckedState; }
    }

    public ICommand ChangeStateCommand { get; private set; }

    private void ChangeState()
    {
      switch (_isCheckedState)
      {
        case null:
          _isCheckedState = true;
          break;
        default:
          _isCheckedState = null;
          break;
      }

      OnPropertyChanged("IsCheckedState");
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
      var changed = PropertyChanged;
      if (changed != null)
        changed(this, new PropertyChangedEventArgs(propertyName));
    }
  }

  public class MyCmd : ICommand
  {
    private readonly Action _execute;
    public event EventHandler CanExecuteChanged;

    public MyCmd(Action execute)
    {
      _execute = execute;
    }

    public void Execute(object parameter)
    {
      _execute();
    }

    public bool CanExecute(object parameter)
    {
      return true;
    }
  }
}
修改Window1.xaml.cs:

using System.Windows;
using System.Windows.Controls.Primitives;

namespace Foo
{
  public partial class Window1
  {
    public Window1()
    {
      InitializeComponent();
    }

    private void OnClick(object sender, RoutedEventArgs e)
    {
      var bindingExpression = MyCheckBox.GetBindingExpression(ToggleButton.IsCheckedProperty);
      if (bindingExpression == null)
        MessageBox.Show("IsChecked property is not bound!");
    }
  }
}
修改Window1.xaml:

<Window
  x:Class="Foo.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:vm="clr-namespace:Foo"
  Title="Window1"
  Height="200"
  Width="200"
  >

  <Window.DataContext>
    <vm:FooViewModel />
  </Window.DataContext>

  <StackPanel>
    <CheckBox
      x:Name="MyCheckBox"
      Command="{Binding ChangeStateCommand}"
      IsChecked="{Binding Path=IsCheckedState, Mode=OneWay}"
      Content="Foo"
      IsThreeState="True"
      Click="OnClick"/>
    <Button Command="{Binding ChangeStateCommand}" Click="OnClick" Content="Change State"/>
  </StackPanel>
</Window>
并更新绑定属性,使其不再为只读:

public bool? IsCheckedState
{
  get { return _isCheckedState; }
  set { }
}
<Window
  x:Class="Foo.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:vm="clr-namespace:Foo"
  Title="Window1"
  Height="200"
  Width="200"
  >

  <Window.DataContext>
    <vm:FooViewModel />
  </Window.DataContext>

  <StackPanel>
    <CheckBox
      x:Name="MyCheckBox"
      Command="{Binding ChangeStateCommand}"
      IsChecked="{Binding Path=IsCheckedState, Mode=OneWay}"
      Content="Foo"
      IsThreeState="True"
      Click="OnClick"/>
    <Button Command="{Binding ChangeStateCommand}" Click="OnClick" Content="Change State"/>
  </StackPanel>
</Window>
IsChecked="{Binding Path=IsCheckedState, Mode=TwoWay, UpdateSourceTrigger=Explicit}"
public bool? IsCheckedState
{
  get { return _isCheckedState; }
  set { }
}