Wannabe Pro Ответов: 2

Как сделать так, чтобы сетка кнопок соответствовала моему шестиугольному изображению в WPF-XAML


https://ibb.co/jkHJ1F - ссылка на изображение
У меня есть изображение шестиугольника для моей кнопки, как на картинке. Я хочу удалить щелчок с угловых краев и нажимать только при нажатии на картинку. Я пробовал несколько решений, моя кликабельная сетка всегда квадратная, и именно поэтому моя область нажатия кнопки больше, чем моя картинка.

Что я уже пробовал:

<pre lang="HTML"><ControlTemplate TargetType="{x:Type Button}">
                    <Grid x:Name="LayoutGrid"
                          SnapsToDevicePixels="true">
                        <ContentPresenter x:Name="contentPresenter"
                                          Focusable="True"
                                          HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                          RecognizesAccessKey="True"
                                          SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                          VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                          Margin="0"
                                          IsHitTestVisible="True"
                                          ToolTip="Button">
                            <ContentPresenter.Content>
                                <Image Source="/WpfApp3;component/Images/hexagonImage.png"
                                       Stretch="None" />
                            </ContentPresenter.Content>
                        </ContentPresenter>
                        <Label Content="Label"
                               HorizontalAlignment="Center"
                               VerticalAlignment="Center"
                               Margin="60,130,60,51"
                               Width="180"
                               Height="40"
                               HorizontalContentAlignment="Center"
                               RenderTransformOrigin="0.428,-0.075"
                               FontSize="18"
                               FontFamily="Arial Narrow"
                               IsHitTestVisible="False" />
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsDefaulted"
                                 Value="true" />
                        <Trigger Property="IsMouseOver"
                                 Value="true" />
                        <Trigger Property="IsPressed"
                                 Value="true" />
                        <Trigger Property="IsEnabled"
                                 Value="false">
                            <Setter Property="TextElement.Foreground"
                                    TargetName="contentPresenter"
                                    Value="{StaticResource Button.Disabled.Foreground}" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>

2 Ответов

Рейтинг:
18

Graeme_Grant

Вот быстрое решение, которое я собрал вместе. Он соблюдает требования к отсечению, а также может поддерживать несколько состояний-наведение мыши, наведение мыши и т. д...

<Window 

    x:Class="WpfWindows.Window2"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    mc:Ignorable="d" WindowStartupLocation="CenterOwner"

    Title="Hex Button" Height="300" Width="300">
    <Window.Resources>
        <Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
            <Setter Property="Background" Value="Black"/>
            <Setter Property="HorizontalAlignment" Value="Center"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Grid VerticalAlignment="{TemplateBinding VerticalContentAlignment}"

                              HorizontalAlignment="{TemplateBinding HorizontalAlignment}">
                            <Viewbox Height="75" Width="75">
                                <Path Data="M2,88.602540 152,2 302,88.602540 v173.215081 L152,350.410161 2,261.807621 z"

                                      Fill="RoyalBlue"/>
                            </Viewbox>

                            <ContentPresenter VerticalAlignment="{TemplateBinding VerticalContentAlignment}"

                                          HorizontalAlignment="{TemplateBinding HorizontalAlignment}"/>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Viewbox>
            <TextBlock Text="Window2"/>
        </Viewbox>
        <Button Grid.Row="1" Style="{StaticResource ButtonStyle}"

                Margin="10" HorizontalAlignment="Center"

                Content="BACK" Click="Back_Click"/>
    </Grid>
</Window>


Wannabe Pro

Спасибо, я попробую, думаю, это сработает. Сделали что-то подобное, нарисовали шестиугольник пути над изображением и установили его кликабельным и прозрачным, а изображение видимым, но не кликабельным, и это решает проблему, но ваш подход кажется действительным :)

Рейтинг:
1

Wannabe Pro

Вот ответ, который я сделал, на случай, если кому-то понадобится что-то подобное в будущем.
1.сначала я создал пользовательский элемент управления, вытекающие из кнопки. А внутри у меня есть 2 DependencyProperties только для того, чтобы изменить изображение по щелчку.



