用于切换按钮的单向绑定';s在WPF中检查属性

用于切换按钮的单向绑定';s在WPF中检查属性,wpf,data-binding,togglebutton,Wpf,Data Binding,Togglebutton,我有一个ToggleButton,它的IsChecked属性使用单向绑定绑定到属性 <ToggleButton Command="{Binding Path=SomeCommand}" IsChecked="{Binding Path=SomeProperty, Mode=OneWay}" /> SomeCommand切换布尔值SomeProperty,并为SomeProperty引发PropertyChanged事件 如果我在视图模型中更改了SomePrope

我有一个
ToggleButton
,它的
IsChecked
属性使用单向绑定绑定到属性

<ToggleButton
    Command="{Binding Path=SomeCommand}"
    IsChecked="{Binding Path=SomeProperty, Mode=OneWay}" />

SomeCommand
切换布尔值
SomeProperty
,并为
SomeProperty
引发
PropertyChanged
事件


如果我在视图模型中更改了
SomeProperty
,则
切换按钮将正确按下。但是,如果我单击
ToggleButton
,绑定似乎丢失,并且按钮不再根据
SomeProperty
的值进行检查。关于如何解决这个问题有什么想法吗?

这是在使用单向数据绑定时设计的。将附加属性PresentationTraceSources.TraceLevel=High添加到绑定中,您将看到它何时断开连接。此链接也描述了问题(不提供任何解决方案):


我通常的解决方法是使用一个用于用户交互的命令和代码隐藏来更改控件外观,因为某些属性已更改

我认为问题归结为命令和
IsChecked
绑定之间的冲突。我的解决方案是将viewmodel更改为公开
bool?
,并将其绑定到
IsChecked
属性。我没有将命令绑定到
切换按钮
。在我的代码中,在我想切换属性的地方,我使用了
SomeCommand

有一种简单而优雅的方法来解决原始海报的问题-将ToggleButton的IsChecked属性替换为可附加属性,该属性将在其更改处理程序中设置按钮的IsChecked:

namespace TBFix
{
  public class TBExtender
  {
    public static readonly DependencyProperty IsCheckedProperty =
      DependencyProperty.RegisterAttached("IsChecked", 
                                          typeof(bool),
                                          typeof(TBExtender),
                                          new PropertyMetadata(OnChanged));

    public static bool GetIsChecked(DependencyObject obj)
    {
      return (bool)obj.GetValue(IsCheckedProperty);
    }
    public static void SetIsChecked(DependencyObject obj, bool value)
    {
      obj.SetValue(IsCheckedProperty, value);
    }

    private static void OnChanged(DependencyObject o,
                                  DependencyPropertyChangedEventArgs args)
    {
      ToggleButton tb = o as ToggleButton;
      if (null != tb)
        tb.IsChecked = (bool)args.NewValue;
    }
  }
}
XAML将如下所示:

<ToggleButton Command="{Binding Path=SomeCommand}"
              TBFix:TBExtender.IsChecked="{Binding Path=SomeProperty,
                                                   Mode=OneWay}" />

编辑:OP解决方案不起作用,因为当按下按钮时,代码中会设置IsChecked属性(这是MS实现ToggleButton控件的方式)-设置该属性会删除其中的绑定,因此它会停止工作


通过使用attached属性,我们可以克服这个问题,因为代码中从未为它赋值,因此绑定保持不变。

我也有类似的问题

这是而不是“绑定似乎丢失了”(除非是早期的框架问题)。绑定继续工作,并且可以通过更改该命令外部的属性(例如,在另一个按钮单击事件/命令的处理程序中)来轻松证明

问题是什么
IsChecked
可以通过两种方式更改:1)绑定(当
SomeProperty
的值更改时,按钮将被更新2)用户(如果用户按下按钮,他将更改
IsChecked
,但绑定是单向的,因此
SomeProperty
不会被更新)

因此,当
SomeProperty==false
但按钮
IsChecked==true
时,可能会发生desync,反之亦然

要优化性能绑定机制,需要检查新值是否与当前值不同。因此,如果发生去同步,并且您尝试用它已经拥有的值更新
SomeProperty
,那么什么也不会发生

解决方法很简单:分两步更新属性

SomeProperty = !set;
SomeProperty = set;

其中,
set
是您需要的值(例如,与当前的
SomeProperty
相反)。

据我所知,Sinatr对于发生的“去同步”是正确的,至少在较新的框架中是如此

解决此问题的另一个简单方法是删除mode=oneway并实现空setter。例:

    bool _MyIsEnabled;
    public bool MyIsEnabled
    {
        get { return _MyIsEnabled; }
        set { }
    }

使用此绑定设置,您可以从命令绑定函数或是否需要更改支持变量的值。请记住调用RaisePropertyChanged。

SomeCommand的作用是什么?我有很多ToggleButton,它们用同样的绑定做同样的事情,SomeCommand所做的就是否定SomeProperty的当前值。SomeProperty实际上是一种不同的类型,我使用转换器将其更改为布尔值。为了让问题更简单,我省略了这一点。嗨,亚历克斯,谢谢你提供了优雅的解决方案,它适合我。但我不明白它是怎么工作的。你能再解释一下吗?我已经补充了几句关于我的解决方案背后的想法。您可以在MSDN()上阅读更多关于附加属性的信息。这确实很优雅!为什么这个答案被接受?它并不能解决这个问题(这个问题存在并且可以很容易地复制)。我喜欢这个简单的解决方法——有点粗糙,但比创建自定义控件简单