2010-08-28 2 views
6

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

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

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

ответ

11

Вы можете создать класс, который наследует от изображения и переопределяет 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

Михал, Я бы не создать реальную "кнопку". Просто перейдите в blend, получите изображение как кисть изображения в прямоугольник, щелкните правой кнопкой мыши, чтобы сделать его кнопкой. Если вы используете 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.

+0

Спасибо, Но у меня нет Blend. Однако я думаю, что это не решит мою проблему, потому что WPF по-прежнему будет использовать прямоугольную область для тестирования ударов, не соблюдая прозрачные пиксели моего изображения. Я прав? Я решил проблему, написав метод, который проверяет, попал ли прозрачный пиксель изображения в обработчик события MouseLeftButtonDown. Но мне интересно, есть ли лучшее, более общее решение. –

+0

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

Смежные вопросы