Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Irregular PNG button's click event in WPF

I need an irregularly shaped button in WPF. I am doing it in this way using 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. The button displays correctly, but Click event handler is executed even when I clik on the transparent part of the image.

Is there any way to create irregular buttons using transparent PNGs?

Thanks, Michal

like image 974
Michał Fronczyk Avatar asked Aug 28 '10 20:08

Michał Fronczyk


1 Answers

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.

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);
    }
}
like image 176
Quartermeister Avatar answered Sep 24 '22 14:09

Quartermeister