WPF:可重复使用的图像按钮模板?

6

我的WPF项目使用了很多图像按钮,但是由于我还没有找到一个正确的方法(我必须每次都写相同的触发器和样式,唯一的区别是图像源),所以我的资源字典变得非常冗长。有更好的方法吗?

这是我用于按钮的样式示例:

<Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
    <!-- Some setters -->
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Grid>
                    <Image Source="Images.png" Stretch="Fill"/>
                </Grid>
                <ControlTemplate.Triggers>
                    <!-- Some triggers ( IsFocused, IsMouseOver, etc.) -->
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

谢谢您 :)
3个回答

11

最简单的方法是创建一个具有 Image 属性的特定控件:

public class ImageButton : Button
{
    static ImageButton()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof (ImageButton),
            new FrameworkPropertyMetadata(typeof (ImageButton)));
    }


    public ImageSource Image
    {
        get { return (ImageSource)GetValue(ImageProperty); }
        set { SetValue(ImageProperty, value); }
    }

    public static readonly DependencyProperty ImageProperty =
        DependencyProperty.Register("Image", typeof(ImageSource), typeof(ImageButton), new PropertyMetadata(default(ImageSource)));

}

然后您只需在 generic.xaml 中为其创建样式,并绑定到 Image 属性,而不是显式设置图像:

<Style x:Key="{x:Type my:ImageButton}" TargetType="{x:Type my:ImageButton}">
    <!-- Some setters -->
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type my:ImageButton}">
                <Grid>
                    <Image Source="{TemplateBinding Image}" Stretch="Fill"/>
                </Grid>
                <ControlTemplate.Triggers>
                    <!-- Some triggers ( IsFocused, IsMouseOver, etc.) -->
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

那么你可以像这样使用它:

<my:ImageButton Image="Image.png" />

如果您需要更多不同状态的按钮图片,可以向控件添加更多依赖属性。

另一种可能的方法是使用我所谓的“参数化样式”,以避免创建特定的控件;有关详细信息,请参见此博客文章


这个例子展示了WPF中自定义控件的一个主要问题。一旦我重写ControlTemplate,所有的主题都基本上被破坏了。我如何在所有环境下保留原始按钮的所有主题?当然,我可以将Button的原始ControlTemplate复制到我的ImageButton中,但这只适用于通用主题。我必须为我想支持的所有主题提供控件模板。但如果有一个我不知道的主题,这就会出问题。 - bitbonk
@bitbonk,是的,这是这个模板系统的主要缺点之一...不幸的是,我不知道有什么好的解决方案。 - Thomas Levesque
@ThomasLevesque,“这篇博客文章”的链接指向了这个StackOverflow问题,而不是博客文章:( - kazarey
@ThomasLevesque,另外,XAML片段的第5行不应该包含{x:Type Button}而是{x:Type my:ImageButton}吗?我一直收到“成员未被识别或无法访问”的错误,但是通过这个更改一切都可以正常工作。 - kazarey
@kazarey,我修复了链接和XAML。谢谢! - Thomas Levesque

1
您可以尝试创建一个自定义控件,继承自Button,并在模板中使用它作为TargetType。 然后,您可以在图像源中使用TemplateBinding。
<Image Source="{TemplateBinding ImageSource}" Stretch="Fill"/>

你需要在自定义控件中创建ImageSource属性。这样,你可以在xaml中设置源,但是只需要一个资源模板。

0
您可以像这样使用BasedOn属性:
<Style x:Key="BlueHighlightedButtonStyle"  BasedOn="{StaticResource ButtonStyle}" TargetType="Button">
    <Setter Property="Background" Value="DeepSkyBlue"/>
</Style>

这将创建一个具有与您的ButtonStyle相同属性的按钮样式,但具有DeepSkyBlue背景。


唯一的问题是BaseOn属性不能与所有触发器一起使用,我想避免每次添加不同按钮时重新定义它们。我尝试在ControlTemplate中使用TemplateBinding,但它没有起作用。 - Shugah

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接