41

看看这个非常简单的示例 WPF 程序:

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">

    <GroupBox>
        <GroupBox.Header>
            <CheckBox Content="Click Here"/>
        </GroupBox.Header>
    </GroupBox>
</Window>

所以我有一个GroupBox,它的标题是一个CheckBox。我们都做过这样的事情——通常你绑定 GroupBox 的内容,这样当 CheckBox 未选中时它就会被禁用。

但是,当我运行此应用程序并单击 CheckBox 时,我发现有时我的鼠标单击被吞下并且 CheckBox 的状态没有改变。如果我是对的,那就是当我单击 GroupBox 的顶部边框所在的确切像素行时。

有人可以复制这个吗?为什么会发生这种情况,有没有办法解决它?

编辑:将 GroupBox 的 BorderThickness 设置为 0 可以解决问题,但显然它会删除边框,因此它看起来不再像 GroupBox。

4

4 回答 4

24

伊恩奥克斯回答塞满了标签顺序,使得标题出现在内容之后。可以修改控件模板,使边框无法获得焦点。

为此,请修改模板,使第 2 和第 3 个边框(都在 Grid Row 1 中)具有IsHitTestVisible=false

下面的完整模板

<BorderGapMaskConverter x:Key="GroupBoxBorderGapMaskConverter" />

<Style x:Key="{x:Type GroupBox}" TargetType="{x:Type GroupBox}">
    <Setter Property="Control.BorderBrush" Value="#FFD5DFE5" />
    <Setter Property="Control.BorderThickness" Value="1" />
    <Setter Property="Control.Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type GroupBox}">
                <Grid SnapsToDevicePixels="True">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="6" />
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="6" />
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="*" />
                        <RowDefinition Height="6" />
                    </Grid.RowDefinitions>
                    <Border Name="Header" Padding="3,1,3,0" Grid.Row="0" Grid.RowSpan="2" Grid.Column="1">
                        <ContentPresenter ContentSource="Header" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
                    </Border>
                    <Border CornerRadius="4" Grid.Row="1" Grid.RowSpan="3" Grid.Column="0" Grid.ColumnSpan="4" BorderThickness="{TemplateBinding Control.BorderThickness}" BorderBrush="#00FFFFFF" Background="{TemplateBinding Control.Background}" IsHitTestVisible="False" />
                    <ContentPresenter Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" Margin="{TemplateBinding Control.Padding}" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}"/>
                    <Border CornerRadius="4" Grid.Row="1" Grid.RowSpan="3" Grid.ColumnSpan="4" BorderThickness="{TemplateBinding Control.BorderThickness}" BorderBrush="#FFFFFFFF" IsHitTestVisible="False">
                        <UIElement.OpacityMask>
                            <MultiBinding Converter="{StaticResource GroupBoxBorderGapMaskConverter}" ConverterParameter="7">
                                <Binding ElementName="Header" Path="ActualWidth" />
                                <Binding Path="ActualWidth" RelativeSource="{RelativeSource Self}" />
                                <Binding Path="ActualHeight" RelativeSource="{RelativeSource Self}" />
                            </MultiBinding>
                        </UIElement.OpacityMask>
                        <Border BorderThickness="{TemplateBinding Control.BorderThickness}" BorderBrush="{TemplateBinding Control.BorderBrush}" CornerRadius="3">
                            <Border BorderThickness="{TemplateBinding Control.BorderThickness}" BorderBrush="#FFFFFFFF" CornerRadius="2" />
                        </Border>
                    </Border>                        
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
于 2010-10-25T12:28:45.433 回答
19

这似乎是 GroupBox 控件模板中的一个细微错误。我发现通过编辑 GroupBox 的默认模板并将名为“Header”的边框移动到控件模板 Grid 元素中的最后一项,问题自行解决。

原因是具有 BorderBrush 的 TemplateBinding 的其他 Border 元素之一在可视树中更靠下,并且正在捕获鼠标单击,这就是将 BorderBrush 设置为 null 允许 CheckBox 正确接收鼠标单击的原因。

下面是 GroupBox 的结果样式。它与控件的默认模板几乎相同,除了名为“Header”的 Border 元素,它现在是 Grid 的最后一个子元素,而不是第二个。

<BorderGapMaskConverter x:Key="BorderGapMaskConverter"/>

<Style x:Key="GroupBoxStyle1" TargetType="{x:Type GroupBox}">
    <Setter Property="BorderBrush" Value="#D5DFE5"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type GroupBox}">
                <Grid SnapsToDevicePixels="true">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="*"/>
                        <RowDefinition Height="6"/>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="6"/>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="6"/>
                    </Grid.ColumnDefinitions>
                    <Border Grid.Column="0" Grid.ColumnSpan="4" Grid.Row="1" Grid.RowSpan="3" Background="{TemplateBinding Background}" BorderBrush="Transparent" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="4"/>
                    <ContentPresenter Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="2"/>
                    <Border Grid.ColumnSpan="4" Grid.Row="1" Grid.RowSpan="3" BorderBrush="White" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="4">
                        <Border.OpacityMask>
                            <MultiBinding Converter="{StaticResource BorderGapMaskConverter}" ConverterParameter="7">
                                <Binding Path="ActualWidth" ElementName="Header"/>
                                <Binding Path="ActualWidth" RelativeSource="{RelativeSource Self}"/>
                                <Binding Path="ActualHeight" RelativeSource="{RelativeSource Self}"/>
                            </MultiBinding>
                        </Border.OpacityMask>
                        <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="3">
                            <Border BorderBrush="White" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="2"/>
                        </Border>
                    </Border>
                    <Border x:Name="Header" Grid.Column="1" Grid.Row="0" Grid.RowSpan="2" Padding="3,1,3,0">
                        <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" ContentSource="Header" RecognizesAccessKey="True"/>
                    </Border>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
于 2008-09-30T10:50:29.290 回答
11

我提出的另一种解决方案是在派生的 GroupBox 中实现 OnApplyTemplate:

public override void OnApplyTemplate()
{
  base.OnApplyTemplate();
  if (Children.Count == 0) return;

  var grid = GetVisualChild(0) as Grid;
  if (grid != null && grid.Children.Count > 3)
  {
    var bd = grid.Children[3] as Border;
    if (bd != null)
    {
      bd.IsHitTestVisible = false;
    }
  }
}
于 2010-09-14T14:37:01.333 回答
4

如果您更改 GroupBox 的 BorderBrush,它就可以工作!

<GroupBox BorderBrush="{x:Null}">

我知道这违背了目标,但它确实证明了问题所在!

于 2008-09-30T06:50:43.173 回答