2010-03-18 12 views
12

me gusta usar ToggleButton en el siguiente manera: Hay 5 imágenes diferentes y cada uno de ellos debería ser exhibidas en función del estado actual:ToggleButton cambio de imagen en función del estado

  1. tecla bloqueada botón
  2. habilitado , sin control botón
  3. habilitado, no se controla, apuntado por el cursor del ratón
  4. botón activado, comprueba botón
  5. habilitado, comprobado, señalado por el cursor del ratón

He encontrado un ejemplo simple con dos imágenes here, pero ¿cómo puedo cambiar la imagen dependiendo de la propiedad "marcada"?

La segunda pregunta: ¿cómo puedo evitar crear diferentes estilos para cada botón en mi aplicación? Estoy usando alrededor de 20 botones diferentes y cada uno de ellos tiene un conjunto diferente de iconos.

Hasta ahora estoy usando solo un icono, debajo de mi código. ¿Es posible tener un código común (estilo y plantilla) y definir la fuente de imágenes en la sección donde quiero crear el botón (como en la sección 3 de mi código)?

<ControlTemplate x:Key="ToggleButtonTemplate" TargetType="{x:Type ToggleButton}"> 
    <Grid> 
     <Border x:Name="ContentBorder" CornerRadius="4" BorderBrush="Transparent" BorderThickness="1" Background="{DynamicResource ButtonOff}"> 
      <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True"/> 
     </Border> 
    </Grid> 
    <ControlTemplate.Triggers> 
     <Trigger Property="IsPressed" Value="true"> 
      <Setter TargetName="ContentBorder" Property="Background" Value="{DynamicResource ButtonOn}"/> 
     </Trigger> 
     <Trigger Property="IsChecked" Value="true"> 
      <Setter TargetName="ContentBorder" Property="Background" Value="{DynamicResource ButtonOn}"/> 
     </Trigger> 
     <Trigger Property="IsEnabled" Value="false"> 
      <Setter TargetName="ContentBorder" Property="Background" Value="{DynamicResource ButtonDisabled}"/> 
      <Setter Property="Foreground" Value="{DynamicResource BorderDisabled}"/> 
     </Trigger> 
    </ControlTemplate.Triggers> 
</ControlTemplate> 

<Style x:Key="ToggleButtonStyle" TargetType="{x:Type ToggleButton}"> 
    <Setter Property="Width" Value="64" /> 
    <Setter Property="Height" Value="64" /> 
    <Setter Property="HorizontalContentAlignment" Value="Center"/> 
    <Setter Property="VerticalContentAlignment" Value="Center"/> 
    <Setter Property="Template" Value="{DynamicResource ToggleButtonTemplate}" /> 
</Style> 

<ToggleButton IsChecked="{Binding Path=IsLectorModeEnabled}" Command="{Binding CmdLector}" Style="{DynamicResource ToggleButtonStyle}"> 
    <Image Source="{DynamicResource LectorImage}" HorizontalAlignment="Center" VerticalAlignment="Center" Stretch="None" /> 
</ToggleButton> 

Respuesta

9

Puede obtener la funcionalidad que desea mediante la creación de un control de usuario que expone las propiedades de dependencia para el mando, IsChecked, y uno para cada imagen con estado. Su control de usuario contendrá un botón de alternar e imagen.

Puede usar MultiDataTriggers para detectar su estado y cambiar la imagen dependiendo del estado.

Debido a que expuso DependencyProperties para las imágenes de estado, se pueden establecer mediante Databinding donde declare su control. Los activadores cambiarán automáticamente la fuente de la imagen por usted, una vez que el estado cambie.

[Editar: Se ha añadido algo de código para ayudar a explicar]

Aquí está un ejemplo parcial para empezar:

MyToggleButton.xaml:

