WPF 中的自定义按钮模板

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2734825/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 21:43:02  来源:igfitidea点击:

Custom button template in WPF

wpfcustom-controlsstyles

提问by Archie

I want to create a simple button template with an image and text inside it. But I want to keep the System button's look and feel.

我想创建一个简单的按钮模板,其中包含图像和文本。但我想保持系统按钮的外观和感觉。

How do I create it, step by step?

我如何一步一步地创建它?

P.S.: I have already tried it with CustomControlin WPF and BasedOnproperty.

PS:我已经CustomControl在 WPF 和BasedOnproperty 中尝试过了。

回答by jeffora

You can do this easily with a style and attached property:

您可以使用样式和附加属性轻松完成此操作:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:ap="clr-namespace:MyProject.Namespace.Path.To.ButtonProperties">
    ...
    <Style x:Key="ImageButton" TargetType="Button">
        <Setter Property="ContentTemplate">
            <Setter.Value>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Image Source="{Binding Path=(ap:ButtonProperties.Image), RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}"></Image>
                        <ContentPresenter Content="{Binding Path=Content, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}"></ContentPresenter>
                    </StackPanel>
                </DataTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    ...
</ResourceDictionary>

and

public class ButtonProperties
{
    public static ImageSource GetImage(DependencyObject obj)
    {
        return (ImageSource)obj.GetValue(ImageProperty);
    }

    public static void SetImage(DependencyObject obj, ImageSource value)
    {
        obj.SetValue(ImageProperty, value);
    }

    public static readonly DependencyProperty ImageProperty =
        DependencyProperty.RegisterAttached("Image", typeof(ImageSource), typeof(ButtonProperties), new UIPropertyMetadata((ImageSource)null));
}

Then in markup:

然后在标记中:

<Button Style="{StaticResource ImageButton}" ap:ButtonProperties.Image="{StaticResource MyImage}" Content="Test">
</Button>

This example looks pretty hideous, but you can easily change the StackPanelto a Gridor something similar to constrain the image proportion. Using the ContentPresenterallows you to preserve the behaviour of a button allowing you to put any UIElementinside, and retaining Command support etc.

这个例子看起来很可怕,但你可以很容易地StackPanel将 a更改为 aGrid或类似的东西来限制图像比例。使用ContentPresenter允许您保留按钮的行为,允许您将任何内容UIElement放入其中,并保留命令支持等。

回答by Archie

I have finally created a Button with image + text inside it:

我终于创建了一个带有图像 + 文本的按钮:

Below is the Full Code:

以下是完整代码:

Step 1 : Create a new User Control called:ImageButtonUC

第 1 步:创建一个名为:ImageButtonUC 的新用户控件

<UserControl Name="ImageButton" x:Class="WpfApp.ImageButtonUC"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
        <Button VerticalAlignment="Top" Width="100" Height="25" Click="button_Click"> 
            <Button.Content>
                <StackPanel Orientation="Horizontal">
                    <Image Width="16" Height="16" Margin="5,0,5,0" Source="{Binding ElementName=ImageButton, Path=Image}"/>
                    <TextBlock Text="{Binding ElementName=ImageButton, Path=Text}"/>
                </StackPanel>
            </Button.Content>
        </Button>
    </Grid>
</UserControl>

Step 2: Edit ImageButtonUC.xaml.cs

步骤 2:编辑 ImageButtonUC.xaml.cs

public partial class ImageButtonUC : UserControl
    {
        public event RoutedEventHandler Click;

        public ImageButtonUC()
        {
            InitializeComponent();

        }

        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }


        public static readonly DependencyProperty TextProperty =
          DependencyProperty.Register("Text", typeof(string), typeof(ImageButtonUC), new UIPropertyMetadata(""));

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

        public static readonly DependencyProperty ImageProperty =
           DependencyProperty.Register("Image", typeof(ImageSource), typeof(ImageButtonUC), new UIPropertyMetadata(null));


        private void button_Click(object sender, RoutedEventArgs e)
        {

            if (null != Click)

                Click(sender, e);

        }

    }

Step 3: In your xaml you can use it this way: Add the namespace as

