WPF Custom Control for Side by Side Layout - wpf

I want to create a custom control so that I can do something like this:
<SideBySide>
<StackPanel SideBySide.Left="True">...</StackPanel>
<StackPanel SideBySide.Right="False">...</StackPanel>
</SideBySide>
I'm going to be using this all over the place, with obviously more options (sizing, etc.).
I've considered using a Panel subclass, but that doesn't seem right (there's a notion of a selected item between the left and the right).
So, I'm trying to use a ItemsControl subclass -- now, does anyone know how to put the items in a control template for an ItemsControl?
This is an abbreviated template for the SideBySide:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfCustomControlLibrary1">
<Style TargetType="{x:Type local:SideBySideControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:SideBySideControl}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Grid.Resources>
<Style TargetType="{x:Type Rectangle}">
<Setter Property="Margin"
Value="5" />
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0"
VerticalAlignment="Stretch">
<!-- PART_LeftContent goes here -->
</Grid>
<GridSplitter Width="3"
Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Stretch"
ShowsPreview="False">
</GridSplitter>
<Grid Grid.Column="2">
<!-- PART_RightContent goes here -->
</Grid>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

The direct answer is that you need an ItemsPresenter in your ControlTemplate, which would look something like this:
<ItemsControl x:Class="ItemsControlExample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<Border SnapsToDevicePixels="True">
<!-- Collection items are displayed by the ItemsPresenter. -->
<ItemsPresenter SnapsToDevicePixels="True" />
</Border>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<!-- Replace the default vertical StackPanel with horizontal. -->
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="...">
<!-- The same container style applies to all items so where do you put the splitter? -->
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
But it should be obvious now that ItemsControl doesn't align to your use case. However, you can implement it as a Control using the ControlTemplate you already have with a ContentControl the PART_LeftContent and PART_RightContent grid cells:
<!-- LeftSideContent is a DependencyProperty of type object -->
<ContentControl x:Name="LeftContentControl" Content="{TemplateBinding LeftSideContent}" />
Then extend your code to handle the ContentControl mouse events in order to select and add style triggers for the selected appearance, but that's pretty straightforward stuff. If you haven't implemented lookless controls before you should be aware that you can't define event callbacks in the template, but instead have to hook them in your code:
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
ContentControl lc = (ContentControl)base.GetTemplateChild("LeftContentControl"));
// check for null in case the active template doesn't have a 'LeftContentControl' element
if (lc != null)
{
// Use these events to set SelectedItem DependencyProperty and trigger selected item
// highlight style. Don't forget to capture the mouse for proper click behavior.
lc.MouseDown += new MouseButtonEventHandler(LeftSide_MouseDown);
lc.MouseUp += new MouseButtonEventHandler(LeftSide_MouseUp);
}
}

Related

WPF Custom Control can not take direct content

I can't put any direct content in my custom control, have a look:
<Style TargetType="local:MyCustomControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:MyCustomControl">
<Grid>
<Viewport3D />
<!-- the viewport is working (proof provided) -->
<!-- both borders are needed -->
<Border>
<Border>
<ContentPresenter />
</Border>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
the class is derived from Control, in the static constructor DefaultStyleKeyProperty.OverrideMetadata is set.
When I try to use MyCustomControl:
<local:MyCustomControl VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<TextBlock Margin="10,0,0,0" FontSize="16" Text="some test value" />
</local:MyCustomControl>
this error message is shown:
Cannot add content to object of type MyCustomControl
MyNamespace.MyCustomControl
What could be the problem? Is somthing wrong with the Contentpresenter?
I think you should bind your Content to your Presenter
<ContentPresenter Content="{TemplateBinding Content}"/>
Thanks ZerO, this was an excellent hint:
MyCustomControl derived from Control - now it derives from ContenControl.
After changing the base class I am now able to bind like suggested by ZerO.
<ContentPresenter Content="{TemplateBinding Content}"/>
problem solved!

Can't set both ContentTemplateSelector and Template properties on a DataGridColumnHeader

