我可以完全控制自定义WPF按钮的绘制吗?

时间:2010-06-28 04:10:29

标签: wpf button

我想你可以用足够的XAML经验绘制任何东西,但我是WPF新手的C ++人。我需要一个渐变颜色加上围绕它的特殊边框的按钮。那么我们C ++人员做了什么?我们去设计师,请求左垂直图像,中间一个和右一个,然后覆盖Win32绘图消息几乎自己绘制按钮。

WPF的做法是什么?我是否需要掌握XAML,或者我可以以某种方式利用这3个图像来组成按钮?我天真的想法是做这样的事情,我把按钮分成3个部分,每个部分都有不同的背景,但是这并没有给我我想要的结果。我可以控制按钮的绘制方式吗?

<Style x:Key="NavButtonStyle" TargetType="{x:Type Button}">
        <Setter Property="OverridesDefaultStyle" Value="True" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Grid ShowGridLines="False">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>
                        <Grid Grid.Column="0">
                            <Grid.Background>
                                <ImageBrush ImageSource="/Images/left.png"/>
                            </Grid.Background>
                        </Grid>
                        <StackPanel Grid.Column="1" HorizontalAlignment="Center" Orientation="Horizontal">
                            <StackPanel.Background>
                                <ImageBrush Stretch="Fill" ImageSource="/Images/middle.png"/>
                            </StackPanel.Background>
                            <Image Source="/Images/Icons/myIcon.png"/>
                            <TextBlock Text="myCaption"/>
                        </StackPanel>
                        <Grid Grid.Column="2">
                            <Grid.Background>
                                <ImageBrush Stretch="Fill" ImageSource="/Images/right.png"/>
                            </Grid.Background>
                        </Grid>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

另一个问题是如何使它成为通用模板,以便我可以复制外观,但只需更改图标和文本。我认为执行此任务的正确方法是提供一个继承自Button的CustomControl类?

2 个答案:

答案 0 :(得分:0)

1#: 我不知道控制按钮是什么意思?但我们可以根据您的喜好控制按钮样式。在上面的XAML中,我只看到了模板,但没有触发器或VisualStates提到按钮的不同状态/行为/效果,如鼠标悬停,鼠标离开,按钮按等等。由于此控件覆盖默认样式,这些效果将表现为默认按钮。

2#:由于这是一个自定义控件,您可以在“Themes”文件夹&amp;下添加样式。 generic.xaml。您不应指定密钥名称,然后它将应用于所有自定义控制按钮,如下所示:

<Style TargetType="{x:Type custom:CustomerControlType}"> 

答案 1 :(得分:0)

真正简短的回答是,这就是你使用Expression Blend的目的。

稍微简短的回答是,如果您了解控件模板的工作原理以及您知道要编辑的内容,则可以通过编辑控件模板来完成您描述的大部分内容。 Expression Blend是一个很好的工具,因为Blend使编辑控件的模板变得相对简单,而且Blend会记住很多你可能会忘记的事情,特别是如果你是WPF的新手。

例如,如果我进入Blend,在画板上画一个按钮,并编辑其控制模板的副本,这是我在开始弄乱任何东西之前得到的:

<Style x:Key="ButtonFocusVisual">
  <Setter Property="Control.Template">
    <Setter.Value>
      <ControlTemplate>
        <Rectangle Stroke="Black" StrokeDashArray="1 2" StrokeThickness="1" Margin="2" SnapsToDevicePixels="true"/>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>
<LinearGradientBrush x:Key="ButtonNormalBackground" EndPoint="0,1" StartPoint="0,0">
  <GradientStop Color="#F3F3F3" Offset="0"/>
  <GradientStop Color="#EBEBEB" Offset="0.5"/>
  <GradientStop Color="#DDDDDD" Offset="0.5"/>
  <GradientStop Color="#CDCDCD" Offset="1"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="ButtonNormalBorder" Color="#FF707070"/>
<Style x:Key="ButtonControlTemplate" TargetType="{x:Type Button}">
  <Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}"/>
  <Setter Property="Background" Value="{StaticResource ButtonNormalBackground}"/>
  <Setter Property="BorderBrush" Value="{StaticResource ButtonNormalBorder}"/>
  <Setter Property="BorderThickness" Value="1"/>
  <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
  <Setter Property="HorizontalContentAlignment" Value="Center"/>
  <Setter Property="VerticalContentAlignment" Value="Center"/>
  <Setter Property="Padding" Value="1"/>
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type Button}">
        <Microsoft_Windows_Themes:ButtonChrome x:Name="Chrome" SnapsToDevicePixels="true" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" RenderDefaulted="{TemplateBinding IsDefaulted}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}">
          <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" RecognizesAccessKey="True"/>
        </Microsoft_Windows_Themes:ButtonChrome>
        <ControlTemplate.Triggers>
          <Trigger Property="IsKeyboardFocused" Value="true">
            <Setter Property="RenderDefaulted" TargetName="Chrome" Value="true"/>
          </Trigger>
          <Trigger Property="ToggleButton.IsChecked" Value="true">
            <Setter Property="RenderPressed" TargetName="Chrome" Value="true"/>
          </Trigger>
          <Trigger Property="IsEnabled" Value="false">
            <Setter Property="Foreground" Value="#ADADAD"/>
          </Trigger>
        </ControlTemplate.Triggers>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

原则上,您需要做的就是找到ContentPresenter元素(插入按钮内容的位置)并用您自己漂亮的东西替换它周围的元素。你可以将XAML复制到你自己的项目中并乱用它,你会得到一些有用的东西。

但是:在你最终制作一个实际上你想要的按钮之前,你需要了解很多东西。其中大部分代表了功能和行为,如果你有任何像我这样的想法,当你有一个明智的想法来开发自己的按钮时,你就不必烦恼自己去思考。像:

  • 当焦点具有焦点时,该外观应该如何变化?
  • 按钮的外观在禁用时应该如何变化?
  • 哪些事件应该改变按钮的视觉外观?

您会注意到,如果您查看此模板,那么最后一个问题的很多答案都嵌入在Microsoft_Windows_Themes:ButtonChrome元素中。它在代码中所做的所有事情(例如RenderPressed)都是你必须通过触发器构建到你的XAML中的东西。 (或者你可以编写自己的类似按钮的对象。)

我想我所说的是你没有走错路,但你需要学习很多东西。

就你的第二个问题而言,是的,你可以创建一个UserControl并公开标题和图像的属性。您也可以尝试一下按钮实际上是内容控件的事实,例如:

<Button Height=50>
  <DockPanel>
    <Image Width="32" Source="image.png"/>
    <TextBlock Text="My button's caption" TextWrapping="Wrap" VerticalAlignment="Center"/>
  </DockPanel>
</Button>