C#WPF中的只读CheckBox

我有一个棘手的问题,我想从复选框中略微不寻常的行为,似乎无法搞清楚。 任何建议都会受到欢迎。 我想要的行为是:

  1. CheckBox已启用并准备供用户单击,IsChecked表示存储在数据结构中的绑定布尔值
  2. 用户单击CheckBox导致单击事件触发但数据结构中的绑定值未更新,并且CheckBox的可视表示未更新但已禁用以停止进一步单击
  3. click事件触发要发送到远程设备的消息,这需要一些时间来响应
  4. 远程设备响应导致使用新值更新数据结构,然后绑定更新isChecked状态,并重新启用CheckBox以进一步单击

我遇到的问题是,虽然OneWay数据绑定在单击CheckBox时不会更新数据结构,但是可视表示确实发生了变化(我觉得很奇怪,现在不应该使用IsChecked作为指向该值的指针)数据结构)。

我可以反转Click()事件中的更改并在那里执行禁用,但这非常混乱。 我也可以使用数据结构值的set属性来设置一个isEnabled值,该值也必须重新启用CheckBox,但这看起来也很麻烦。

有干净的方法吗? 也许使用派生的CheckBox类? 如何阻止视觉表示更新?

谢谢

埃德

那么数据绑定到IsHitTestVisible属性呢?

例如,假设采用MVVM方法:

  1. IsReadOnly属性添加到视图模型,最初设置为true以允许单击。
  2. 将此属性绑定到CheckBox.IsHitTestVisible。
  3. 首次单击后,更新视图模型以将此值设置为false,从而防止任何进一步的单击。

我没有这个确切的要求,我只需要一个总是只读的复选框,它似乎很好地解决了这个问题。 另请注意Goran在下面关于Focusable属性的评论。

我不认为为此创建一个完整的控制是必要的。 您遇到的问题来自于您看到“支票”的地方不是真正的复选框,它是一颗子弹。 如果我们查看CheckBox的ControlTemplate ,我们可以看到它是如何发生的(虽然我更喜欢Blend模板)。 作为其中的一部分,即使您对IsChecked属性的绑定设置为OneWay,它仍然在UI中更新,即使它没有设置绑定值。

因此,解决这个问题的一个非常简单的方法就是修改ControlTemplate以查看相关的复选框。

如果我们使用Blend来获取控件模板,我们可以在ControlTemplate中看到代表实际复选框区域的Bullet。

      

在这里,IsChecked和RenderPressed正在实际显示’Check’,因此要修复它,我们可以从ComboBox上的IsChecked属性中删除绑定,并使用它来替换Bullet的IsChecked属性上的TemplateBinding。

这是一个展示所需效果的小样本,请注意保持Vista CheckBox外观需要将PresentationFramework.Aero dll添加到项目中。

                     

