WPF 中 ToggleButton 的 IsChecked 属性的 OneWay 绑定

发布于 2024-09-24 19:52:21 字数 548 浏览 4 评论 0原文

我有一个 ToggleButton ,其 IsChecked 属性使用 OneWay 绑定绑定到一个属性。

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

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

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

I have a ToggleButton with its IsChecked property bound to a property using a OneWay binding.

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

The SomeCommand toggles the boolean SomeProperty value, and a PropertyChanged event is raised for SomeProperty.

If I change SomeProperty in my viewmodel the ToggleButton depresses correctly. However if I click the ToggleButton the binding seems to get lost and the button no longer gets checked according to the value of SomeProperty. Any ideas on how to fix this problem?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

谁对谁错谁最难过 2024-10-01 19:52:21

有一种简单而优雅的方法可以解决原始海报的问题 - 将 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 控件的方式) - 设置该属性会从中删除绑定,因此它会停止工作。

通过使用附加属性,我们可以克服这个问题,因为它永远不会在代码中分配值,因此绑定保持不变。

There is a simple and elegant way to solve the original poster's problem - replacing IsChecked property of the ToggleButton with an attachable property that will set IsChecked of the button in its change handler:

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 then will look like this:

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

EDIT: The OP solution does not work, because when the button is pressed the IsChecked property is set in the code (this is the way MS implemented ToggleButton control) - setting the property removes the binding from it and so it stops working.

By using attached property we can overcome this problem because it is never assigned a value in code and so the bindings stays intact.

傲鸠 2024-10-01 19:52:21

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

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

This is by design when using oneway data binding. Add the attached property PresentationTraceSources.TraceLevel=High to your binding and you will see when it gets disconnected. This link describes the problem as well (without offering any solution): Debugging Data Binding in WPF

The way I normally solve it is to use a command for user interaction and code behind to change the control appearance because of some changed properties.

硬不硬你别怂 2024-10-01 19:52:21

据我所知,Sinatr 关于发生的“不同步”是正确的,至少在较新的框架中是这样。

解决该问题的另一种简单方法是删除 mode=oneway 并实现一个空设置器。例如:

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

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

To my knowledge Sinatr is correct regarding the 'desync' that occurs, at least in newer frameworks.

Another simple way around the issue is to remove the mode=oneway and implement an empty setter. Ex:

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

With this binding setup you can you change the value of the backing variable from your command binding function, or from whether you need to. Just remember to call RaisePropertyChanged.

池予 2024-10-01 19:52:21

我有类似的问题。

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

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

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

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

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

SomeProperty = !set;
SomeProperty = set;

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

I have similar problem.

It is not "the binding seems to get lost" (unless it's earlier frameworks problems). Binding continues working and can be easily proved by changing property outside of that command (e.g. in handler of another button click event/command).

The problem is what IsChecked can be changed in two ways: 1) binding (when value of SomeProperty is changed button will be updated 2) user (if user press button he will change IsChecked, but binding is OneWay so SomeProperty will not be updated).

So you may have desync occurs when SomeProperty == false but button IsChecked == true or vice-versa.

To optimize performance binding mechanism is checking if new value is different from current. So if desync occurs and you try to update SomeProperty with the value which it already have, then nothing will happens.

Workaround is simple: update property in 2 steps

SomeProperty = !set;
SomeProperty = set;

where set is the value you need (e.g. opposite to current SomeProperty).

三月梨花 2024-10-01 19:52:21

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

I think what the problem boils down to is a conflict between the command and the IsChecked binding. My solution was to change my viewmodel to expose a bool? and bind that to the IsChecked property. I did not bind a command to the ToggleButton. Elsewhere in my code where I want to toggle the property I use SomeCommand.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文