为什么我的WPF CheckBox绑定不工作? [英] Why is my WPF CheckBox Binding not working?

查看:107
本文介绍了为什么我的WPF CheckBox绑定不工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用MVVM,VS 2008和.NET 3.5 SP1。我有一个项目列表,每个都显示一个IsSelected属性。我添加了一个复选框来管理列表中所有项目的选择/取消选择(更新每个项目的IsSelected属性)。一切正常工作,但是当CheckBox的绑定控件发生PropertyChanged事件时,视图中IsChecked属性未被更新。

  ;复选框
Command ={Binding SelectAllCommand}
IsChecked ={Binding Path = AreAllSelected,Mode = OneWay}
Content =选择/取消选择所有标识的重复项
IsThreeState =True/>

我的虚拟机:

 public class MainViewModel:BaseViewModel 
{
public MainViewModel(ListViewModel listVM)
{
ListVM = listVM;
ListVM.PropertyChanged + = OnListVmChanged;
}

public ListViewModel ListVM {get;私人集合}
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 :$ {

$ b

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

并更新虚拟机:

  ... 

public string SelectAllText
{
get
{
var msg =全选;
if(ListVM!= null&&& ListVM.AreAllSelected!= null&& ListVM.AreAllSelected.Value)
msg =取消全选;

return msg;
}
}

...

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

所有内容都按预期工作 - 按钮的文字会随着所有项目的选择/被删除有没有关于CheckBox的IsSelected属性的绑定的东西?



感谢任何帮助!

解决方案

我发现问题。在WPF 3.0中存在一个Bug,IsChecked上的OneWay绑定会导致绑定被删除。感谢这篇文章 for帮助,这听起来像在WPF 4.0中修复的错误



要重现,创建一个新的WPF项目。



添加一个FooViewModel.cs:

  using System; 
使用System.ComponentModel;
使用System.Windows.Input;

命名空间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 void ChangeState()
{
switch(_isCheckedState)
{
case null:
_isCheckedState = true;
break;
默认值:
_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 :

 使用System.Windows; 
使用System.Windows.Controls.Primitives;

命名空间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属性未绑定!);
}
}
}

修改Window1.xaml: / p>

 < 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
标题=Window1
高度=200
宽度=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 =OnClickContent =更改状态/>
< / StackPanel>
< / Window>

点击按钮几次,看到CheckBox的状态在true和null之间切换(不是false) 。但是点击CheckBox,你会看到Binding从IsChecked属性中删除。



解决方法:



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

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

并更新绑定属性所以它不再是只读的:

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


I'm using MVVM, VS 2008, and .NET 3.5 SP1. I have a list of items, each exposing an IsSelected property. I have added a CheckBox to manage the selection/de-selection of all the items in the list (updating each item's IsSelected property). Everything is working except the IsChecked property is not being updated in the view when the PropertyChanged event fires for the CheckBox's bound control.

<CheckBox
  Command="{Binding SelectAllCommand}"
  IsChecked="{Binding Path=AreAllSelected, Mode=OneWay}"
  Content="Select/deselect all identified duplicates"
  IsThreeState="True" />

My 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");
  }
}

I'm not showing the implementation of SelectAllCommand or individual item selection here, but it doesn't seem to be relevant. When the user selects a single item in the list (or clicks the problem CheckBox to select/de-select all items), I have verified that the OnPropertyChanged("AreAllSelected") line of code executes, and tracing in the debugger, can see the PropertyChanged event is subscribed to and does fire as expected. But the AreAllSelected property's get is only executed once - when the view is actually rendered. Visual Studio's Output window does not report any data binding errors, so from what I can tell, the CheckBox's IsSelected property is properly bound.

If I replace the CheckBox with a Button:

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

and update the 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");
}

everything works as expected - the button's text is updated as all items are selected/desected. Is there something I'm missing about the Binding on the CheckBox's IsSelected property?

Thanks for any help!

解决方案

I found the problem. It seems a bug existed in WPF 3.0 with OneWay bindings on IsChecked causing the binding to be removed. Thanks to this post for the assistance, it sounds like the bug was fixed in WPF 4.0

To reproduce, create a new WPF project.

Add a 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;
    }
  }
}

Modify 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!");
    }
  }
}

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

Click on the button a few times and see the CheckBox's state toggle between true and null (not false). But click on the CheckBox and you will see that the Binding is removed from the IsChecked property.

The workaround:

Update the IsChecked binding to be TwoWay and set its UpdateSourceTrigger to be explicit:

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

and update the bound property so it's no longer read-only:

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

这篇关于为什么我的WPF CheckBox绑定不工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