<UserControl x:Class="ToggleTest.MyToggleButton" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
<ToggleButton 
    IsChecked='{Binding RelativeSource={RelativeSource FindAncestor, 
    AncestorType={x:Type ToggleButton} }, 
    Path=IsChecked}'> 
    <Image 
     x:Name='ButtonImage'> 
     <Image.Style> 
      <Style 
       TargetType='{x:Type Image}'> 
       <Style.Triggers> 
        <MultiDataTrigger> 
         <MultiDataTrigger.Conditions> 
          <Condition 
           Binding='{Binding 
           RelativeSource={RelativeSource FindAncestor, 
           AncestorType={x:Type ToggleButton} }, 
           Path=IsChecked}' 
           Value='True' /> 
          <Condition 
           Binding='{Binding 
           RelativeSource={RelativeSource Self}, 
           Path=IsEnabled}' 
           Value='True' /> 
         </MultiDataTrigger.Conditions> 
         <Setter 
          Property='Source' 
          Value='{Binding 
          RelativeSource={RelativeSource FindAncestor, 
          AncestorType={x:Type UserControl} }, 
          Path=EnabledChecked}' /> 
        </MultiDataTrigger> 
        <MultiDataTrigger> 
         <MultiDataTrigger.Conditions> 
          <Condition 
           Binding='{Binding 
           RelativeSource={RelativeSource FindAncestor, 
           AncestorType={x:Type ToggleButton} }, 
           Path=IsChecked}' 
           Value='False' /> 
          <Condition 
           Binding='{Binding 
           RelativeSource={RelativeSource Self}, 
           Path=IsEnabled}' 
           Value='True' /> 
         </MultiDataTrigger.Conditions> 
         <Setter 
          Property='Source' 
          Value='{Binding 
          RelativeSource={RelativeSource FindAncestor, 
          AncestorType={x:Type UserControl} }, 
          Path=EnabledUnchecked}' /> 
        </MultiDataTrigger> 
        <MultiDataTrigger> 
         <MultiDataTrigger.Conditions> 
          <Condition 
           Binding='{Binding 
           RelativeSource={RelativeSource FindAncestor, 
           AncestorType={x:Type ToggleButton} }, 
           Path=IsChecked}' 
           Value='False' /> 
          <Condition 
           Binding='{Binding 
           RelativeSource={RelativeSource Self}, 
           Path=IsEnabled}' 
           Value='False' /> 
         </MultiDataTrigger.Conditions> 
         <Setter 
          Property='Source' 
          Value='{Binding 
          RelativeSource={RelativeSource FindAncestor, 
          AncestorType={x:Type UserControl} }, 
          Path=DisabledUnchecked}' /> 
        </MultiDataTrigger> 
       </Style.Triggers> 
      </Style> 
     </Image.Style> 
    </Image> 
</ToggleButton> 

Y el cs archivo:

using System; 

    using System.Windows; 
    using System.Windows.Controls; 
    using System.Windows.Media; 

    namespace ToggleTest 

{ 
    /// <summary> 
    /// Interaction logic for ToggleButton.xaml 
    /// </summary> 
    public partial class MyToggleButton : UserControl 
    { 
     public MyToggleButton() 
     { 
      InitializeComponent(); 
     } 


     public static readonly DependencyProperty EnabledUncheckedProperty = 
      DependencyProperty.Register(
      "EnabledUnchecked", 
      typeof(ImageSource), 
      typeof(MyToggleButton), 
      new PropertyMetadata(onEnabledUncheckedChangedCallback)); 

     public ImageSource EnabledUnchecked 
     { 
      get { return (ImageSource)GetValue(EnabledUncheckedProperty); } 
      set { SetValue(EnabledUncheckedProperty, value); } 
     } 

     static void onEnabledUncheckedChangedCallback(
      DependencyObject dobj, 
      DependencyPropertyChangedEventArgs args) 
     { 
      //do something if needed 
     } 

     public static readonly DependencyProperty DisabledUncheckedProperty = 
      DependencyProperty.Register(
      "DisabledUnchecked", 
      typeof(ImageSource), 
      typeof(MyToggleButton), 
      new PropertyMetadata(onDisabledUncheckedChangedCallback)); 

     public ImageSource DisabledUnchecked 
     { 
      get { return (ImageSource)GetValue(DisabledUncheckedProperty); } 
      set { SetValue(DisabledUncheckedProperty, value); } 
     } 

     static void onDisabledUncheckedChangedCallback(
      DependencyObject dobj, 
      DependencyPropertyChangedEventArgs args) 
     { 
      //do something if needed 
     } 


     public static readonly DependencyProperty EnabledCheckedProperty = 
      DependencyProperty.Register(
      "EnabledChecked", 
      typeof(ImageSource), 
      typeof(MyToggleButton), 
      new PropertyMetadata(onEnabledCheckedChangedCallback)); 

