开发者

WPF : give me a best way for icon button

We can easily make an icon button using a control template like the following code:

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

But i think it's not a productive way in practice. because i can't make a number of styles for each one of icon buttons. (ex. let's assume three buttons in App:'open' button, 'close' button and 'navigate' button. these buttons have different icon sets. i can't make styles like 'IconButton_Close', 'IconButton_Open', 'IconButton_Nav'. it's too stupid.)

UserControl may be an answer. but i think it's not a smart way for that. because if i make UserControl, it'll be just a wrapper of the Button control. it's not a right way.

So, give me the best way for icon button.

thanks.


The correct way to do this would be to define a custom button class, like so:

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

    }

Then define the default Style like so:

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

And you'd use it like so:

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


I did something similar to this for a custom control a while back using the TemplatePart attribute. This displays an icon and some text in a panel. If the icons is the error or fail icon, it turns the text red. There is a dependency property called "Type" which is really just the image file name without the extension. Here's the code, I bet you can adapt this for a custom Button where you can set the source and still have your customization to the template.

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