Заголовок GroupBox в WPF глотает щелчки мышью? - PullRequest
41 голосов
/ 30 сентября 2008

Посмотрите на этот очень простой пример программы 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 расположена.

Может кто-нибудь повторить это? Почему это произошло, и есть ли способ обойти это?

Edit: установка BorderThickness GroupBox в 0 решает проблему, но, очевидно, он удаляет границу, поэтому он больше не похож на GroupBox.

Ответы [ 4 ]

23 голосов
/ 25 октября 2010

Ответ Яна Оукса складывает порядок вкладок так, что заголовок идет после содержимого. Можно изменить шаблон элемента управления так, чтобы граница не могла получить фокус.

Для этого измените шаблон так, чтобы 2-я и 3-я границы (обе в строке 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>
18 голосов
/ 30 сентября 2008

Кажется, что это небольшая ошибка в шаблоне элемента управления для GroupBox. Я нашел, отредактировав шаблон по умолчанию для GroupBox и переместив границу с именем 'Header' к последнему элементу в элементе Grid шаблонов элементов управления, проблема решается сама собой.

Причина в том, что один из других элементов Border с TemplateBinding of BorderBrush находился дальше в визуальном дереве и захватывал щелчок мыши, поэтому установка нулевого значения BorderBrush позволяла CheckBox правильно получать щелчок мыши.

Ниже приведен стиль для GroupBox. Он почти идентичен шаблону по умолчанию для элемента управления, за исключением элемента Border с именем «Заголовок», который теперь является последним дочерним элементом таблицы, а не вторым.

<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>
11 голосов
/ 14 сентября 2010

Альтернативное решение, которое я принял, заключается в реализации OnApplyTemplate в производном 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;
    }
  }
}
4 голосов
/ 30 сентября 2008

Если вы измените BorderBrush GroupBox, он работает!

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

Я знаю, что это побеждает цель, но она доказывает, в чем проблема!

...