开发者

WPF TriState Image Button

开发者 https://www.devze.com 2022-12-23 13:42 出处:网络
Does anyone have any pointers for creating a tristate image button? I have the following but what I really want to do is have a control with multiple ImageSource properties like <Controls.Tristat

Does anyone have any pointers for creating a tristate image button?

I have the following but what I really want to do is have a control with multiple ImageSource properties like <Controls.TristateButton Image="" HoverImage="" 开发者_开发技巧PressedImage="" />

<Style TargetType="{x:Type Button}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <StackPanel Orientation="Horizontal" >
                    <Image Name="PART_Image" Source="path to normal image" />
                </StackPanel>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="Source" Value="path to mouse over image" TargetName="PART_Image"/>
                    </Trigger>
                    <Trigger Property="IsPressed" Value="True">
                        <Setter Property="Source" Value="path to pressed image" TargetName="PART_Image"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>


I have run into the same problem myself. I have created an open source project here http://imagebuttonwpf.codeplex.com where you can get the latest version of the Image Button. I don't like the "accepted" solution provided for several reasons (Although it is a lighter solution and has its own advantages)

Blockquote The accepted answer to this StackOverflow question shows an easy way to do this: WPF - How to create image button with template

Mainly I don't think its correct to override the control template for every button you would like to change the image for so I have created a custom control called ImageButton. It extends from button so as to have any of its functionality (though it may be able to extend from content control just as easily) but also contains an Image which can be styled without rewriting the entire control template. Another reason why I don't like rewriting the entire control template for my button each time is that my base button style contains several borders and animation effects for mouse over, is pressed etc. Rewriting these each time obviously has its own redundancy problems. Anyway here is the ImageButton class

public class ImageButton : Button
{
static ImageButton() {
  DefaultStyleKeyProperty.OverrideMetadata(typeof(ImageButton), new FrameworkPropertyMetadata(typeof(ImageButton)));
}

#region Dependency Properties

public double ImageSize
{
  get { return (double)GetValue(ImageSizeProperty); }
  set { SetValue(ImageSizeProperty, value); }
}

public static readonly DependencyProperty ImageSizeProperty =
    DependencyProperty.Register("ImageSize", typeof(double), typeof(ImageButton),
    new FrameworkPropertyMetadata(30.0, FrameworkPropertyMetadataOptions.AffectsRender, ImageSourceChanged));

public string NormalImage
{
  get { return (string)GetValue(NormalImageProperty); }
  set { SetValue(NormalImageProperty, value); }
}

public static readonly DependencyProperty NormalImageProperty =
    DependencyProperty.Register("NormalImage", typeof(string), typeof(ImageButton),
    new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.AffectsRender,ImageSourceChanged));

public string HoverImage
{
  get { return (string)GetValue(HoverImageProperty); }
  set { SetValue(HoverImageProperty, value); }
}

public static readonly DependencyProperty HoverImageProperty =
    DependencyProperty.Register("HoverImage", typeof(string), typeof(ImageButton),
    new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.AffectsRender, ImageSourceChanged));

public string PressedImage
{
  get { return (string)GetValue(PressedImageProperty); }
  set { SetValue(PressedImageProperty, value); }
}

public static readonly DependencyProperty PressedImageProperty =
    DependencyProperty.Register("PressedImage", typeof(string), typeof(ImageButton),
    new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.AffectsRender, ImageSourceChanged));

public string DisabledImage
{
  get { return (string)GetValue(DisabledImageProperty); }
  set { SetValue(DisabledImageProperty, value); }
}

public static readonly DependencyProperty DisabledImageProperty =
    DependencyProperty.Register("DisabledImage", typeof(string), typeof(ImageButton),
    new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.AffectsRender, ImageSourceChanged));

private static void ImageSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
  Application.GetResourceStream(new Uri("pack://application:,,," + (string) e.NewValue));
}

#endregion

Next up we need to provide a default control template for our button ive taken most of my borders etc out of this one, bar one so you can see that it is inherited throughout all our styles

<ControlTemplate x:Key="ImageButtonTemplate" TargetType="{x:Type Controls:ImageButton}">   
<Grid x:Name="Grid">
  <Border x:Name="Background" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="3" />
  <StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center">
    <Image x:Name="ButtonImage" Source="{Binding NormalImage, RelativeSource={RelativeSource TemplatedParent}}" 
           Height="{Binding ImageSize, RelativeSource={RelativeSource TemplatedParent}}" 
           Width="{Binding ImageSize, RelativeSource={RelativeSource TemplatedParent}}"/>
    <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True" />
  </StackPanel>      
</Grid>
<ControlTemplate.Triggers>
  <Trigger Property="IsMouseOver" Value="true">
    <Setter TargetName="ButtonImage" Property="Source" Value="{Binding HoverImage, RelativeSource={RelativeSource TemplatedParent}}" />
  </Trigger>
  <Trigger Property="IsPressed" Value="true">
    <Setter TargetName="ButtonImage" Property="Source" Value="{Binding PressedImage, RelativeSource={RelativeSource TemplatedParent}}" />
  </Trigger>
  <Trigger Property="IsEnabled" Value="false">
    <Setter TargetName="ButtonImage" Property="Source" Value="{Binding DisabledImage, RelativeSource={RelativeSource TemplatedParent}}" />
  </Trigger>
</ControlTemplate.Triggers>

then of course we need a default style for our new image button

<Style TargetType="{x:Type Controls:ImageButton}" BasedOn="{x:Null}">
<Setter Property="Template" Value="{StaticResource ImageButtonTemplate}" />
</Style>

And of course the benefits of using this method i have created a style based on the parent style which uses a Setter to change the dependency properties (instead of needed to override the control template - the goal)

<Style x:Key="TestImageButton" TargetType="{x:Type Controls:ImageButton}" BasedOn="{StaticResource {x:Type Controls:ImageButton}}">
<Setter Property="NormalImage" Value="/ImageButton;component/Resources/clear.png"/>
<Setter Property="HoverImage"  Value="/ImageButton;component/Resources/clear_green.png" />
<Setter Property="PressedImage" Value="/ImageButton;component/Resources/clear_darkgreen.png" />
<Setter Property="DisabledImage" Value="/ImageButton;component/Resources/clear_grey.png" />
</Style>

and finally this means that one can declare the button in a few different ways either declare the image path in the XAML

<Controls:ImageButton 
    Content="Test Button 1" 
    NormalImage="/ImageButton;component/Resources/edit.png"
    HoverImage="/ImageButton;component/Resources/edit_black.png"
    PressedImage="/ImageButton;component/Resources/edit_darkgrey.png"
    DisabledImage="/ImageButton;component/Resources/edit_grey.png"/>

Or alternatively use the style

  <Controls:ImageButton 
    Content="Test Button 2"
    Style="{DynamicResource TestImageButton}"/>

Hope it helps


The accepted answer to this StackOverflow question shows an easy way to do this: WPF - How to create image button with template

You create property triggers on the IsEnabled and IsPressed properties and show or hide the images as needed.

As Avanka noted in his answer, you'll need to create dependency properties to set the paths to the images.


Ideally, you have to create a custom control, inherited from Button. Add three dependency properties, and create default style for new control.

You can check ImageButton class from FluidKit library - it does exactly what you want.

0

精彩评论

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

关注公众号