     public ImageSource EnabledChecked 
     { 
      get { return (ImageSource)GetValue(EnabledCheckedProperty); } 
      set { SetValue(EnabledCheckedProperty, value); } 
     } 

     static void onEnabledCheckedChangedCallback(
      DependencyObject dobj, 
      DependencyPropertyChangedEventArgs args) 
     { 
      //do something if needed 
     } 


     public static readonly DependencyProperty IsCheckedProperty = 
      DependencyProperty.Register(
      "IsChecked", 
      typeof(Boolean), 
      typeof(MyToggleButton), 
      new PropertyMetadata(onCheckedChangedCallback)); 

     public Boolean IsChecked 
     { 
      get { return (Boolean)GetValue(IsCheckedProperty); } 
      set { if(value != IsChecked) SetValue(IsCheckedProperty, value); } 
     } 

     static void onCheckedChangedCallback(
      DependencyObject dobj, 
      DependencyPropertyChangedEventArgs args) 
     { 
      //do something, if needed 
     } 



    } 
} 

Este control podría ser utilizado de esta manera:

<local:MyToggleButton 
      IsChecked='True' 
      IsEnabled='False' 
      EnabledChecked='<add your image source here>' 
      EnabledUnchecked='<add your image source here>' 
      DisabledUnchecked='<add your image source here>'/> 
5

Sir Ed González, gracias por el buen ejemplo.

El único problema es que el enlace a la propiedad de dependencia MyToggleButton.IsChecked no funciona correctamente (plataforma: Windows 7., NET 4.0, VS2010). Así que hice algunos cambios en tu ejemplo.

xaml:

<ToggleButton x:Class="MyApp.ToggleButtonEx" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     Checked="ToggleButton_CheckedChanged" 
     Unchecked="ToggleButton_CheckedChanged" 
     IsEnabledChanged="ToggleButton_IsEnabledChanged" 
     Loaded="ToggleButton_Loaded"> 
    <Image x:Name='ButtonImage'/> 
</ToggleButton> 

cs:

public partial class ToggleButtonEx : ToggleButton 
{ 
    public ToggleButtonEx() 
    { 
     InitializeComponent();    
    } 

    public static readonly DependencyProperty EnabledUncheckedProperty = 
     DependencyProperty.Register(
     "EnabledUnchecked", 
     typeof(ImageSource), 
     typeof(ToggleButtonEx), 
     new PropertyMetadata(onEnabledUncheckedChangedCallback)); 

    public ImageSource EnabledUnchecked 
    { 
     get { return (ImageSource)GetValue(EnabledUncheckedProperty); } 
     set { SetValue(EnabledUncheckedProperty, value); } 
    } 

    static void onEnabledUncheckedChangedCallback(
     DependencyObject dobj, 
     DependencyPropertyChangedEventArgs args) 
    { 
     //do something if needed 
    } 

    public static readonly DependencyProperty DisabledUncheckedProperty = 
     DependencyProperty.Register(
     "DisabledUnchecked", 
     typeof(ImageSource), 
     typeof(ToggleButtonEx), 
     new PropertyMetadata(onDisabledUncheckedChangedCallback)); 

    public ImageSource DisabledUnchecked 
    { 
     get { return (ImageSource)GetValue(DisabledUncheckedProperty); } 
     set { SetValue(DisabledUncheckedProperty, value); } 
    } 

    static void onDisabledUncheckedChangedCallback(
     DependencyObject dobj, 
     DependencyPropertyChangedEventArgs args) 
    { 
     //do something if needed 
    } 


    public static readonly DependencyProperty EnabledCheckedProperty = 
     DependencyProperty.Register(
     "EnabledChecked", 
     typeof(ImageSource), 
     typeof(ToggleButtonEx), 
     new PropertyMetadata(onEnabledCheckedChangedCallback)); 

    public ImageSource EnabledChecked 
    { 
     get { return (ImageSource)GetValue(EnabledCheckedProperty); } 
     set { SetValue(EnabledCheckedProperty, value); } 
    } 

    static void onEnabledCheckedChangedCallback(
     DependencyObject dobj, 
     DependencyPropertyChangedEventArgs args) 
    { 
     //do something if needed 
    } 