和代码背后,我们的支持布尔值:

 public partial class Window1 : Window, INotifyPropertyChanged { public Window1() { InitializeComponent(); this.DataContext = this; } private bool myBoolean; public bool MyBoolean { get { return this.myBoolean; } set { this.myBoolean = value; this.NotifyPropertyChanged("MyBoolean"); } } #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(String info) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(info)); } } #endregion } 

这是我为了类似的原因而写的类似的东西(仍然正常引发所有Click和Command事件,但默认情况下不会改变绑定源,也不会自动切换。不幸的是它仍然有点击动画淡入淡出,如果点击处理代码最终没有改变IsChecked,这有点奇怪。

 public class OneWayCheckBox : CheckBox { private class CancelTwoWayMetadata : FrameworkPropertyMetadata { protected override void Merge(PropertyMetadata baseMetadata, DependencyProperty dp) { base.Merge(baseMetadata, dp); BindsTwoWayByDefault = false; } } static OneWayCheckBox() { // Remove BindsTwoWayByDefault IsCheckedProperty.OverrideMetadata(typeof(OneWayCheckBox), new CancelTwoWayMetadata()); } protected override void OnToggle() { // Do nothing. } } 

用法:

  

(请注意,IsChecked绑定现在默认是单向的;如果需要,可以将其声明为TwoWay,但这会使部分失败。)

迟到的答案,但我刚刚遇到了寻找其他问题的问题。 您想要的不是具有exception行为的复选框,您想要的是具有不寻常外观的按钮。 更改控件的外观总是比它的行为更容易。 沿着这些方向应该做的事情(未经测试)

  

我还需要关闭一个Checkbox / RadioButton的AutoCheckfunction,我想在没有控件自动检查的情况下处理Click事件。 我在这里和其他线程尝试了各种解决方案,并对结果不满意。

所以我挖掘了WPF正在做的事情(使用Reflection),我注意到:

  1. CheckBox和RadioButton都inheritance自ToggleButton控件原语。 它们都没有OnClickfunction。
  2. ToggleButtoninheritance自ButtonBase控件原语。
  3. ToggleButton重写OnClick函数并执行:this.OnToggle(); base.OnClick();
  4. ButtonBase.OnClick执行’base.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent,this));’

基本上,我需要做的就是覆盖OnClick事件,不要调用OnToggle,并执行base.RaiseEvent

这是完整的代码(请注意,这也可以很容易地重做RadioButtons):

 using System.Windows.Controls.Primitives; public class AutoCheckBox : CheckBox { private bool _autoCheck = false; public bool AutoCheck { get { return _autoCheck; } set { _autoCheck = value; } } protected override void OnClick() { if (_autoCheck) { base.OnClick(); } else { base.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent, this)); } } } 

我现在有一个不自动检查的CheckBox,仍然会触发Click事件。 另外,当我以编程方式更改IsChecked属性时,我仍然可以订阅Checked / Unchecked事件并处理那些事情。

最后一点:与在Click事件中执行类似IsChecked!= IsChecked的其他解决方案不同,这不会导致Checked / Unchecked / Indeterminate事件触发,直到您以编程方式设置IsChecked属性。

使用validation来阻止布尔值在您不希望的情况下进行切换 – http://www.codeproject.com/KB/WPF/wpfvalidation.aspx

这比其他答案要小得多,或挂钩Clicked

我一直在尝试创建我的通用ReadOnlyCheckBox样式/模板,但我遇到了绑定数据的问题。 在示例中,您直接绑定到ControlTemplate定义中的数据,但当然这不是我想要的,因为我希望能够声明这样的新复选框:

   

当然,当我这样做,然后将子弹上的事件触发器设置为IsChecked的TemplateBinding时,我就完全按照我的开头! 我想我不明白为什么直接在子弹中设置绑定不同于设置IsChecked然后绑定到那个,不是TemplateBinding只是一种引用正在创建的控件的属性中设置的内容的方式? 即使数据没有更新,Click如何触发UI更新? 是否有触发器Click我可以覆盖以停止更新?

我得到了所有DictionaryResource的工作正常,所以我很高兴,为指针欢呼。

我很好奇的另一件事是,如果可以通过使用样式中的BasedOn参数来减少我的Control / Style模板,那么我只会覆盖我实际需要更改的内容而不是声明我认为的很多内容无论如何,它是标准模板的一部分。 我可能会玩这个游戏。

干杯

ED

如果它对任何人有帮助,我发现一个快速而优雅的解决方案是挂钩Checked和Unchecked事件并根据你的标志操纵值。

  public bool readOnly = false; private bool lastValidValue = false; public MyConstructor() { InitializeComponent(); contentCheckBox.Checked += new RoutedEventHandler(contentCheckBox_Checked); contentCheckBox.Unchecked += new RoutedEventHandler(contentCheckBox_Checked); } void contentCheckBox_Checked(object sender, RoutedEventArgs e) { if (readOnly) contentCheckBox.IsChecked = lastValidValue; else lastValidValue = (bool)contentCheckBox.IsChecked; } 

将CheckBox包装在ContentControl中。 使ContentControl IsEnabled = False

这两个属性是 – IsHitTestVisible和Focusable使这两个属性为False。 这使得WPF中的只读复选框成为可能。 因此,WPF中的readonly复选框的最终XAML语句如下所示 –