2010-03-18 4 views
12

Я хотел бы использовать ToggleButton в следующим образом: Есть 5 различных изображений, и каждый из них должен быть отображен в зависимости от текущего состояния:ToggleButton изменения изображения в зависимости от состояния

  1. кнопка отключена кнопка
  2. включена , бесконтрольно кнопка
  3. включена, бесконтрольно, указываемый курсор мыши
  4. кнопки включены, проверяется
  5. кнопка включена, проверяется, указываемый курсором мыши

Я нашел простой пример с двумя изображениями here, но как изменить изображение в зависимости от свойства «checked»?

Второй вопрос: как я могу избежать создания разных стилей для каждой кнопки в моем приложении? Я использую около 20 различных кнопок, и каждый из них имеет разные значки.

До сих пор я использую только один значок, расположенный ниже моего кода. Возможно ли иметь общий код (стиль и шаблон) и определить источник изображений в разделе, где я хочу создать кнопку (как в разделе 3 моего кода)?

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

ответ

9

Вы можете получить функциональность вы хотите, создавая UserControl, который предоставляет свойства зависимостей для команд, IsChecked, и по одному для каждого изображения с учетом состояния. Пользовательский элемент управления будет содержать кнопку переключения и изображение.

Вы можете использовать MultiDataTriggers для определения вашего состояния и swtich изображения в зависимости от состояния.

Поскольку вы выставили DependencyProperties для изображений с сохранением состояния, их можно настроить с помощью привязки данных, где бы вы ни объявляли свой контроль. Триггеры автоматически переключат источник изображения для вас, как только состояние изменится.

[Edit: Добавлен код, чтобы помочь объяснить]

Вот неполный пример, чтобы вы начали:

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> 

И CS файл:

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 
     } 



    } 
} 

Этот контроль может быть использован следующим образом:

<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

Сэр Эд Гонсалес, спасибо за хороший пример.

Единственная проблема заключается в том, что привязка к свойству зависимостей MyToggleButton.IsChecked не работает должным образом (платформа: Windows 7., NET 4.0, VS2010). Поэтому я сделал некоторые изменения в вашем примере.

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

узор Использование остается 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

Это работало отлично для меня (и я узнал кое-что!). Отличная работа! – Flea

-1

Сэр Эд Гонсалес, спасибо за хороший пример.

Единственная проблема заключается в том, что привязка к свойству зависимостей в MyToggleButton.IsChecked не работает должным образом (платформы: Windows 7, NET 4.0, VS2010). Поэтому я сделал некоторые изменения в вашем примере.

Просто удалите статический на IsChecked DependencyProperty, добавить свой ChangeImage() в IsChecked() и примеру сэра Эда Гонсалеса работать хорошо ^^

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

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

Это не сработает, эти get/set не вызывается каркасом. –

32

Это решение является простым:

<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

Краткое разъяснение, 'IsCheckedState' выше является свойством в VM, не имеет ничего общего с WPF. То есть если у вас есть свойство VM для «IsNewUser» для привязки, вы замените «IsCheckedState» в примере выше для «IsNewUser». – HockeyJ

+0

работает как шарм! –

0

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

<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> 
Смежные вопросы