需求的提出
对于一个checkbox,要求不使用默认的方框,而采用图片代替,并且在选中/反选的状态下能自动更换指定的图片。
解决办法
1、使用Style.Trigger,根据IsChecked属性值的不同设定不同的ControlTemplate:
<Style TargetType="CheckBox">
<Setter Property="OverridesDefaultStyle" Value="True"></Setter>
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="CheckBox">
<Image HorizontalAlignment="Left" Name="image1" Stretch="Fill" VerticalAlignment="Top" Width="16" Height="16"
Source="/WpfApplication1;component/Images/accept.png" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="CheckBox">
<Image HorizontalAlignment="Left" Name="image1" Stretch="Fill" VerticalAlignment="Top" Width="16" Height="16"
Source="/WpfApplication1;component/Images/add.png" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
注意需要设置属性OverridesDefaultStyle为True。这种办法能够达到预期的效果,但不足的是图片的URI直接写到了Style里,不利于复用,且设置不灵活。
2、使继承自CheckBox的自定义类,公开属性用于保存图片路径,并且在Style里为Image设置binding。
自定义类代码:
public class TaskButton : CheckBox, INotifyPropertyChanged
{
private string _unCheckedImageUri;
public string UnCheckedImageUri
{
get { return _unCheckedImageUri; }
set { _unCheckedImageUri = value; }
}
private string _checkedImageUri;
public string CheckedImageUri
{
get { return _checkedImageUri; }
set { _checkedImageUri = value; }
}
}
将第一段XAML代码中的Image的Source属性分别设置为:
Source="{Binding Path=CheckedImageUri, RelativeSource={RelativeSource Mode=TemplatedParent}}"
Source="{Binding Path=UnCheckedImageUri, RelativeSource={RelativeSource Mode=TemplatedParent}}"
注意使用了RelativeSource更改目标数据源。之后需要修改TargetType为“local:TaskButton”(注册的前缀为local)。
这样下来似乎好了一点,但是,能不能不使用Trigger呢?
3、使用INotifyPropertyChanged
把TaskButton加工一下,让其实现INotifyPropertyChanged接口。添加属性用于返回当前状态下应使用的图片URI,并重载OnPropertyChanged事件处理器以在
适时通知属性已发生更改。添加代码如下:
public string CurrentImageUri
{
get
{
if (!IsChecked.HasValue)
return _unCheckedImageUri;
else
{
if (IsChecked.Value)
return _checkedImageUri;
else
return _unCheckedImageUri;
}
}
}
protected override void OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (e.Property == CheckBox.IsCheckedProperty)
{
PropertyChanged(this, new PropertyChangedEventArgs("CurrentImageUri"));
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
再将Style改为如下定义:
<Style TargetType="local:TaskButton">
<Setter Property="OverridesDefaultStyle" Value="True"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:TaskButton">
<Image HorizontalAlignment="Left" Name="image1" Stretch="Fill" VerticalAlignment="Top" Width="16" Height="16"
Source="{Binding Path=CurrentImageUri, RelativeSource={RelativeSource Mode=TemplatedParent}}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>