In short, the question title says it all. For those that want more detail, here is the crux of my problem: I need to apply a custom ControlTemplate to the DataGridColumnHeader elements in my DataGrid control, but I also need to style them differently, depending on the cell data nearest the header. However, when I set both the ContentTemplateSelector and Template properties on a DataGridColumnHeader element, the DataTemplateSelector that is set as the value of the ContentTemplateSelector property is not called. Commenting out the Template property setting confirms this to be the case, as the DataTemplateSelector element will now be called.
Yes, I know that you guys love to see some code, but I have completely templated the whole DataGrid control to look like Excel, so as you can imagine, I have far too much code to display here. But just to please you code hungry devs, I've recreated my problem in a much simpler example... let's first see the XAML:
<Window x:Class="WpfApp1.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:Local="clr-namespace:WpfApp1"
xmlns:System="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid>
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
<DataGrid.Items>
<System:String>One</System:String>
<System:String>Two</System:String>
<System:String>Three</System:String>
</DataGrid.Items>
<DataGrid.Resources>
<Local:StringDataTemplateSelector x:Key="StringDataTemplateSelector" />
<Style TargetType="{x:Type DataGridColumnHeader}" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">
<Setter Property="ContentTemplateSelector" Value="{StaticResource StringDataTemplateSelector}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid>
<Thumb x:Name="PART_LeftHeaderGripper" HorizontalAlignment="Left" />
<Thumb x:Name="PART_RightHeaderGripper" HorizontalAlignment="Right" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.Resources>
</DataGrid>
</Grid>
</Window>
Now the most simple DataTemplateSelector class:
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
namespace WpfApp1
{
public class StringDataTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
Debugger.Break();
return null;
}
}
}
In the XAML, we see a DataGrid, with just one DataGridTemplateColumn and three string values, one on each row, and some resources. There is a Style for the DataGridColumnHeader element in the Resource section, with the most simple ControlTemplate set up for it, that only includes the required named parts from the default ControlTemplate.
If you run the application as it is, then it will NOT currently break at the Debugger.Break() method in the StringDataTemplateSelector class. This is unexpected. If you now comment out the setting of the Template property in the Style and run the application again, then you will now see that program execution will now break at the Debugger.Break() method, as expected.
Further information:
In the Remarks section of the ContentControl.ContentTemplateSelector Property page of MSDN, it states that
If both the ContentTemplateSelector and the ContentTemplate properties are set, then this property is ignored.
However, it does not mention the Template property and there is also no mention of this on the Control.Template Property page on MSDN.
Furthermore, I tried this same setup using a simple Button control and can confirm that setting both the ContentTemplateSelector and the ContentTemplate properties on that does NOT stop the StringDataTemplateSelector class from being called:
<ItemsControl>
<ItemsControl.Resources>
<Local:StringDataTemplateSelector x:Key="StringDataTemplateSelector" />
<Style TargetType="{x:Type Button}">
<Setter Property="ContentTemplateSelector" Value="{StaticResource StringDataTemplateSelector}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Ellipse Stroke="Red" StrokeThickness="1" Width="{TemplateBinding ActualWidth}" Height="{TemplateBinding Height}" />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ItemsControl.Resources>
<Button Content="One" />
<Button Content="Two" />
<Button Content="Three" />
</ItemsControl>
So, what I'm after is a way to apply a custom ControlTemplate element to the DataGridColumnHeader objects, yet still be able to have the DataTemplateSelector class called during the rendering process.
add a content presenter in your controltemplate?
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid>
<Thumb x:Name="PART_LeftHeaderGripper" HorizontalAlignment="Left" />
<Thumb x:Name="PART_RightHeaderGripper" HorizontalAlignment="Right" />
<ContentPresenter></ContentPresenter>
</Grid>
</ControlTemplate>

Have my cake and eat it too: Binding a Container and It's Contents