第 3 步:在您的 xaml 中,您可以这样使用:将命名空间添加为

xmlns:Local="clr-namespace:WpfApp"

And use it as:

并将其用作:

<Local:ImageButtonUC x:Name="buttonImg" Width="100" Margin="10,0,10,0" Image="/WpfApp;component/Resources/Img.bmp" Text="Browse..." Click="buttonImg_Click"/>

Note: My Image is loacted in the Resources folder here

注意:我的图像位于此处的资源文件夹中

Reference:

参考:

http://blogs.msdn.com/knom/archive/2007/10/31/wpf-control-development-3-ways-to-build-an-imagebutton.aspx

http://blogs.msdn.com/knom/archive/2007/10/31/wpf-control-development-3-ways-to-build-an-imagebutton.aspx

回答by dogracer

If you don't want to write any code-behind, there is another way of doing this (inspired by jeffora's answer). You can use the control's Content field to put the URI to the image you want to see in your button:

如果您不想编写任何隐藏代码,还有另一种方法可以做到这一点(受 jeffora 的回答启发)。您可以使用控件的 Content 字段将 URI 放入您想要在按钮中看到的图像:

<Button Content="https://www.google.com/images/srpr/logo3w.png" Height="100" Width="200" Style="{DynamicResource ButtonStyle1}"/>

And then you can edit the default Button Style to look like this:

然后您可以将默认按钮样式编辑为如下所示:

<Style>
...
<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="{x:Type Button}">
            <Microsoft_Windows_Themes:ButtonChrome x:Name="Chrome" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}" RenderDefaulted="{TemplateBinding IsDefaulted}" SnapsToDevicePixels="true">
                <Image x:Name="theImage" Source="{Binding Path=Content, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}" Margin="4,0,0,0">
                    <Image.ToolTip>
                        <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                    </Image.ToolTip>
                </Image>
            </Microsoft_Windows_Themes:ButtonChrome>
            <ControlTemplate.Triggers>
                ...
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Setter.Value>
</Setter>
</Style>

The magic is in the 'Source=(Binding ...}' part. It has worked well for me to have the ToolTip there for debugging missing/changed images -- but can easily be removed as well.

神奇之处在于 'Source=(Binding ...}' 部分。在那里使用 ToolTip 来调试丢失/更改的图像对我来说效果很好——但也可以轻松删除。

回答by Dave NP

Here is my Solution!

这是我的解决方案!

<Button Content="Browse" Margin="10" Name="btBrowse">
            <Button.Template>
                <ControlTemplate>
                    <StackPanel Orientation="Vertical" Height="50" Margin="5" VerticalAlignment="Center" HorizontalAlignment="Center">
                        <Image Source="MyIcons\browse.png" Height="30" />
                        <TextBlock Text="{Binding ElementName=btBrowse, Path=Content}" VerticalAlignment="Center" HorizontalAlignment="Center" />
                    </StackPanel>
                </ControlTemplate>
            </Button.Template>
        </Button>

Result is below:

结果如下:

screenshot

截屏

回答by Declan Taylor

Another answer - improving on u/dogracer's and u/Dave NP:

另一个答案 - 改进 u/dogracer's 和 u/Dave NP:



<Button Content = "{Binding object}" >
    <Button.Style >
        <Style TargetType="Button">
            <Setter Property = "ContentTemplate" >
                <Setter.Value >
                    <DataTemplate >
                        <StackPanel >
                            <Image  Source="{Binding Path=Content.ImageUrl, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}" >
                                <TextBlock Text = "{Binding Path=Content.Text,RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}" />
                        </ StackPanel >
                    </ DataTemplate >
                </ Setter.Value >
            </ Setter >
        </ Style >
    </ Button.Style >
</ Button >
  1. Content is the bound to 'object' with 'ImageUrl' and 'Text' Properties.
  2. This works in a usercontrol outside the main assembly.
  3. Style is that of a regular button
  1. 内容绑定到具有“ImageUrl”和“Text”属性的“object”。
  2. 这适用于主程序集之外的用户控件。
  3. 样式是普通按钮的样式