【问题标题】:ToggleButton changing image depending on stateToggleButton 根据状态更改图像
【发布时间】:2010-03-18 21:25:45
【问题描述】:

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

  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>

【问题讨论】:

    标签: c# wpf wpf-controls


    【解决方案1】:

    这个解决方案很简单:

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

    【讨论】:

    • 简要说明,上面的“IsCheckedState”是VM中的一个属性,与WPF无关。 IE。如果您有要绑定的 VM 属性“IsNewUser”,则可以将上面示例中的“IsCheckedState”替换为“IsNewUser”。
    【解决方案2】:

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

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

    因为您公开了有状态图像的 DependencyProperties,所以可以在您声明控件的任何位置使用数据绑定来设置它们。一旦状态发生变化,触发器将自动为您切换图像源。

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

    这里有一个部分示例可以帮助您入门:

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

    【讨论】:

      【解决方案3】:

      埃德·冈萨雷斯爵士,谢谢你的好榜样。

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

      【讨论】:

      • 这对我很有用(而且我学到了一两件事!)。干得好!
      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

        另一种方法是在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>
        

        【讨论】:

          【解决方案6】:

          只是因为我讨厌弄乱内容的切换按钮模板。我更喜欢只使用 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>
          

          【讨论】:

            【解决方案7】:

            埃德·冈萨雷斯爵士,谢谢你的好榜样。

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

            只需删除 IsChecked DependencyProperty 上的静态,在 IsChecked() 中添加您的 ChangeImage(),Ed Gonzalez 爵士的示例效果很好 ^^

            public readonly DependencyProperty IsCheckedProperty =
                        DependencyProperty.Register(
                        "IsChecked" ...
            
            public Boolean IsChecked
            ... if (value != IsChecked) SetValue(IsCheckedProperty, value); ChangeImage();
            

            【讨论】:

            • 那不行,框架不会调用这些get/set。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-08-22
            • 2017-11-27
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多