I have a custom control, Cake, that contains two DependencyProperties named Slice and Filling. How do I create a style that gives me access to Slice, but also lets me design slice?
<Style TargetType={x:Type local:Cake}>
//I don't like setting DataContext Here
<Setter Property="DataContext" Value="{Binding RelativeSource={RelativeSource Self}}/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType={x:Type local:Cake}>
<Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}">
//This is how I display a slice
<ContentPresenter Content={Binding Slice}/>
//This is how cake decorations are displayed
<ItemsPresenter/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Slice">
<Setter.Value>
//Design Slice Here - it's easy to override when I want
<Slice Filling={Binding Filling}> // it's just in a setter.
</Setter.Value>
</Setter>
<Setter Property="DataContext" Value="{Binding RelativeSource={RelativeSource Self}}/>
</Style>
Options I've tried:
I can't use a UserControl, because I want to allow named content, which apparently doesn't work with User Controls. See Here.
I don't like the example above because I have to set the DataContext of the Cake container to self, meaning a user can't use the DataContext for their
bindings.
I can't bind the Filling property using RelativeSource, because with several
cakes, the Style wouldn't know which one was the correct parent. See
Here.
I could replace the Content Presenter directly with a Slice Element,
but because it is in a template, I loose access to the Slice Anywhere
outside the Template. While I could probably typecast my way down the visualTree to the slice, this feels a maintenance nightmare.
I basically want each cake to have a slice, and to be able to set it using
<Cake.Slice>
<DockPanel>
<Rectangle Background= “Blue”/>
<Rectangle Background= “Blue”/>
<Rectangle Background=“{Binding Filling}”/>
</DockPanel>
</Cake.Slice>
while also giving it a default look.
EDIT:
Apparently my style DOES work, provided that I reference the Cake.dll as opposed to the Cake project. Why would that be?
This won't be exactly what you need, but I hope it will give you pointers how to achieve that.
First, you don't need to set DataContext to the control itself, you can bind to properties on the Cake control (Filling and Slice) from Cake's ControlTemplate using {TemplateBinding Slice}, which is just a shortcut for {Binding Slice, RelativeSource={RelativeSource TemplatedParent}} (so you can use one or the other).
This will be a simplified version of your control, as I don't know which items the ItemPresenter in your ControlTemplate should present, or what is the Type of your Slice and Filling properties. In this example Filling is SolidColorBrush, and Slice is a Style. That style is applied to a ContentControl within Cake's ControlTemplate, so you can have predefined styles for slices, and apply the filling of your choice (if your Slice property has different purpose, you can introduce another property called SliceStyle for example).
Cake control:
public class Cake : Control
{
static Cake()
{
DefaultStyleKeyProperty.OverrideMetadata(
typeof(Cake),
new FrameworkPropertyMetadata(typeof(Cake)));
}
public SolidColorBrush Filling
{
get { return (SolidColorBrush)GetValue(FillingProperty); }
set { SetValue(FillingProperty, value); }
}
public static readonly DependencyProperty FillingProperty =
DependencyProperty.Register(
"Filling",
typeof(SolidColorBrush),
typeof(Cake),
new PropertyMetadata(Brushes.Transparent));
public Style Slice
{
get { return (Style)GetValue(SliceProperty); }
set { SetValue(SliceProperty, value); }
}
public static readonly DependencyProperty SliceProperty =
DependencyProperty.Register(
"Slice",
typeof(Style),
typeof(Cake),
new PropertyMetadata(null));
}
Default Style (Generic.xaml):
<Style TargetType="{x:Type local:Cake}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:Cake}">
<ContentControl Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
Style="{TemplateBinding Slice}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Different slice styles (these are setting ControlTemplate for ContentControl, so you will not hit the issue number 3 in your question):
<Window.Resources>
<Style x:Key="TwoLayeredSlice" TargetType="{x:Type ContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Rectangle Fill="{Binding Filling,
RelativeSource={RelativeSource AncestorType={x:Type local:Cake}}}"/>
<Rectangle Fill="Brown"
Grid.Row="1"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="FourLayeredSlice" TargetType="{x:Type ContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Rectangle Fill="{Binding Filling,
RelativeSource={RelativeSource AncestorType={x:Type local:Cake}}}"/>
<Rectangle Fill="Brown"
Grid.Row="1"/>
<Rectangle Fill="{Binding Filling,
RelativeSource={RelativeSource AncestorType={x:Type local:Cake}}}"
Grid.Row="2"/>
<Rectangle Fill="Brown"
Grid.Row="3"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
And the control in use:
<Grid Background="Gray">
<local:Cake Width="200"
Height="100"
HorizontalAlignment="Left"
Filling="Gold"
Slice="{StaticResource TwoLayeredSlice}"/>
<local:Cake Width="200"
Height="100"
HorizontalAlignment="Center"
Filling="Pink"
Slice="{StaticResource FourLayeredSlice}"/>
<local:Cake Width="200"
Height="100"
HorizontalAlignment="Right"
Filling="Blue"
Slice="{StaticResource FourLayeredSlice}"/>
</Grid>
Bon appetit!

