How to interpret the style programmatically - wpf

In my application I have to manipulate a DataGrid in code-behind (The DataGrid is also created in code-behind in runtime), and I want to set below styles for the DataGrid
<DataGrid.RowHeaderStyle>
<Style TargetType="DataGridRowHeader">
<Setter Property="Visibility" Value="Collapsed"/>
<Setter Property="Template" Value="{x:Null}"/>
</Style>
</DataGrid.RowHeaderStyle>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="DataGridRow">
<Border BorderThickness="{TemplateBinding Border.BorderThickness}" BorderBrush="{TemplateBinding Border.BorderBrush}" Background="{TemplateBinding Panel.Background}" Name="DGR_Border" SnapsToDevicePixels="True">
<SelectiveScrollingGrid> <!--How to translate this-->
<DataGridCellsPresenter ItemsPanel="{TemplateBinding ItemsControl.ItemsPanel}" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}"/>
</SelectiveScrollingGrid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.RowStyle>
Below is the my interpreted code, but I do not know how to 'translate' the SelectiveScrollingGrid part
var myGrid = new DataGrid
{
RowHeaderStyle = new Style(typeof(DataGridRowHeader)),
RowStyle = new Style(typeof(DataGridRow))
};
myGrid.RowHeaderStyle.Setters.Add(new Setter(VisibilityProperty, Visibility.Collapsed));
myGrid.RowHeaderStyle.Setters.Add(new Setter(DataGridRowHeader.TemplateProperty, null));
ControlTemplate templateButton = new ControlTemplate(typeof(DataGridRow));
FrameworkElementFactory elemFactory = new FrameworkElementFactory(typeof(Border));
elemFactory.SetValue(Border.BorderThicknessProperty, new TemplateBindingExtension(Border.BorderThicknessProperty));
elemFactory.SetValue(Border.BorderBrushProperty, new TemplateBindingExtension(Border.BorderBrushProperty));
elemFactory.SetValue(Border.BackgroundProperty, new TemplateBindingExtension(Panel.BackgroundProperty));
elemFactory.SetValue(Border.NameProperty, "DGR_Border");
elemFactory.SetValue(Border.SnapsToDevicePixelsProperty, true);
var cellsPresenterFactory = new FrameworkElementFactory(typeof(DataGridCellsPresenter));
cellsPresenterFactory.SetValue(DataGridCellsPresenter.ItemsPanelProperty, new TemplateBindingExtension(ItemsControl.ItemsPanelProperty));
cellsPresenterFactory.SetValue(DataGridCellsPresenter.SnapsToDevicePixelsProperty, new TemplateBindingExtension(UIElement.SnapsToDevicePixelsProperty));
//elemFactory.AppendChild(selectiveScrollingGridFactory);
templateButton.VisualTree = elemFactory;
elemFactory.AppendChild(new FrameworkElementFactory(typeof(ContentPresenter)));

Just create another FrameworkElementFactory with a type of System.Windows.Controls.Primitives.SelectiveScrollingGrid:
...
var selectiveScrollingGridFactory = new FrameworkElementFactory(typeof(System.Windows.Controls.Primitives.SelectiveScrollingGrid));
elemFactory.AppendChild(selectiveScrollingGridFactory);
var cellsPresenterFactory = new FrameworkElementFactory(typeof(DataGridCellsPresenter));
cellsPresenterFactory.SetValue(DataGridCellsPresenter.ItemsPanelProperty, new TemplateBindingExtension(ItemsControl.ItemsPanelProperty));
cellsPresenterFactory.SetValue(DataGridCellsPresenter.SnapsToDevicePixelsProperty, new TemplateBindingExtension(UIElement.SnapsToDevicePixelsProperty));
selectiveScrollingGridFactory.AppendChild(selectiveScrollingGridFactory);
...
Note that the recommended way to programmatically create a template is to load XAML from a string or a memory stream using the Load method of the XamlReader class as stated in the documenation on MSDN: https://msdn.microsoft.com/en-us/library/system.windows.frameworkelementfactory(v=vs.110).aspx

