WPF中CheckBox的自定义鼠标点击区域

5
我为复选框设置了自定义样式,它的未选状态如下图所示: Image of an expander with a border around it and dog-ear signifying a checkbox 当复选框被“选中”时,应该看起来像这样: Image of an expander with a border around it and dog-ear highlighted green. 我想让用户只能通过点击右上角的复选标记来切换它。现在,无论用户在框内或展开器内的哪个位置单击,复选框都会切换。
是否有一种方法可以将鼠标单击区域设置为仅在右上角的复选标记周围切换复选框?
以下是我目前的代码:
<SolidColorBrush x:Key="SelectedCheckboxColor" Color="Green"/>
<SolidColorBrush x:Key="UnselectedCheckboxColor" Color="Gray"/>
<Style x:Key="SelectBoxCheckBoxStyle" TargetType="{x:Type CheckBox}">
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type CheckBox}">
                <Border x:Name="border" BorderThickness="2" BorderBrush="#FF666666">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="Auto"/>
                        </Grid.ColumnDefinitions>
                        <ContentPresenter Grid.Column="0" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        <Image x:Name="image" Width="24" Height="24" Grid.Column="1" VerticalAlignment="Top" Source="Resources/checkbox-dogear-unchecked.png"/>
                    </Grid>

                    <!--<BulletDecorator Background="Transparent" SnapsToDevicePixels="true">
                        <BulletDecorator.Bullet>
                            <Themes:BulletChrome BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" IsChecked="{TemplateBinding IsChecked}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}"/>
                        </BulletDecorator.Bullet>
                    </BulletDecorator>-->
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="HasContent" Value="true">
                        <Setter Property="Padding" Value="4,0,0,0"/>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                    </Trigger>
                    <Trigger Property="IsChecked" Value="True">
                        <Setter Property="Source" TargetName="image" Value="Resources/checkbox-dogear-checked.png"/>
                        <Setter Property="BorderBrush" TargetName="border" Value="#FF00D212"/>
                    </Trigger>
                    <Trigger Property="IsMouseCaptureWithin" Value="True">
                        <Setter Property="BorderBrush" TargetName="border" Value="#FFA200FF"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

3
我会将复选框样式化为三角形部分,而将控件的其余部分制作成其他元素,例如“ContentControl”。我的翻译是否符合您的要求? - Rachel
2个回答

3

我认为Rachel的回答是正确的方式,因为这不是我之前尝试过的事情,所以我想尝试一下(欢迎批评)。

由于我没有你使用的图片,所以我用了一个

        <SolidColorBrush x:Key="SelectedCheckboxColor" Color="#FF00D212"/>
        <SolidColorBrush x:Key="UnselectedCheckboxColor" Color="Gray"/>
        <Style TargetType="{x:Type CheckBox}">
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type CheckBox}">
                        <Border x:Name="border" BorderThickness="2" BorderBrush="{StaticResource ResourceKey=UnselectedCheckboxColor}">
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*"/>
                                    <ColumnDefinition Width="Auto"/>
                                </Grid.ColumnDefinitions>
                                <ContentPresenter Grid.Column="0" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>

                                <!-- Tickbox Mockup -->
                                <Polygon x:Name="checkPoly" Points="0,0 24,24 24,0 0,0" Stroke="Purple" StrokeThickness="0" Width="24" Height="24" 
                                         VerticalAlignment="Top" HorizontalAlignment="Right" Fill="{StaticResource ResourceKey=UnselectedCheckboxColor}" />
                                <Path Stroke="White" Data="M 6,6 L 9, 9 L 16,2" StrokeThickness="2" Margin="0, 1, 1, 0"
                                      VerticalAlignment="Top" HorizontalAlignment="Right" />
                            </Grid>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="HasContent" Value="true">
                                <Setter Property="Padding" Value="4,0,0,0"/>
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                            </Trigger>
                            <Trigger Property="IsChecked" Value="True">
                                <Setter Property="Fill" TargetName="checkPoly" Value="{StaticResource ResourceKey=SelectedCheckboxColor}"/>
                                <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource ResourceKey=SelectedCheckboxColor}" />
                            </Trigger>
                            <Trigger Property="IsMouseCaptureWithin" Value="True">
                                <Setter Property="BorderBrush" TargetName="border" Value="#FFA200FF"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

接着,将此内容与一个已填充一些测试内容的Expander一起放在了一个ContentControl中进行托管:

<ContentControl Width="100" Height="100">
        <Grid>
            <!-- Make sure the Checkbox is the foremost element -->
            <CheckBox Grid.ZIndex="99" />
            <Expander Header="Test" >
                <StackPanel>
                    <TextBlock Text="Test" />
                    <TextBlock Text="Test" />
                    <TextBlock Text="Test" />
                </StackPanel>
            </Expander>
        </Grid>
</ContentControl>

这是一个例子: enter image description here 具体效果因使用的Control而异。需要注意的一点是,即使点击边框,复选框依然会切换 - 如果这是个问题,您可以从CheckBox中删除边框宽度,将其放在ContentControl上,并使用一些绑定来连接CheckBox中的Border画笔颜色。

我最终还是用多边形来绘制了勾选区域,因为我想能更容易地改变颜色(微调和其他操作)。为了快速制作一个供审查的原型,我创建了一个UserControl模拟了我想要的行为,包括只有当鼠标悬停在上面时才显示。但是,我确实希望最终将其转换为复选框,以利用其内置的无障碍功能。 - Spen-ZAR

-1
也许你可以为复选框设置一个 on_click 监听器,然后检查鼠标位置,只有当鼠标在正确的相对边界内时才改变复选框状态?

我开始思考,也许试图把方形钉子塞进圆孔是个坏主意。我可能需要将其转换为自定义控件。不过,仅为了那一个功能,这有点傻。 - Spen-ZAR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接