ToggleButton根据状态更改图像

时间:2010-03-18 21:25:45

标签: c# wpf wpf-controls

我想以下列方式使用ToggleButton: 有5个不同的图像,每个图像都应根据当前状态显示:

  1. 按钮已停用
  2. 按钮已启用,未选中
  3. 按钮已启用,未选中,由鼠标光标指向
  4. 按钮已启用,已选中
  5. 按钮启用,检查,鼠标光标指向
  6. 我找到了一个包含两个图片here的简单示例,但是如何根据“已检查”属性更改图片?

    第二个问题:如何避免为我的应用程序中的每个按钮创建不同的样式?我使用了大约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>
    

7 个答案:

答案 0 :(得分:36)

这个解决方案很简单:

 <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 :(得分:11)

您可以通过创建UserControl来获取所需的功能,该UserControl公开Command,IsChecked的依赖项属性,并为每个有状态图像公开一个。您的用户控件将包含切换按钮和图像。

您可以使用MultiDataTriggers检测您的状态,并根据状态切换图像。

因为您公开了有状态图像的DependencyProperties,所以只要您声明控件,就可以使用Databinding设置它们。一旦状态发生变化,触发器将自动为您切换图像源。

[编辑:添加了一些代码以帮助解释]

以下是让您入门的部分示例:

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

答案 2 :(得分:5)

Ed Gonzalez爵士,谢谢你的好榜样。

唯一的问题是绑定到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;
        }
    }
}

使用模式保持不变:

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

答案 3 :(得分:1)

我为我的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>

答案 4 :(得分:0)

另一种解决方法是在ToggleButton本身上使用样式。将图像添加为内容,并使用ToggleButton的IsChecked属性上的触发器更改图像

    <ToggleButton Name="ExpandButton" Grid.Row="1" Grid.Column="0" IsChecked="{Binding IsCheckedState}">
      <ToggleButton.Template>
        <ControlTemplate TargetType="ToggleButton">
         <Grid>
            <Image Name="LogoImage" Stretch="Uniform" Source="checked.png"/>
          </Grid> 

          <ControlTemplate.Triggers>
            <Trigger Property="IsChecked" Value="true">
              <Setter TargetName="LogoImage" Property="Source" Value="checked.png"/> 
            </Trigger>
            <Trigger Property="IsChecked" Value="false">
              <Setter TargetName="LogoImage" Property="Source" Value="unchecked.png"/>
            </Trigger>
          </ControlTemplate.Triggers>
        </ControlTemplate>
      </ToggleButton.Template>  
    </ToggleButton>

答案 5 :(得分:0)

只是因为我讨厌把我的切换按钮模板弄乱。我更喜欢使用 bool 到可见性转换器来实现与上述相同的行为。而且超级简单。现在我使用 XAML 矢量图像,所以我目前使用的是内容控件,但您可以轻松地将它们替换为图像。这让我可以保持我的切换按钮样式纯粹,这样我就可以为整个应用程序保留它们的默认样式,而无需为每个按钮编写自定义样式。

<UserControl.Resources>
    <BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
    <converters:InverseBooleanToVisibilityConverter x:Key="InverseBooleanToVisibilityConverter" />
</UserControl.Resources>

<ToggleButton>
    <Grid>
        <ContentControl Visibility="{Binding IsChecked, RelativeSource={RelativeSource AncestorType={x:Type ToggleButton}}, Converter={StaticResource BoolToVisConverter}}" Content="{StaticResource Play}" />
        <ContentControl Visibility="{Binding IsChecked, RelativeSource={RelativeSource AncestorType={x:Type ToggleButton}}, Converter={StaticResource InverseBooleanToVisibilityConverter}}" Content="{StaticResource Pause}" />
    </Grid>
</ToggleButton>

<ToggleButton>
    <Grid>
        <Image Visibility="{Binding IsChecked, RelativeSource={RelativeSource AncestorType={x:Type ToggleButton}}, Converter={StaticResource BoolToVisConverter}}" Source="play.png" />
        <Image Visibility="{Binding IsChecked, RelativeSource={RelativeSource AncestorType={x:Type ToggleButton}}, Converter={StaticResource InverseBooleanToVisibilityConverter}}" Source="pause.png" />
    </Grid>
</ToggleButton>

答案 6 :(得分:-1)

  

Ed Gonzalez爵士,谢谢你的好榜样。

     

唯一的问题是绑定到MyToggleButton.IsChecked   依赖属性无法正常工作(平台:Windows 7.,NET   4.0,VS2010)。所以我在你的例子中做了一些改变。

只需删除IsChecked DependencyProperty上的静态,在ChangeImage()中添加IsChecked(),并且Sir Ed Gonzalez的示例运行良好^^

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

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