WPF:给我一个最好的图标按钮方式

时间:2011-08-02 23:11:11

标签: wpf templates button icons

我们可以使用控制模板轻松制作图标按钮,如下面的代码:

<Style x:Key="IconButton" TargetType="{x:Type Button}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate>
                <Grid>
                    <Image x:Name="Background" Source="/UOC;component/TOOLBAR_BUTTON_NORMAL.png"/>
                    <Image Source="/UOC;component/ICON_SLICER.gif" Width="20" Height="20" Margin="0,-10,0,0"/>
                    <TextBlock Foreground="White" FontSize="9" Text="{TemplateBinding Button.Content}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,15,0,0"/>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="Button.IsMouseOver" Value="True">
                        <Setter Property="Source" TargetName="Background" Value="/UOC;component/TOOLBAR_BUTTON_OVER.png"/>
                        <Setter Property="Cursor" Value="Hand"/>
                    </Trigger>
                    <Trigger Property="Button.IsPressed" Value="True">
                        <Setter Property="Source" TargetName="Background" Value="/UOC;component/TOOLBAR_BUTTON_CLICK.png"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

但我认为这在实践中并不是一种富有成效的方式。因为我无法为每个图标按钮制作多种样式。 (例如,我们假设App中有三个按钮:'打开'按钮,'关闭'按钮和'导航'按钮。这些按钮有不同的图标集。我不能制作像'IconButton_Close','IconButton_Open','IconButton_Nav'这样的样式这太愚蠢了。)

UserControl可能是一个答案。但我认为这不是一个聪明的方法。因为如果我创建UserControl,它将只是Button控件的包装器。这不是一个正确的方法。

所以,给我一个最佳的图标按钮方式。

感谢。

2 个答案:

答案 0 :(得分:5)

执行此操作的正确方法是定义自定义按钮类,如下所示:

public class MyButton : Button {

    static MyButton() {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(MyButton), new FrameworkPropertyMetadata(typeof(MyButton)));
    }

    public static readonly DependencyProperty ImageSourceProperty = DependencyProperty.Register("ImageSource", typeof(ImageSource),
        typeof(MyButton), new FrameworkPropertyMetadata(null);

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

    public static readonly DependencyProperty ImageSourceHoverProperty = DependencyProperty.Register("ImageSourceHover", typeof(ImageSource),
        typeof(MyButton), new FrameworkPropertyMetadata(null);

    public ImageSource ImageSourceHover {
        get { return (ImageSource)GetValue(ImageSourceHoverProperty); }
        set { SetValue(ImageSourceHoverProperty, value); }
    }

    public static readonly DependencyProperty ImageSourcePressedProperty = DependencyProperty.Register("ImageSourcePressed", typeof(ImageSource),
        typeof(MyButton), new FrameworkPropertyMetadata(null);

    public ImageSource ImageSourcePressed {
        get { return (ImageSource)GetValue(ImageSourcePressedProperty); }
        set { SetValue(ImageSourcePressedProperty, value); }
    }

}

然后定义默认样式:

<Style x:Key="{x:Type local:MyButton}" TargetType="{x:Type local:MyButton}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:MyButton}">
                <Grid>
                    <Image x:Name="Background" Source="{TemplateBinding ImageSource}" />
                    <Image Source="/UOC;component/ICON_SLICER.gif" Width="20" Height="20" Margin="0,-10,0,0"/>
                    <TextBlock Foreground="White" FontSize="9" Text="{TemplateBinding Button.Content}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,15,0,0"/>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="Button.IsMouseOver" Value="True">
                        <Setter Property="Source" TargetName="Background" Value="{TemplateBinding ImageSourceHover}"/>
                        <Setter Property="Cursor" Value="Hand"/>
                    </Trigger>
                    <Trigger Property="Button.IsPressed" Value="True">
                        <Setter Property="Source" TargetName="Background" Value="{TemplateBinding ImageSourcePressed}"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

你会这样使用它:

<local:MyButton ImageSource="/UOC;component/TOOLBAR_BUTTON_NORMAL.png"
    ImageSourceHover="/UOC;component/TOOLBAR_BUTTON_OVER.png"
    ImageSourcePressed="/UOC;component/TOOLBAR_BUTTON_CLICK.png" />

答案 1 :(得分:0)

我使用TemplatePart属性为自定义控件做了类似的事情。这会在面板中显示图标和一些文本。如果图标是错误或失败图标,则会将文本变为红色。有一个名为“Type”的依赖属性,它实际上只是没有扩展名的图像文件名。这是代码,我敢打赌你可以为自定义按钮进行调整,你可以在其中设置源代码,并且仍然可以自定义模板。

[TemplatePart(Name = "PART_Image", Type = typeof(Image))]
public class IconPanel : ContentControl
{
    static IconPanel()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(IconPanel), new FrameworkPropertyMetadata(typeof(IconPanel)));
}


public string Type
{
    get { return (string)GetValue(TypeProperty); }
    set { SetValue(TypeProperty, value); }
}

public static readonly DependencyProperty TypeProperty =
    DependencyProperty.Register("Type", typeof(string), typeof(IconPanel), 
    new UIPropertyMetadata("warning", TypeChangedCallback));

static void TypeChangedCallback(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
    IconPanel panel = obj as IconPanel;
    panel.UpdateImage();
}

void UpdateImage()
{
    Image img = GetTemplateChild("PART_Image") as Image;
    if (img == null) return;
    string ImagePath = String.Format("pack://application:,,,/Resources/{0}.png", this.Type);
    Uri uri = new Uri(ImagePath, UriKind.RelativeOrAbsolute);
    BitmapImage bmp = new BitmapImage(uri);
    img.Source = bmp;
    if ( String.Compare(Type, "error", true) == 0 ||
        String.Compare(Type, "fail", true) == 0 )
    {
        this.Foreground = new SolidColorBrush(Color.FromRgb(0xFF, 0x00, 0x00));
    }
}

public override void OnApplyTemplate()
{
    UpdateImage();
    base.OnApplyTemplate();
    }
}

XAML:

<Style TargetType="{x:Type local:IconPanel}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:IconPanel}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            Padding="7">
                        <Grid Background="{TemplateBinding Background}">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="*"/>
                            </Grid.ColumnDefinitions>
                                <Image
                                    x:Name="PART_Image"
                                    Margin="0,0,5,5"
                                    VerticalAlignment="Top"
                                    HorizontalAlignment="Left"
                                    Width="16" 
                                    Height="16" />
                            <ContentPresenter Grid.Column="1"/>
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>