Reputation: 1420
In a WPF application I have a style used for buttons:
<Style TargetType="Button" x:Key="ButtonEllipse">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<StackPanel Orientation="Vertical">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0 0 0 10"/>
<Image x:Name="ButtonImage" HorizontalAlignment="Center" VerticalAlignment="Center" Stretch="None" Source="/MyProject;component/Images/ButtonEllipse.png"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
For most buttons that is OK but for one specific instance I want to use the same template but change the image to ButtonEllipseNew.png (which is the value of a view model property). The button is defined like this:
<Button Content="Test" Style="{StaticResource ButtonEllipse}">
</Button>
How can I change the value of the image source in the template only for this specific button? I want to bind the source to a property in the view model.
Upvotes: 0
Views: 5230
Reputation: 784
In order to bind a property to your style you should do the following:
Create a user control let's name it ButtonImage.cs
public class ButtonImage : Button
{
public ImageSource Source
{
get
{
return (ImageSource)GetValue(SourceProperty);
}
set
{
SetValue(SourceProperty, value);
}
}
public static readonly DependencyProperty SourceProperty =
DependencyProperty.Register("Source",
typeof(ImageSource),
typeof(ButtonImage),
new PropertyMetadata(null));
}
I would create a ResourceDictionary so you can use it for all your styles. Let's name it Dictionary.xaml. An there you define your style like:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication4">
<Style TargetType="{x:Type local:ButtonImage}" x:Key="ButtonEllipse">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ButtonImage}">
<StackPanel Orientation="Vertical">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0 0 0 10"/>
<Image x:Name="ButtonImage" HorizontalAlignment="Center" VerticalAlignment="Center" Stretch="None" Source="{TemplateBinding Source}"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Then in your view you can do:
<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:wpfApplication4="clr-namespace:WpfApplication4"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="Dictionary.xaml">
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<wpfApplication4:ButtonImage Margin="0,50,0,0" Content="Test" Source="{Binding Name}" Style="{StaticResource ButtonEllipse}" />
</Grid>
</Window>
Upvotes: 0
Reputation: 166
I would write a custom control that looks something like this:
internal class IconButton : Button
{
public ImageSource Source
{
get { return (ImageSource)GetValue(SourceProperty); }
set { SetValue(SourceProperty, value); }
}
public static readonly DependencyProperty SourceProperty =
DependencyProperty.Register("Source", typeof(ImageSource), typeof(IconButton), new PropertyMetadata(null));
}
Then edit your style to accommodate it:
<Style TargetType="{x:Type location:IconButton}" x:Key="ButtonEllipse">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type location:IconButton}">
<StackPanel Orientation="Vertical">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0 0 0 10"/>
<Image x:Name="ButtonImage" HorizontalAlignment="Center" VerticalAlignment="Center" Stretch="None" Source="{TemplateBinding Source"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
Where location is a xaml-defined namespace where the IconButton class is placed.
Then just set the Source
property of your button. You can mess around with the Source property to set a default as well.
Upvotes: 1
Reputation: 169420
I am afraid you can't reuse only a part of a ControlTemplate
. You must define the template as a whole:
WPF: Is there a way to override part of a ControlTemplate without redefining the whole style?
What you could do is to bind the Source
property of the Image
in the template to some property that you can then set individually for each control to which the template is applied:
<Style TargetType="Button" x:Key="ButtonEllipse">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<StackPanel Orientation="Vertical">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0 0 0 10"/>
<Image x:Name="ButtonImage" HorizontalAlignment="Center" VerticalAlignment="Center" Stretch="None"
Source="{Binding Tag, RelativeSource={RelativeSource AncestorType=Button}}"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
...
<Button Content="Test" Style="{StaticResource ButtonEllipse}" Tag="image.png" />
Upvotes: 4