Related

Add new brush property in VS WPF designer

I'm creating a new button control, and I wanted to create a new property under the brushes section where I can set the hovercolor. Anyone know how you would do this?
The simplest way to add a property that will appear in the "Brush" section of the Properties panel is to - define a Brush property in control's class code:
public partial class MyFancyControl : UserControl
{
// ...
public Brush FancyBrush
{
get;
set;
}
// ...
}
The property will show in "Brush" section with no further action (at least it does in my VS2013, see below).
While such a property will work just fine in most cases, the proper way to do it is to define it as a DependencyProperty:
public partial class MyFancyControl : UserControl
{
// ...
public Brush FancyBrush
{
get
{
return (Brush)GetValue(FancyBrushProperty);
}
set
{
SetValue(FancyBrushProperty, value);
}
}
public static readonly DependencyProperty FancyBrushProperty =
DependencyProperty.Register("FancyBrush", typeof(Brush), typeof(IntUpDown), new PropertyMetadata(default(Brush)));
// ...
}
Using DependencyProperty will enable binding and other "advanced" stuff.
Tip: Use VS Intellisense helpers to avoid need to type all the surrounding code - type "propdp" and press Tab twice.
To make sure the property will show up in the correct section of the Properties panel, add the Category attribute:
[System.ComponentModel.Category("Brush")]
public Brush FancyBrush
{...
Again, this seems to work automatically for Brush type so it may not be necessary.
You can also add a Description attribute that will show in the tooltip in the Properties panel:
[System.ComponentModel.Description("Gets or sets a brush that defines fancy look of the control.")]
You can just create the brush and add it as a resource something like:
<SolidColorBrush x:Key="MouseOverColor" Color="#FFFFFFF"/>
Then in the template triggers in your button template:
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="ButtonBorder" Property="Background" Value="StaticResource MouseOverColor}"/>
</Trigger>
Here is a simple button from in a resource dictionary file that uses defined brushes:
<SolidColorBrush x:Key="SelectionHighlightBrush" Color="#282828"/>
<SolidColorBrush x:Key="SelectionHighlightTextBrush" Color="White"/>
<SolidColorBrush x:Key="ForegroundBrush" Color="#282828"/>
<SolidColorBrush x:Key="ControlBackgroundBrush" Color="White"/>
<SolidColorBrush x:Key="ControlBorderBrush" Color="#C0C0C0" />
<Style TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="{StaticResource ForegroundBrush}"/>
<Setter Property="Background" Value="{StaticResource ControlBackgroundBrush}"/>
<Setter Property="BorderBrush" Value="{StaticResource ControlBorderBrush}"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate x:Name="temp" TargetType="ToggleButton">
<Border x:Name="bd" CornerRadius="3"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter x:Name="contentPresenter" Margin="{TemplateBinding Padding}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bd" Property="Background" Value="{StaticResource SelectionHighlightBrush}"/>
<Setter Property="TextElement.Foreground" Value="{StaticResource SelectionHighlightTextBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Custom control's properties not changing when used in a template

I have created a custom control (inherits Control) that exposes a single enumerated DependencyProperty. The default control template renders differently based on the selected value for the property using Triggers to turn elements on/off. The control works great when placed directly into a UserControl for viewing in the UI. However, the point of the control is to exist as part of a large composite control so it is also used in the ControlTemplate of another custom control. When I do so, changes to the dependency property are not recognized by the control. I verified this by adding a PropertyChangedCallback to the dependency property and setting a break point which is never hit.
For example, when I use "CustomControl" in a template like this:
<ControlTemplate>
<my:CustomControl EnumProperty="EnumValue" />
</ControlTemplate>
The EnumProperty (which is a DependencyProperty) is not changed to "EnumValue" and it remains the default value. And, as I said, a breakpoint in the PropertyChangedCallback for the DP is never called.
What am I missing?
UPDATE
Here is a cleansed version of my control:
public class CustomControl : Control
{
static CustomControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl), new FrameworkPropertyMetadata(typeof(CustomControl)));
}
public StandardIcon()
: base()
{
BorderType = BorderType.None;
}
public static readonly DependencyProperty BorderTypeProperty = DependencyProperty.Register("BorderType", typeof(BorderType), typeof(CustomControl), new PropertyMetadata(BorderType.None));
public BorderType BorderType
{
get { return (BorderType)GetValue(BorderTypeProperty); }
set { SetValue(BorderTypeProperty, value); }
}
}
<Style TargetType="{x:Type local:CustomControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomControl}">
<Border x:Name="Rectangle"
BorderBrush="{TemplateBinding Foreground}"
BorderThickness="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<ContentPresenter ContentSource="Content" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="BorderType" Value="Rectangle">
<Setter Property="BorderThickness" TargetName="Rectangle" Value="2" />
</Trigger>
<Trigger Property="BorderType" Value="RoundedRectangle">
<Setter Property="BorderThickness" TargetName="Rectangle" Value="2" />
<Setter Property="CornerRadius" TargetName="Rectangle" Value="5" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And this is how it is being used within another control (notice that it is in a DataTemplate and not a ControlTemplate as I originally indicated).
<Style TargetType="{x:Type local:OtherControl}">
<Setter Property="FontFamily" Value="{x:Static theme:StandardFonts.FontFamily}" />
<Setter Property="FontSize" Value="{x:Static theme:StandardFonts.FontSizeXS}" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<local:CustomControl BorderType="{Binding TemplatedParent.BorderType, RelativeSource={RelativeSource TemplatedParent}}"
Foreground="{Binding TemplatedParent.Foreground, RelativeSource={RelativeSource TemplatedParent}}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And then it is used like this:
<controls:OtherControl Foreground="Red" BorderType="Rectangle" />
The Foreground property IS changing as expected. When I change the Foreground of the OtherControl, the Foreground of the CustomControl is changed. But the BorderType property is not being respected - it always renders with the default BorderType.None value.
The parent of your ControlTemplate needs to have something for your CustomControl to bind to. Then, you bind the CustomControl in your template to the parent.
In the following example, I'm using a Border to template a Button, which binds its BorderBrush to the Button's Background:
<ControlTemplate TargetType="{x:Type Button}">
<Border BorderBrush="{TemplateBinding Background}" />
</ControlTemplate>
Replace Button with your "large composite control" and Border with my:CustomControl and you should be set...

