微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c# – 为什么我的WPF CheckBox绑定不起作用?

我正在使用MVVM,VS 2008和.NET 3.5 SP1.我有一个项目列表,每个项目都暴露一个IsSelected属性.我添加一个CheckBox来管理列表中所有项目的选择/取消选择(更新每个项目的IsSelected属性).一切正常,但是当PropertyChanged事件触发CheckBox的绑定控件时,视图中没有更新IsChecked属性.
<CheckBox
  Command="{Binding SelectAllCommand}"
  IsChecked="{Binding Path=AreAllSelected,Mode=OneWay}"
  Content="Select/deselect all identified duplicates"
  IsThreeState="True" />

我的VM:

public class Mainviewmodel : Baseviewmodel
{
  public Mainviewmodel(Listviewmodel listVM)
  {
    ListVM = listVM;
    ListVM.PropertyChanged += OnListVmChanged;
  }

  public Listviewmodel ListVM { get; private set; }
  public ICommand SelectAllCommand { get { return ListVM.SelectAllCommand; } }

  public bool? AreAllSelected
  {
    get
    {
      if (ListVM == null)
        return false;

      return ListVM.AreAllSelected;
    }
  }

  private void OnListVmChanged(object sender,PropertyChangedEventArgs e)
  {
    if (e.PropertyName == "AreAllSelected")
      OnPropertyChanged("AreAllSelected");
  }
}

我没有在这里显示SelectAllCommand或单个项目选择的实现,但它似乎没有相关性.当用户选择列表中的单个项目(或单击问题CheckBox来选择/取消选择所有项目)时,我已经验证了OnPropertyChanged(“AreAllSelected”)代码行的执行,以及在调试器中的跟踪,可以看到PropertyChanged事件已订阅并按预期触发.但AreAllSelected属性的get只执行一次 – 实际呈现视图时. Visual Studio的“输出”窗口不报告任何数据绑定错误,因此从我可以看出,CheckBox的IsSelected属性已正确绑定.

如果我用Button替换CheckBox

<Button Content="{Binding SelectAllText}" Command="{Binding SelectAllCommand}"/>

并更新VM:

...

public string SelectAllText
{
  get
  {
    var msg = "Select All";
    if (ListVM != null && ListVM.AreAllSelected != null && ListVM.AreAllSelected.Value)
      msg = "deselect All";

    return msg;
  }
}

...

private void OnListVmChanged(object sender,PropertyChangedEventArgs e)
{
  if (e.PropertyName == "AreAllSelected")
    OnPropertyChanged("SelectAllText");
}

一切都按预期工作 – 按钮的文本会更新,因为所有项目都被选中/取消.在CheckBox的IsSelected属性上有关于绑定的东西吗?

谢谢你的帮助!

解决方法

我发现了问题.似乎在WPF 3.0中存在一个错误,在IsChecked上使用OneWay绑定导致绑定被删除.感谢 this post的帮助,听起来像是在WPF 4.0中修复了这个bug

要重现,请创建一个新的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>

单击按钮几次,看到CheckBox的状态在true和null之间切换(非假).但是单击CheckBox,您将看到Binding已从IsChecked属性删除.

解决方法

将IsChecked绑定更新为TwoWay并将其UpdateSourceTrigger设置为显式:

IsChecked="{Binding Path=IsCheckedState,Mode=TwoWay,UpdateSourceTrigger=Explicit}"

并更新绑定属性,使其不再是只读的:

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

原文地址:https://www.jb51.cc/csharp/99588.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