C#WPF中的只读CheckBox

18 c# wpf checkbox binding

我有一个棘手的问题,我想从复选框中略微不寻常的行为,似乎无法弄明白.任何建议都是最受欢迎的.我想要的行为是:

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

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

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

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

谢谢

埃德

si6*_*618 18

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

例如,假设采用MVVM方法:

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

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

  • 在这种情况下,您确实应该将Focusable设置为false以防止用户使用选项卡选中复选框. (3认同)

Ste*_*nko 6

这个答案不是你的问题,但它回答了标题中的问题。

WPF 中的复选框没有该IsReadOnly属性。但是,使用属性 IsHitTestVisible="False"Focusable="False"

      <CheckBox IsHitTestVisible="False"
                Focusable="False"/>
Run Code Online (Sandbox Code Playgroud)


rmo*_*ore 5

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

因此,解决此问题的一种非常简单的方法是仅修改相关复选框的ControlTemplate。

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

        <BulletDecorator SnapsToDevicePixels="true"
                         Background="Transparent">
            <BulletDecorator.Bullet>
                <Microsoft_Windows_Themes:BulletChrome Background="{TemplateBinding Background}"
                                                       BorderBrush="{TemplateBinding BorderBrush}"
                                                       IsChecked="{TemplateBinding IsChecked}"
                                                       RenderMouseOver="{TemplateBinding IsMouseOver}"
                                                       RenderPressed="{TemplateBinding IsPressed}" />
            </BulletDecorator.Bullet>
            <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                              Margin="{TemplateBinding Padding}"
                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                              RecognizesAccessKey="True" />
        </BulletDecorator>
Run Code Online (Sandbox Code Playgroud)

在这里,IsChecked和RenderPressed实际上是使“检查”出现的原因,因此要解决此问题,我们可以从ComboBox的IsChecked属性中删除绑定,并使用它替换Bullet的IsChecked属性上的TemplateBinding。

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

<Window x:Class="Sample.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
    Title="Window1"
    Height="300"
    Width="300">
<Window.Resources>
    <SolidColorBrush x:Key="CheckBoxFillNormal"
                     Color="#F4F4F4" />
    <SolidColorBrush x:Key="CheckBoxStroke"
                     Color="#8E8F8F" />
    <Style x:Key="EmptyCheckBoxFocusVisual">
        <Setter Property="Control.Template">
            <Setter.Value>
                <ControlTemplate>
                    <Rectangle SnapsToDevicePixels="true"
                               Margin="1"
                               Stroke="Black"
                               StrokeDashArray="1 2"
                               StrokeThickness="1" />
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style x:Key="CheckRadioFocusVisual">
        <Setter Property="Control.Template">
            <Setter.Value>
                <ControlTemplate>
                    <Rectangle SnapsToDevicePixels="true"
                               Margin="14,0,0,0"
                               Stroke="Black"
                               StrokeDashArray="1 2"
                               StrokeThickness="1" />
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style x:Key="CheckBoxStyle1"
           TargetType="{x:Type CheckBox}">
        <Setter Property="Foreground"
                Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
        <Setter Property="Background"
                Value="{StaticResource CheckBoxFillNormal}" />
        <Setter Property="BorderBrush"
                Value="{StaticResource CheckBoxStroke}" />
        <Setter Property="BorderThickness"
                Value="1" />
        <Setter Property="FocusVisualStyle"
                Value="{StaticResource EmptyCheckBoxFocusVisual}" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type CheckBox}">
                    <BulletDecorator SnapsToDevicePixels="true"
                                     Background="Transparent">
                        <BulletDecorator.Bullet>
                            <Microsoft_Windows_Themes:BulletChrome Background="{TemplateBinding Background}"
                                                                   BorderBrush="{TemplateBinding BorderBrush}"
                                                                   RenderMouseOver="{TemplateBinding IsMouseOver}" />
                        </BulletDecorator.Bullet>
                        <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                          HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                          Margin="{TemplateBinding Padding}"
                                          VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                          RecognizesAccessKey="True" />
                    </BulletDecorator>
                    <ControlTemplate.Triggers>
                        <Trigger Property="HasContent"
                                 Value="true">
                            <Setter Property="FocusVisualStyle"
                                    Value="{StaticResource CheckRadioFocusVisual}" />
                            <Setter Property="Padding"
                                    Value="4,0,0,0" />
                        </Trigger>
                        <Trigger Property="IsEnabled"
                                 Value="false">
                            <Setter Property="Foreground"
                                    Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>
<Grid>
    <StackPanel>
        <CheckBox x:Name="uiComboBox"
                  Content="Does not set the backing property, but responds to it.">
            <CheckBox.Style>
                <Style TargetType="{x:Type CheckBox}">
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type CheckBox}">
                                <BulletDecorator SnapsToDevicePixels="true"
                                                 Background="Transparent">
                                    <BulletDecorator.Bullet>
                                        <Microsoft_Windows_Themes:BulletChrome Background="{TemplateBinding Background}"
                                                                               BorderBrush="{TemplateBinding BorderBrush}"
                                                                               RenderMouseOver="{TemplateBinding IsMouseOver}"
                                                                               IsChecked="{Binding MyBoolean}">
                                        </Microsoft_Windows_Themes:BulletChrome>
                                    </BulletDecorator.Bullet>
                                    <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                                      HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                                      Margin="{TemplateBinding Padding}"
                                                      VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                                      RecognizesAccessKey="True" />
                                </BulletDecorator>
                                <ControlTemplate.Triggers>
                                    <Trigger Property="HasContent"
                                             Value="true">
                                        <Setter Property="FocusVisualStyle"
                                                Value="{StaticResource CheckRadioFocusVisual}" />
                                        <Setter Property="Padding"
                                                Value="4,0,0,0" />
                                    </Trigger>
                                    <Trigger Property="IsEnabled"
                                             Value="false">
                                        <Setter Property="Foreground"
                                                Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
                                    </Trigger>
                                </ControlTemplate.Triggers>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </CheckBox.Style>
        </CheckBox>

        <TextBlock Text="{Binding MyBoolean, StringFormat=Backing property:{0}}" />

        <CheckBox IsChecked="{Binding MyBoolean}"
                  Content="Sets the backing property." />
    </StackPanel>
</Grid>
</Window>
Run Code Online (Sandbox Code Playgroud)

后面的代码,带有我们支持的布尔值:

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
}
Run Code Online (Sandbox Code Playgroud)