WPF change style (with trigger) programmatically

I need to change the background of the selected item in a list view, programmatically.
The style currently looks like this (as default)
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background">
<Setter.Value>
<ImageBrush ImageSource="images/selection-large.png"/>
</Setter.Value>
</Setter>
</Trigger>
I need to be able to change that background image of the selected item programmatically.
I have attempted to do this myself however i am not really sure how to go about it.
I did notice that the listview has a styles property but other than that i am completely stumped.
I am using VB.net
Edit
Would something like this work? and if so, what am i doing wrong? My listview is completely invisible with this code.
Dim trigger As New Trigger()
trigger.Property = ListViewItem.IsSelectedProperty
trigger.Value = True
trigger.Setters.Add(New Setter(ListViewItem.BackgroundProperty, Brushes.Pink))
mylistview.Style.Triggers.Add(trigger)
mylistview.ItemContainerStyle = Style
Bind your IsSelected property to some bool value in the ViewModel and toggle that.
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsSelected" Value="{Binding IsSelected}"/>
</Style>
</ListView.ItemContainerStyle>
Item ViewModel:
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
_isSelected = value;
NotifyPropertyChange("IsSelected");
}
}
In WPF you don't manipulate UI elements in procedural code, instead you use DataBinding and manipulate your models / ViewModels' properties
As an aside, I recommend against using PNG or other bitmap based stuff for regular UI elements in WPF.
Instead of that you should create your UI using WPF elements which are vector-based and thus resolution independent.
You can do this within the XAML, Try this:
<Window.Resources>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Background">
<Setter.Value>
<ImageBrush ImageSource="images/selection-large.png"/>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
I was able to finally work it out..
All i had to do was make another style based on the first one and give them both different x:keys.. Then i was able to change styles like this.
mylistview.ItemContainerStyle = DirectCast(FindResource("XKeyName"), Style)

