2010-04-29 10 views
13

Quiero crear una plantilla de botón simple con una imagen y texto dentro de ella. Pero quiero mantener el aspecto y la sensación del botón del sistema.Plantilla de botón personalizado en WPF

¿Cómo lo creo, paso a paso?

P.S .: Ya lo he intentado con CustomControl en WPF y BasedOn propiedad.

Respuesta

33

Puede hacerlo fácilmente con un estilo y adjunta la propiedad:

<ResourceDictionary 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:ap="clr-namespace:MyProject.Namespace.Path.To.ButtonProperties"> 
    ... 
    <Style x:Key="ImageButton" TargetType="Button"> 
     <Setter Property="ContentTemplate"> 
      <Setter.Value> 
       <DataTemplate> 
        <StackPanel Orientation="Horizontal"> 
         <Image Source="{Binding Path=(ap:ButtonProperties.Image), RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}"></Image> 
         <ContentPresenter Content="{Binding Path=Content, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}"></ContentPresenter> 
        </StackPanel> 
       </DataTemplate> 
      </Setter.Value> 
     </Setter> 
    </Style> 
    ... 
</ResourceDictionary> 

y

public class ButtonProperties 
{ 
    public static ImageSource GetImage(DependencyObject obj) 
    { 
     return (ImageSource)obj.GetValue(ImageProperty); 
    } 

    public static void SetImage(DependencyObject obj, ImageSource value) 
    { 
     obj.SetValue(ImageProperty, value); 
    } 

    public static readonly DependencyProperty ImageProperty = 
     DependencyProperty.RegisterAttached("Image", typeof(ImageSource), typeof(ButtonProperties), new UIPropertyMetadata((ImageSource)null)); 
} 

A continuación, en el marcado:

<Button Style="{StaticResource ImageButton}" ap:ButtonProperties.Image="{StaticResource MyImage}" Content="Test"> 
</Button> 

En este ejemplo se ve bastante horrible, pero se puede cambiar fácilmente el StackPanel a un Grid o algo similar a restringir la proporción de la imagen. El uso del ContentPresenter le permite conservar el comportamiento de un botón que le permite colocar UIElement dentro y conservar el soporte de comandos, etc.

+0

Gracias. Lo intenté con la Plantilla de Control pero no tuve éxito. – Archie

+0

No debería necesitar usar una plantilla de control. Hice todo eso solo usando la clase de botón WPF estándar. – jeffora

+0

¡Esto es bueno! Al enlazar contra las propiedades adjuntas, las plantillas se pueden personalizar dinámicamente. ¡Muchas gracias! – henon

6

fin he creado un botón con la imagen + texto en su interior:

A continuación se muestra el código completo:

Paso 1: Crear un nuevo control de usuario llamado: ImageButtonUC

<UserControl Name="ImageButton" x:Class="WpfApp.ImageButtonUC" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
    <Grid> 
     <Button VerticalAlignment="Top" Width="100" Height="25" Click="button_Click"> 
      <Button.Content> 
       <StackPanel Orientation="Horizontal"> 
        <Image Width="16" Height="16" Margin="5,0,5,0" Source="{Binding ElementName=ImageButton, Path=Image}"/> 
        <TextBlock Text="{Binding ElementName=ImageButton, Path=Text}"/> 
       </StackPanel> 
      </Button.Content> 
     </Button> 
    </Grid> 
</UserControl> 

Paso 2: Editar ImageButtonUC.xaml.cs

public partial class ImageButtonUC : UserControl 
    { 
     public event RoutedEventHandler Click; 

     public ImageButtonUC() 
     { 
      InitializeComponent(); 

     } 

     public string Text 
     { 
      get { return (string)GetValue(TextProperty); } 
      set { SetValue(TextProperty, value); } 
     } 


     public static readonly DependencyProperty TextProperty = 
      DependencyProperty.Register("Text", typeof(string), typeof(ImageButtonUC), new UIPropertyMetadata("")); 

     public ImageSource Image 
     { 
      get { return (ImageSource)GetValue(ImageProperty); } 
      set { SetValue(ImageProperty, value); } 
     } 

     public static readonly DependencyProperty ImageProperty = 
      DependencyProperty.Register("Image", typeof(ImageSource), typeof(ImageButtonUC), new UIPropertyMetadata(null)); 


     private void button_Click(object sender, RoutedEventArgs e) 
     { 

      if (null != Click) 

       Click(sender, e); 

     } 

    } 