WPF Style: Generalizing

Following being WPF style, is there a way to generalize the hard-coded column names (Name and Code), so that I could specify them when actually applying this style on a ComboBox? Even better, if I could even modify the number of columns?
<Style TargetType="ComboBox" x:Key="MultiColumnComboBoxStyle">
<Style.Resources>
<Style TargetType="ComboBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBoxItem">
<Border>
<Grid HorizontalAlignment="Stretch" TextElement.FontWeight="Normal">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" SharedSizeGroup="Code" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Path=Name}" />
<Rectangle Grid.Column="1" Width="1" Fill="Black" />
<TextBlock Grid.Column="2" Text="{Binding Path=Code}" Margin="5,0,5,0" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Style.Resources>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<StackPanel Grid.IsSharedSizeScope="True" IsItemsHost="True" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
instead of using a style you could consider craeting a custom control with a dependency property for your columns.
a little bit of setup involved but It will better meet your needs, especialy if you want to reuse it.
an example would be something like the following. Some of this is psuedo code you should be able to fill out.
<!-- In your generic.xaml file -->
<Style TargetType="MyCustomComboBox" >
<Setter Property="Template" >
<Setter.Value>
<ControlTemplate TargetType="MyCustomComboBox" >
<!-- your template code goes here -->
<Grid x:Name="_myCustomGrid />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
//then in a cs file inherit from the combo box
public class MyCustomColumnComboBox : ComboBox //get all the combobox functionality
{
public IList ComboColumns
{
get { return (IList)GetValue(ComboColumnsProperty);}
set { SetValue(ComboColumnsProperty,value);}
}
public static readonly DependencyProperty ComboColumnsProperty = DependencyProperty.RegisterProperty(...);
private Grid _grid;
public override OnApplyTemplate()
{
//pull your template grid info here, then use that when setting the columns.
_grid = GetTemplateChild("_myCustomGrid") as Grid;
//from here you can check to see if you have your list yet,
//if you don't then you maintain the grid for when you do have your list.
// This can behave different depending on if you are in wpf or silverlight,
// and depending on how you were to add the items to the dependency property.
}
}
In Summary, for you, add the custom control with the custom dependency property, then in your theme/generic.xaml drop in your template and name the grid to what you want to pull into your template in the on apply template function. from there you are either ready to set up or can set up your columns that you specified in the dependency property.
NOTE : The dependency property isn't actually necessary but it can help to buy you a little bit more flexibility later on using things like the dependency properties on change callback to update if necessary.

How to bind Fill property to a custom property into a controltemplate