Include XAML Trigger To ControlTemplate

I am pretty new with WPF and am doing some custom control stuff...
My problem is that the code in one file is going to be way to much, so i want
to split the code in seperate files, so other people looking in that code aren´t going to be overwhelmed.
Okay to my question...
I got a ResourceDictionary... the "Generic.xaml"
In this file a got the template of an DataGrid:
<Style TargetType="{x:Type local:BADataGrid}">
<Style.Setters>
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="local:BADataGrid">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}"
SnapsToDevicePixels="True">
<!-- *SOME TEMPLATE CODE* -->
</Border>
<ControlTemplate.Triggers>
<Trigger Property="GridStyle" Value="CUSTOMER">
<Trigger.Setters>
<Setter Property="ColumnHeaderStyle">
<Setter.Value>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Background">
<Setter.Value>
<ImageBrush>
<ImageBrush.ImageSource>
<Binding Path="HeaderBackground" RelativeSource="{RelativeSource AncestorType=local:BADataGrid}">
<Binding.TargetNullValue>
<ImageSource>
headerBack.png
</ImageSource>
</Binding.TargetNullValue>
</Binding>
</ImageBrush.ImageSource>
</ImageBrush>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Trigger.Setters>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
Now I want the "ControlTemplate.Triggers" part of the code above in another .XAML File.
Is this even possible?
it´s me again. Sorry it took me so long to answer.
I am a few steps ahead now... I got the Trigger in an additional ResourceDictionary, and if I impletment it in the "Window.Resources" where I implement the control everything works just fine.
My problem now is... I don´t want to implement the ResourceDictionary in the "Window.Resources" but in the "ControlTemplate.Resources" of my custom control. But when I do so it tell´s me :
"Unable to cast object of type 'Microsoft.Expression.Markup.DocumentModel.DocumentCompositeNode' to type 'System.Windows.ResourceDictionary'.
<ControlTemplate.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="Customer.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</ControlTemplate.Resources>
If I copy the code inside the Customer.xaml ResourceDictionary into the ControlTemplate.Resources it works... but I want it in an additional file...
Any ideas?
Look into Resource Dictionaries. That should allow you to split styles across files.
Did it with a nasty workaround... I´ll just share it with you.
I just implemented an event that is fired when the DataGrid is loaded.
In this event I load the ResourceDictionarys i wanted to add to the control template
in ResourceDictionary object´s. Then i iterate through all entrys in the ResourceDictionary object and add each seperate to the ControlTemplate´s resources...
Here´s the code:
void DataGridLoaded(object sender, RoutedEventArgs e)
{
BADataGrid dg = (BADataGrid)VisualTreeHelper.GetParent((DependencyObject)sender);
List<string> resourceList = new List<string>();
resourceList.Add(Properties.Resources.Customer);
foreach (string s in resourceList)
{
System.Xml.XmlReader xmlReader = new System.Xml.XmlTextReader(new System.IO.StringReader(s));
ResourceDictionary resource = (ResourceDictionary)XamlReader.Load(xmlReader);
foreach (System.Collections.DictionaryEntry item in resource)
{
dg.Resources.Add(item.Key, item.Value);
}
}

WPF TriState Image Button

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.

Resources