Paso 3: En el XAML que pueda usarlo de esta manera: Añadir el espacio de nombres como

xmlns:Local="clr-namespace:WpfApp" 

y utilizarlo como:

<Local:ImageButtonUC x:Name="buttonImg" Width="100" Margin="10,0,10,0" Image="/WpfApp;component/Resources/Img.bmp" Text="Browse..." Click="buttonImg_Click"/> 

Nota: Mi imagen esta ubicado en la carpeta Recursos aquí

Referencia:

http://blogs.msdn.com/knom/archive/2007/10/31/wpf-control-development-3-ways-to-build-an-imagebutton.aspx

+0

La desventaja sin embargo es que el control no se deriva de botón. Por lo tanto, si desea vincular un Comando, por ejemplo, deberá agregar otra propiedad de dependencia. Pero si solo quieres una imagen y un texto que funcione bien. – Josh

2

Si no desea escribir ningún código subyacente, hay otra forma de hacerlo (inspirado por la respuesta de Jeffora). Puede utilizar el campo Contenido del control para poner el URI de la imagen que desea ver en su botón:

<Button Content="https://www.google.com/images/srpr/logo3w.png" Height="100" Width="200" Style="{DynamicResource ButtonStyle1}"/> 

Y a continuación, puede editar el estilo de botón predeterminado a tener este aspecto:

<Style> 
... 
<Setter Property="Template"> 
    <Setter.Value> 
     <ControlTemplate TargetType="{x:Type Button}"> 
      <Microsoft_Windows_Themes:ButtonChrome x:Name="Chrome" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}" RenderDefaulted="{TemplateBinding IsDefaulted}" SnapsToDevicePixels="true"> 
       <Image x:Name="theImage" Source="{Binding Path=Content, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}" Margin="4,0,0,0"> 
        <Image.ToolTip> 
         <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/> 
        </Image.ToolTip> 
       </Image> 
      </Microsoft_Windows_Themes:ButtonChrome> 
      <ControlTemplate.Triggers> 
       ... 
      </ControlTemplate.Triggers> 
     </ControlTemplate> 
    </Setter.Value> 
</Setter> 
</Style> 

La magia está en la parte 'Fuente = (Encuadernación ...}'. Me ha funcionado bien tener la información sobre herramientas para depurar imágenes perdidas/cambiadas, pero también se puede quitar fácilmente.

0

Aquí está ¡mi solución!

<Button Content="Browse" Margin="10" Name="btBrowse"> 
      <Button.Template> 
       <ControlTemplate> 
        <StackPanel Orientation="Vertical" Height="50" Margin="5" VerticalAlignment="Center" HorizontalAlignment="Center"> 
         <Image Source="MyIcons\browse.png" Height="30" /> 
         <TextBlock Text="{Binding ElementName=btBrowse, Path=Content}" VerticalAlignment="Center" HorizontalAlignment="Center" /> 
        </StackPanel> 
       </ControlTemplate> 
      </Button.Template> 
     </Button> 

El resultado es el siguiente:

screenshot

0

Otra respuesta - la mejora de u/dogracer de yu/a Dave NP:


<Button Content = "{Binding object}" > 
    <Button.Style > 
     <Style TargetType="Button"> 
      <Setter Property = "ContentTemplate" > 
       <Setter.Value > 
        <DataTemplate > 
         <StackPanel > 
          <Image Source="{Binding Path=Content.ImageUrl, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}" > 
           <TextBlock Text = "{Binding Path=Content.Text,RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}" /> 
         </ StackPanel > 
        </ DataTemplate > 
       </ Setter.Value > 
      </ Setter > 
     </ Style > 
    </ Button.Style > 
</ Button > 
  1. contenido está vinculado a 'objeto' con las propiedades 'ImageUrl' y 'Text'.
  2. Esto funciona en un control de usuario fuera del ensamblaje principal.
  3. estilo es el de un botón normal
Cuestiones relacionadas