WPF GroupBox header swallows mouse clicks?

Take a look at this very simple example of a WPF program:

<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> 

So, I have a GroupBox whose title is CheckBox. We all did something like this: usually you bind the contents of the GroupBox in such a way that it is disabled when the CheckBox is not checked.

However, when I launch this application and click on CheckBox, I find that sometimes my mouse clicks are swallowed and the status of CheckBox does not change. If I'm right, this is when I click on the exact row of pixels that the GroupBox top border is on.

Can anyone repeat this? Why is this happening, and is there a way around it?

Edit: setting the GroupBox BorderThickness parameter to 0 solves the problem, but obviously it removes the border, so it no longer looks like a GroupBox.

+41
checkbox wpf groupbox
Sep 30 '08 at 6:32
source share
4 answers

This seems to be a subtle mistake in the management template for GroupBox. I found by editing the default template for GroupBox and moving the border with the title "Title" to the last element in the control element of the lattice element, the problem solves itself.

The reason is that one of the other Border elements with TemplateBinding BorderBrush was even lower in the visual tree and was captured with a mouse click, so CheckBox was allowed to correctly receive the mouse click to set BorderBrush to null.

The following is the style for GroupBox. It is almost identical to the default template for the control, with the exception of the Border element named "Header", which is now the last child of the Grid, and not the second.

 <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> 
+18
Sep 30 '08 at 10:50
source share

Ian Oakes answer picks up the tab so that the title appears after the content. It is possible to change the control pattern so that the border cannot receive focus.

To do this, change the template so that the 2nd and 3rd borders (as in Grid Row 1) have IsHitTestVisible=false

Full template below

 <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> 
+23
Oct 25 2018-10-10
source share

An alternative solution that I made is to implement OnApplyTemplate in a derived GroupBox:

 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; } } } 
+11
Sep 14 '10 at 14:37
source share

If you change GroupBox BorderBrush, it works!

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

I know this defeats the goal, but it proves where the problem is!

+4
Sep 30 '08 at 6:50
source share



All Articles