Нерегулярное событие нажатия кнопки PNG в WPF - PullRequest
6 голосов
/ 29 августа 2010

Мне нужна кнопка неправильной формы в WPF.Я делаю это таким образом, используя XAML:

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

Мое изображение ball.png - это изображение PNG с шариком с прозрачной областью вокруг него.Кнопка отображается правильно, но обработчик события Click выполняется, даже когда я кликаю по прозрачной части изображения.

Есть ли способ создания неправильных кнопок с использованием прозрачных PNG?

Спасибо, Михал

Ответы [ 2 ]

12 голосов
/ 29 августа 2010

Вы можете создать класс, который наследует от Image и переопределяет HitTestCore , чтобы он не реагировал на тестирование попадания по прозрачным частям изображения, а затем использовать этот класс в шаблоне вместо простого Образ.

Вот пример, хотя код для проверки прозрачных пикселей не очень надежен, поскольку он делает некоторые предположения об источнике изображения и формате пикселей. Если у вас уже есть код для проверки прозрачных пикселей, вы должны вместо этого подключить его.

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);
    }
}
1 голос
/ 29 августа 2010

Михал, Я бы не стал создавать настоящую «кнопку». Просто смешайте, поместите изображение в виде кисти в прямоугольник, щелкните правой кнопкой мыши, чтобы сделать его кнопкой. Если вы используете Blend 4, это создаст соответствующие состояния в Visual State Manager. Вы можете навести курсор мыши, нажать и т. Д., Чтобы они выглядели как кнопка. Даже отключенное состояние.

Вот пример:

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

Теперь используйте кнопку следующим образом:

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

Я знаю, что в качестве кнопки не используется прозрачный png, но было бы гораздо лучше, если бы у вас была возможность конвертировать png в xaml.

...