简体   繁体   English

WPF中不规则的PNG按钮的单击事件

[英]Irregular PNG button's click event in WPF

I need an irregularly shaped button in WPF. 在WPF中我需要一个不规则形状的按钮。 I am doing it in this way using XAML: 我是这样用XAML做的:

<Button Name="toggleButton" Click="toggleButton_Click" Canvas.Left="177" Canvas.Top="0">
  <Button.Template>
    <ControlTemplate>
      <Image Source="ball.png" />
    </ControlTemplate>
  </Button.Template>
</Button>

My ball.png image is a PNG image with a ball with transparent area around it. 我的ball.png图像是一张PNG图像,周围有一个透明区域的球。 The button displays correctly, but Click event handler is executed even when I clik on the transparent part of the image. 该按钮显示正确,但即使我克隆图像的透明部分,也会执行Click事件处理程序。

Is there any way to create irregular buttons using transparent PNGs? 有没有办法使用透明PNG创建不规则按钮?

Thanks, Michal 谢谢,米哈尔

You can create a class that inherits from Image and overrides HitTestCore so that it does not respond to hit testing over the transparent parts of an image, and then use that class in your template instead of a plain Image. 您可以创建一个继承自Image并重写HitTestCore的类,这样它就不会响应图像透明部分的命中测试,然后在模板中使用该类而不是普通的Image。

Here is an example, although the code to check for transparent pixels isn't very robust since it makes some assumptions about the image source and pixel format. 这是一个例子,虽然检查透明像素的代码不是很强大,因为它对图像源和像素格式做了一些假设。 If you already have code to check for transparent pixels then you should plug that in instead. 如果您已经有代码来检查透明像素,那么您应该将其插入。

public class TransparentImage
    : Image
{
    protected override HitTestResult HitTestCore(
        PointHitTestParameters hitTestParameters)
    {
        // Get value of current pixel
        var source = (BitmapSource)Source;
        var x = (int)(hitTestParameters.HitPoint.X /
            ActualWidth * source.PixelWidth);
        var y = (int)(hitTestParameters.HitPoint.Y /
            ActualHeight * source.PixelHeight);
        var pixels = new byte[4];
        source.CopyPixels(new Int32Rect(x, y, 1, 1), pixels, 4, 0);
        // Check alpha channel
        if (pixels[3] < 10)
        {
            return new PointHitTestResult(this, hitTestParameters.HitPoint);
        }
        else
        {
            return null;
        }
    }

    protected override GeometryHitTestResult HitTestCore(
        GeometryHitTestParameters hitTestParameters)
    {
        // Do something similar here, possibly checking every pixel within
        // the hitTestParameters.HitGeometry.Bounds rectangle
        return base.HitTestCore(hitTestParameters);
    }
}

Michal, I wouldn't create a real "button". Michal,我不会创建一个真正的“按钮”。 Just go to blend, get your image as an image brush into a rectangle, right-click make it a Button. 只需进行混合,将图像作为图像画笔变成矩形,右键单击使其成为按钮。 If you are using Blend 4, this will generate the appropriate states in the Visual State Manager. 如果您使用Blend 4,这将在Visual State Manager中生成适当的状态。 You can get your mouse over, pressed, etc., to look like a button. 您可以将鼠标悬停,按下等,看起来像一个按钮。 Even disabled state. 甚至禁用状态。

Here's an example: 这是一个例子:

<Window.Resources>
        <Style x:Key="CrazyButtonStyle" TargetType="{x:Type Button}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Grid>
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Normal">
                                        <Storyboard>
                                            <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" Storyboard.TargetName="path">
                                                <EasingColorKeyFrame KeyTime="0" Value="#FFBEBEBE"/>
                                            </ColorAnimationUsingKeyFrames>
                                            <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)" Storyboard.TargetName="path">
                                                <EasingColorKeyFrame KeyTime="0" Value="#FF919191"/>
                                            </ColorAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="MouseOver">
                                        <Storyboard>
                                            <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)" Storyboard.TargetName="path">
                                                <EasingColorKeyFrame KeyTime="0" Value="#FF782B2B"/>
                                            </ColorAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Pressed">
                                        <Storyboard>
                                            <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)" Storyboard.TargetName="path">
                                                <EasingColorKeyFrame KeyTime="0" Value="#FF1D0C0C"/>
                                            </ColorAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Disabled">
                                        <Storyboard>
                                            <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)" Storyboard.TargetName="path">
                                                <EasingColorKeyFrame KeyTime="0" Value="#FF720505"/>
                                            </ColorAnimationUsingKeyFrames>
                                            <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" Storyboard.TargetName="path">
                                                <EasingColorKeyFrame KeyTime="0" Value="#FF6E0000"/>
                                            </ColorAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <Path x:Name="path" Data="M95.5,33.499981 C71.500031,31.499967 76.5,68.5 76.5,68.5 L112.5,75.500276 107.5,92.500393 144.5,105.50048 152.5,79.500301 132.5,63.50019 154.5,54.500128 173.5,68.500225 168.5,87.500356 172.5,97.500425 185.5,96.500418 197.12084,75.753906 200.12084,44.753692 176.5,34.49999 143.5,32.499975 142.5,13.499841 130.5,28.499946 137.5,41.500036 135.5,51.500106 117.5,52.500113 99.5,54.500126 116.5,39.500022 z" Stretch="Fill" Stroke="{x:Null}">
                                <Path.Fill>
                                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                        <GradientStop Color="Black" Offset="0"/>
                                        <GradientStop Color="White" Offset="1"/>
                                    </LinearGradientBrush>
                                </Path.Fill>
                            </Path>
                            <ContentPresenter HorizontalAlignment="Right" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Top" Margin="0,24.52,18.715,0"/>
                        </Grid>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsFocused" Value="True"/>
                            <Trigger Property="IsDefaulted" Value="True"/>
                            <Trigger Property="IsMouseOver" Value="True"/>
                            <Trigger Property="IsPressed" Value="True"/>
                            <Trigger Property="IsEnabled" Value="False"/>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>

Now use the button as follows: 现在使用按钮如下:

<Button Content="This is my crazy button" Style="{DynamicResource CrazyButtonStyle}"/>

I know this is not using the transparent png as the button but it would be a much better alternative if you have the ability to convert the png to xaml. 我知道这不是使用透明的png作为按钮,但如果你有能力将png转换为xaml,它将是一个更好的选择。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM