2010-08-28 22 views
6

Necesito un botón de forma irregular en WPF. Lo estoy haciendo de esta manera el uso de XAML:Evento de clic del botón Irregular PNG en WPF

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

imagen Mi ball.png es una imagen PNG con una pelota con zona transparente alrededor de ella. El botón se muestra correctamente, pero el controlador de eventos Click se ejecuta incluso cuando hago clic en la parte transparente de la imagen.

¿Hay alguna manera de crear botones irregulares utilizando PNG transparentes?

Gracias, Michal

Respuesta

11

Puede crear una clase que herede de Image e invalide HitTestCore para que no responda a la prueba de aciertos sobre las partes transparentes de una imagen, y luego use esa clase en su plantilla en lugar de una imagen simple.

Aquí hay un ejemplo, aunque el código para verificar píxeles transparentes no es muy robusto ya que hace algunas suposiciones sobre la fuente de la imagen y el formato de píxeles. Si ya tiene un código para verificar los píxeles transparentes, debe conectarlo en su lugar.

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

Michal, yo no crear un "botón" real. Solo tiene que ir a fusionar, obtener su imagen como un pincel de imagen en un rectángulo, hacer clic con el botón derecho en un Botón. Si está utilizando Blend 4, esto generará los estados apropiados en el Visual State Manager. Puede colocar el mouse sobre, presionar, etc., para que parezca un botón. Incluso estado deshabilitado.

He aquí un ejemplo:

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

Ahora utilice el botón de la siguiente manera:

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

Sé que esto no está utilizando el png transparente como el botón, pero sería una alternativa mucho mejor si usted tiene la capacidad de convertir el png a xaml.

+0

Gracias, Pero no tengo Blend. Sin embargo, creo que no resolvería mi problema porque WPF todavía usaría el área rectangular para la prueba de impacto, sin respetar los píxeles transparentes de mi imagen. ¿Estoy en lo cierto? Resolví el problema escribiendo un método que comprueba si se golpeó un píxel transparente de la imagen en el controlador de eventos MouseLeftButtonDown. Pero me pregunto si hay una solución mejor y más general. –

+0

Michal, ese puede ser el caso con la imagen, todavía no estoy seguro, pero usando una ruta o geometría puedes hacerlo mucho más simple. Estoy editando mi respuesta para ofrecerte un ejemplo completo. –

Cuestiones relacionadas