    private void ToggleButton_CheckedChanged(object sender, RoutedEventArgs e) 
    { 
     ChangeImage(); 
    } 

    private void ToggleButton_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e) 
    { 
     ChangeImage(); 
    } 

    private void ToggleButton_Loaded(object sender, RoutedEventArgs e) 
    { 
     ChangeImage(); 
    } 

    private void ChangeImage() 
    { 
     if (IsEnabled) 
     { 
      if(IsChecked == true) 
       ButtonImage.Source = EnabledChecked; 
      else 
       ButtonImage.Source = EnabledUnchecked; 
     } 
     else 
     { 
      ButtonImage.Source = DisabledUnchecked; 
     } 
    } 
} 

patrón de uso sigue siendo unchaged:

<local:MyToggleButton 
     IsChecked='True' 
     IsEnabled='False' 
     EnabledChecked='<add your image source here>' 
     EnabledUnchecked='<add your image source here>' 
     DisabledUnchecked='<add your image source here>'/> 
+0

Esto funcionó muy bien para mí (¡y aprendí una o dos cosas!). ¡Gran trabajo! – Flea

-1

Sir Ed González, gracias por el buen ejemplo.

El único problema es que la unión a la propiedad de dependencia MyToggleButton.IsChecked no funciona correctamente (Plataforma: Windows 7., NET 4.0, VS2010). Así que hice algunos cambios en tu ejemplo.

Basta con retirar estática en IsChecked DependencyProperty, añadir su ChangeImage() en IsChecked() y el ejemplo las de Sir Ed González funcionar bien ^^

public readonly DependencyProperty IsCheckedProperty = 
      DependencyProperty.Register(
      "IsChecked" ... 

public Boolean IsChecked 
... if (value != IsChecked) SetValue(IsCheckedProperty, value); ChangeImage(); 
+3

Eso no funcionará, estos get/set no son llamados por el framework. –

32

Esta solución es muy sencilla:

<ToggleButton IsChecked="{Binding IsCheckedState}"> 
      <Image Width="24" Height="24" > 
       <Image.Style> 
        <Style TargetType="{x:Type Image}"> 
         <Style.Triggers> 
          <DataTrigger Binding="{Binding IsCheckedState}" Value="true"> 
           <Setter Property="Source" Value="Images/checked.ico"/> 
          </DataTrigger> 
          <DataTrigger Binding="{Binding IsCheckedState}" Value="false"> 
           <Setter Property="Source" Value="Images/unchecked.ico"/> 
          </DataTrigger> 
         </Style.Triggers> 
        </Style> 
       </Image.Style> 
      </Image> 
     </ToggleButton> 
+1

Breve aclaración, el 'IsCheckedState' anterior es una propiedad en la VM, no tiene nada que ver con WPF. Es decir. si tiene una propiedad de VM de 'IsNewUser' para enlazar, reemplazaría 'IsCheckedState' en el ejemplo anterior por 'IsNewUser'. – HockeyJ

+0

funciona como un encanto! –

0

I hice lo mismo con mi RibbonToggleButton, pero creo que es un poco más fácil. Puse el gatillo de estilo dentro del botón en lugar de usar un elemento de imagen extra.

<RibbonToggleButton Label="{x:Static p:Resources.Main_Connect}" Command="{Binding ConnectRemoteCommand}" CommandParameter="{Binding Path=IsChecked, RelativeSource={RelativeSource Self}}"> 
         <RibbonToggleButton.Style> 
          <Style TargetType="{x:Type RibbonToggleButton}"> 
           <Style.Triggers> 
            <DataTrigger Binding="{Binding Path=IsChecked, RelativeSource={RelativeSource Self}}" Value="true"> 
             <Setter Property="LargeImageSource" Value="../../Resources/Images/GPS-On.png"/> 
            </DataTrigger> 
            <DataTrigger Binding="{Binding Path=IsChecked, RelativeSource={RelativeSource Self}}" Value="false"> 
             <Setter Property="LargeImageSource" Value="../../Resources/Images/GPS-Off.png"/> 
            </DataTrigger> 
           </Style.Triggers> 
          </Style> 
         </RibbonToggleButton.Style> 
        </RibbonToggleButton> 
Cuestiones relacionadas