I have a button control which its template is stilyzed in an external resource Theme.xaml. Below the controltemplate definition:
<ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type Button}">
<Grid x:Name="Grid">
<Border x:Name="Background" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="2,2,2,2" CornerRadius="2,2,2,2">
<Border x:Name="Hover" Background="{StaticResource HoverBrush}" CornerRadius="1,1,1,1" Height="Auto" Width="Auto" Opacity="0"/>
</Border>
<StackPanel Orientation="Horizontal" Margin="2,2,2,2">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True" />
</StackPanel>
...
Now I added an item which is an ellipse that must be filled with red or green color (as a semaphore) depending on a custom property defined into my usercontrol:
<UserControl.Resources>
<ResourceDictionary Source="Themes/theme.xaml"/>
</UserControl.Resources>
<Grid>
<Button Click="Button_Click"></Button>
<Ellipse x:Name="ellipse1" Width="20" Height="20" Margin="5,40,45,5"></Ellipse>
</Grid>
and in the behind code I have:
private SolidColorBrush ButtonValue_;
public SolidColorBrush ButtonValue {
get { return ButtonValue_; }
set {
ButtonValue_ = value;
}
}
I'm trying to put into the CONTROLTEMPLATE this ellipse item, but i have some problems regarding how to BIND the Fill property of the ellipse with the ButtonValue custom property into the controlTemplate.
Any hints??
Thanks in advance
You can go to several directions:
Implement a custom control, that is your own class derived from an existing control (Button in your case). Add a dependency property (e.g. ButtonValue). Note - dependency property aren't standard .NET property - they have much more. Check out the following sample: http://msdn.microsoft.com/en-us/library/cc295235(v=expression.30).aspx (A custom button), or here: http://wpftutorial.net/HowToCreateACustomControl.html (A simpler sample, but without a property.
Have a data context for the control. Typically the data context is a separate class (a.k.a. the "View Model"), but if you aren't following the mvvm paradigm, it is OK the data context is self. Whatever data context you are using, it must derived from INotifyPropertyChanged, and it must file PropertyChanged event.
(Recommended!) Create a Control Template for CheckBox. When you come to think about it, logically your control is really a button with a binary state. Red/Green in your case, Checked/Unchecked for a CheckBox. So logically, you are looking for a checkbox, but you just want to present it differently.
So in your control template, draw the ellipse, and add a trigger for the IsChecked property:
<ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type CheckBox}">
<Grid>
... everything else in the control ...
<Ellipse x:Name="ellipse1" Width="20" Height="20" Margin="5,40,45,5" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="ellipse1" Property="Fill" Value="Red" />
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter TargetName="ellipse1" Property="Fill" Value="Green" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
This is a nice example for the difference between behavior and presentation of WPF.
While your control may look like a button, it behaves like a CheckBox, in the sense that it has two states.
EDIT: Use ToggleButton - this is the base class of CheckBox (and RadioButton), and it has exactly the functionality that you need, including the IsChecked property.
You have a couple of options:
1.The easiest one is to re-purpose an unused Brush or Color(with a converter) Button existing property:
<Window.Resources>
<ControlTemplate x:Key="repurposedProperty" TargetType="Button">
<Border Background="{TemplateBinding BorderBrush}">
<ContentPresenter/>
</Border>
</ControlTemplate>
</Window.Resources>
...
<Button Template="{StaticResource repurposedProperty}">Button</Button>
2.Other option is to define an attached property and use it in the ControlTemplate. On any Button that you apply the template to you have to set the attached property:
public static readonly DependencyProperty AttachedBackgroundProperty =
DependencyProperty.RegisterAttached("AttachedBackground", typeof (Brush), typeof (MainWindow),
new PropertyMetadata(default(Brush)));
public static void SetAttachedBackground(UIElement element, Brush value)
{
element.SetValue(AttachedBackgroundProperty, value);
}
public static Brush GetAttachedBackground(UIElement element)
{
return (Brush) element.GetValue(AttachedBackgroundProperty);
}
...
<
Window.Resources>
<ControlTemplate x:Key="attachedProperty" TargetType="Button">
<Border Background="{TemplateBinding WpfApplication1:MainWindow.AttachedBackground}">
<ContentPresenter/>
</Border>
</ControlTemplate>
</Window.Resources>
...
<Button Template="{StaticResource attachedProperty}">
<WpfApplication1:MainWindow.AttachedBackground>
<SolidColorBrush Color="Pink"></SolidColorBrush>
</WpfApplication1:MainWindow.AttachedBackground>
Button</Button>
PS: you can use a binding to set the value of the attached property.

Resources