【问题标题】:Custom button template in WPFWPF中的自定义按钮模板
【发布时间】:2010-04-29 04:49:30
【问题描述】:

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

如何一步一步创建它?

P.S.:我已经在 WPF 中使用 CustomControlBasedOn 属性进行了尝试。

【问题讨论】:

    标签: wpf custom-controls styles


    【解决方案1】:

    您可以使用样式和附加属性轻松做到这一点:

    <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>
    

    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));
    }
    

    然后在标记中:

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

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

    【讨论】:

    • 您不需要使用控制模板。我只是使用标准的 WPF Button 类完成了所有这些工作。
    • 这很好!!通过绑定附加属性模板可以动态定制。非常感谢!
    • 请原谅我的 nievity(我是 C# 新手),但这是 ButtonProperties 它自己的文件?您是否需要在其他文件中引用它?我得到"The attachable property "Image" was not found in the type 'ButtonProperties'.
    • ButtonProperties 类可以是它自己的文件,或者你可以有一个定义许多不同附加属性的类——这并不重要,但你需要什么(我已经更新了回答指示)是将命名空间包含在 XAML 中的附加属性中。这通常采用xmlns:ap="clr-namespace:MyProject.Path.To.AttachedProperties.Namesapce" 的形式,其中ap 成为您用来引用该命名空间中的内容的前缀。
    • 请帮帮我。我的问题就是基于此。
    【解决方案2】:

    我终于创建了一个里面有图片+文字的按钮:

    以下是完整代码:

    第 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>
    

    第 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);
    
            }
    
        }
    

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

    xmlns:Local="clr-namespace:WpfApp"
    

    并将其用作:

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

    注意:我的图片位于此处的 Resources 文件夹中

    参考:

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

    【讨论】:

    • 缺点是你的控件不是从按钮派生的。因此,如果你想绑定一个命令,例如,你需要添加另一个依赖属性。但是,如果您只想要一个可以正常工作的图像和文本。
    【解决方案3】:

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

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

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

    <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>
    

    神奇之处在于“Source=(Binding ...}”部分。它对我来说很有效,因为它有工具提示用于调试丢失/更改的图像——但也可以很容易地删除。

    【讨论】:

      【解决方案4】:

      这是我的解决方案!

      <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>
      

      结果如下:

      【讨论】:

        【解决方案5】:

        另一个答案 - 改进 u/dogracer 和 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. 内容通过“ImageUrl”和“Text”属性绑定到“object”。
        2. 这适用于主程序集之外的用户控件。
        3. 样式是常规按钮的样式

        【讨论】:

          猜你喜欢
          • 2015-11-10
          • 2015-08-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-04-07
          • 1970-01-01
          相关资源
          最近更新 更多