实现图片式复选框

需求的提出

对于一个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>
posted @ 2011-01-25 09:19  细雨黄昏  阅读(3169)  评论(0编辑  收藏  举报