2010-03-18 13 views
12

Vorrei utilizzare ToggleButton nel seguente modo: Ci sono 5 immagini diverse e ciascuno di essi deve essere visualizzato a seconda dello stato attuale:ToggleButton cambiare immagine a seconda dello stato

  1. pulsante disattivato pulsante
  2. abilitato , incontrollato pulsante
  3. attivata, non controllato, indicate dal cursore
  4. pulsante attivato, controllato pulsante
  5. attivata, controllato, puntato dal cursore del mouse

Ho trovato un semplice esempio con due immagini here, ma come modificare l'immagine in base alla proprietà "checked"?

La seconda domanda: come evitare di creare stili diversi per ciascun pulsante nella mia applicazione? Sto usando circa 20 pulsanti diversi e ognuno di essi ha un diverso set di icone.

Finora sto utilizzando solo un'icona, sotto il mio codice. È possibile avere codice comune (stile e modello) e definire la fonte delle immagini nella sezione in cui voglio creare il pulsante (come nella sezione 3 del mio codice)?

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

risposta

9

È possibile ottenere la funzionalità desiderata mediante la creazione di un controllo utente che espone le proprietà di dipendenza per Command, IsChecked, e uno per ogni immagine stateful. Il tuo controllo utente conterrà un pulsante di attivazione e un'immagine.

È possibile utilizzare MultiDataTrigger per rilevare lo stato e spostare l'immagine in base allo stato.

Poiché hai esposto le proprietà di dipendenza per le immagini stateful, possono essere impostate utilizzando l'associazione dati ovunque dichiari il controllo. I trigger commuteranno automaticamente la sorgente dell'immagine per te, una volta che lo stato cambia.

[Edit: aggiunto un po 'di codice per aiutare a spiegare]

Ecco un esempio parziale per iniziare:

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> 

E il cs file:

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 
     } 



    } 
} 

Questo controllo potrebbe essere utilizzato in questo modo:

<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 Gonzalez, grazie per il buon esempio.

L'unico problema è che il collegamento alla proprietà di dipendenza MyToggleButton.IsChecked non funziona correttamente (piattaforma: Windows 7., NET 4.0, VS2010). Quindi ho apportato alcune modifiche nel tuo esempio.

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

modello di utilizzo rimane 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

Questo ha funzionato bene per me (e ho imparato una cosa o due!). Ottimo lavoro! – Flea

-1

Sir Ed Gonzalez, grazie per il buon esempio.

L'unico problema è che il collegamento alla proprietà di dipendenza MyToggleButton.IsChecked non funziona correttamente (piattaforma: Windows 7., NET 4.0, VS2010). Quindi ho apportato alcune modifiche nel tuo esempio.

Basta togliere statico sul IsChecked DependencyProperty, aggiungere il ChangeImage() in IsChecked() e l'esempio di Sir Ed Gonzalez lavorare bene ^^

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

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

Che non funziona, questi get/set non vengono chiamati dal framework. –

32

Questa soluzione è semplice:

<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 chiarimento, il 'IsCheckedState' sopra è una proprietà nella VM, non qualcosa a che fare con WPF. Cioè se si dispone di una proprietà VM di 'IsNewUser' per il binding, si sostituirà 'IsCheckedState' nell'esempio sopra per 'IsNewUser'. – HockeyJ

+0

funziona come un fascino! –

0

I ha fatto lo stesso per il mio RibbonToggleButton, ma penso un po 'più facilmente. Inserisco il trigger di stile all'interno del pulsante anziché utilizzare un elemento immagine aggiuntivo.

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