Click here to Skip to main content
15,917,645 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
https://ibb.co/jkHJ1F -link to image
I have a hexagon Image for my button as in picture. I want to remove click from corner edges, and to be clicked only when clicking on picture. I have tried few solution, by my clickable grid is always squared, and that's why my button click area is bigger then my picture.

What I have tried:

<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>
Posted
Updated 7-Mar-17 22:35pm

Here is a quick solution that I've thrown together. It honors the clipping requirements and can also support multiple states - MouseOver, MouseDown, etc...
XAML
<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>
 
Share this answer
 
Comments
Wannabe Pro 7-Mar-17 9:03am    
Thanks, ill try that, i think it will work. Have done something similar, drawn hexagon path over image and set it to be clickable and transparent, and image to be visible but not clickable, and that solve problem, but your aproach seems to be valid :)
Here is answer that i've done, in case someone will need something similar in future.
1.rst i have made customControl deriving from Button. And inside i have 2 DependencyProperties just to change Image on click.



C#
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));



Inside of Generic.xaml i havse structured code like this ( This works for me and my project).

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


Trick was to make path (Hexagon) that will be exactly same as my pictures, and set that path to be clickable but transparent, and picture to be visible but not clickable, and that solve my problem, now i have fully functional Hexagon button.

Sample of code in main window, just to show purpose.

HTML
<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>
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900