我想以下列方式使用ToggleButton: 有5个不同的图像,每个图像都应根据当前状态显示:
我找到了一个包含两个图片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>
答案 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();