public ImageSource Image
            {
                get { return (ImageSource)GetValue(ImageProperty); }
                set { SetValue(ImageProperty, value); }
            }
           public static readonly DependencyProperty ImageProperty =
                DependencyProperty.Register("Image", typeof(ImageSource), typeof(CustomControl), 
                    new FrameworkPropertyMetadata(default(ImageSource), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
    
            public ImageSource NewImage
            {
                get { return (ImageSource)GetValue(NewImageProperty); }
                set { SetValue(NewImageProperty, value); }
            }

            public static readonly DependencyProperty NewImageProperty =
                DependencyProperty.Register("NewImage", typeof(ImageSource), typeof(CustomControl),
                     new FrameworkPropertyMetadata(default(ImageSource), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));



Внутри Generic. xaml у меня есть структурированный код, подобный этому ( это работает для меня и моего проекта).

<ResourceDictionary

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:local="clr-namespace:wpf.core">
   

    <Style TargetType="{x:Type local:CustomControl}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Grid HorizontalAlignment="Center"
                          VerticalAlignment="Center"
                          Width="{Binding ActualWidth, ElementName=image}"
                          Height="{Binding ActualHeight, ElementName=image}">
                        
                        <Image x:Name="image"
                               IsHitTestVisible="False"
                               Stretch="None"
                               VerticalAlignment="Center"
                               HorizontalAlignment="Center">
                            <Image.Style>
                                <Style TargetType="{x:Type Image}">
                                    <Setter Property="Source"
                                            Value="{Binding Image, RelativeSource={RelativeSource TemplatedParent}}" />
                                    <Style.Triggers>
                                        <DataTrigger Binding="{Binding IsPressed, RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
                                                     Value="true">
                                            <Setter Property="Source"
                                                    Value="{Binding NewImage, RelativeSource={RelativeSource TemplatedParent}}" />
                                        </DataTrigger>
                                    </Style.Triggers>
                                </Style>
                            </Image.Style>
                        </Image>
                        <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}"

                                          Content="{TemplateBinding Content}"

                                          ContentStringFormat="{TemplateBinding ContentStringFormat}"

                                          Height="48"

                                          IsHitTestVisible="False"

                                          Margin="38.667,0,38,46.666"

                                          VerticalAlignment="Bottom"

                                          HorizontalAlignment="Center"

                                          MaxHeight="48"

                                          MaxWidth="188" />
                        <Path Data="M2,88.60254L152,2 302,88.60254 302,261.817621 152,350.410161 2,261.807621z"

                              RenderTransformOrigin="0.5,0.5"

                              Stretch="Fill"

                              Fill="Transparent"

                              Focusable="True"

                              StrokeThickness="0"

                              Margin="25.333,-24.001,25.333,-23.999"

                              VerticalAlignment="Stretch"

                              Opacity="0">
                            <Path.RenderTransform>
                                <TransformGroup>
                                    <ScaleTransform />
                                    <SkewTransform />
                                    <RotateTransform Angle="90" />
                                    <TranslateTransform />
                                </TransformGroup>
                            </Path.RenderTransform>
                        </Path>
                    </Grid>

                    <ControlTemplate.Triggers>
                        <Trigger Property="IsPressed"

                                 Value="true">
                            <Setter Property="Foreground"

                                    Value="White" />
                        </Trigger>

                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>


Трюк состоял в том, чтобы сделать путь (шестиугольник), который будет точно таким же, как мои фотографии, и установить этот путь, чтобы он был кликабельным, но прозрачным, а изображение было видимым, но не кликабельным, и это решило мою проблему, теперь у меня есть полностью функциональная кнопка шестиугольника.

Пример кода в главном окне, просто чтобы показать цель.

<Grid>
        <cc:CustomControl Image="/WpfApp3;component/Images/hexPicture1.png"

                          NewImage="/WpfApp3;component/Images/hexPicture2.png"

                          ToolTip="Button"

                          Content="Some content"

                          FontFamily="Arial narrow"

                          FontSize="18"/>
    </Grid>