I am using ModernUIIcons that come with MahApps.Metro in a Xaml file as StaticResources. To put one in my UI is very easy, like this:
<Rectangle Width="19"
Height="19">
<Rectangle.Fill>
<VisualBrush Visual="{StaticResource appbar_database}" />
</Rectangle.Fill>
</Rectangle>
I want to encapsulate all the logic of the rectangle in a CustomControl so I can do something like the following:
<cc:MenuItemIcon Source="{StaticResource appbar_page}"/>
This is what I got so far:
In one project as library, Themes/Generic.xaml:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:AMIGEDM.CustomControls.Menu">
<Style TargetType="{x:Type local:MenuItemIcon}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MenuItemIcon}">
<Rectangle Width="19"
Height="19">
<Rectangle.Fill>
<VisualBrush Visual="{TemplateBinding Source}" />
</Rectangle.Fill>
</Rectangle>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
And in the CS file
namespace AMIGEDM.CustomControls.Menu
{
public class MenuItemIcon : Control
{
static MenuItemIcon()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MenuItemIcon), new FrameworkPropertyMetadata(typeof(MenuItemIcon)));
}
public static readonly DependencyProperty SourceProperty =
DependencyProperty.Register("Source", typeof(Visual), typeof(MenuItemIcon));
public Visual Source
{
get { return (Visual)GetValue(SourceProperty); }
set { SetValue(SourceProperty, value); }
}
}
}
Everything compiles silky smooth, so I go to my TestDummy Project
<Window x:Class="AMIGEDM.TestDummy.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:cc="clr-namespace:AMIGEDM.CustomControls.Menu;assembly=AMIGEDM.CustomControls">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/AMIGEDM.TestDummy;component/Resources/Icons.xaml"/>
<ResourceDictionary Source="pack://application:,,,/AMIGEDM.CustomControls;component/Themes/Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Menu IsMainMenu="True" SnapsToDevicePixels="True">
<MenuItem Header="_Open">
<MenuItem Header="_File">
<MenuItem.Icon>
<cc:MenuItemIcon Source="{StaticResource appbar_page}"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="_File">
<MenuItem.Icon>
<Rectangle Width="19"
Height="19">
<Rectangle.Fill>
<VisualBrush Visual="{StaticResource appbar_database}" />
</Rectangle.Fill>
</Rectangle>
</MenuItem.Icon>
</MenuItem>
</MenuItem>
</Menu>
</Grid>
The Library puts the Icon using the Rectangle, Rectangle Fill and VisualBrush, but when I try to use the CustomControl it shows nothing
All the code looks normal, except for the style of MenuItemIcon. Quote about TemplateBinding from Adam Nathan book:
TemplateBinding doesn’t work outside a template or outside its VisualTree property, so you can’t even use TemplateBinding inside a template’s trigger. Furthermore,
TemplateBinding doesn’t work when applied to a Freezable (for mostly artificial reasons).
And quote from MSDN about VisualBrush:
Freezable Features: Because it inherits from the Freezable class, the VisualBrush class provides several special features: VisualBrush objects can be declared as resources and shared among multiple objects.
Therefore instead of:
<VisualBrush Visual="{TemplateBinding Source}" />
Use the construction {RelativeSource TemplatedParent} and a Path equal to the dependency property whose value you want to retrieve:
<Style TargetType="{x:Type local:MenuItemIcon}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MenuItemIcon}">
<Rectangle Width="22" Height="22">
<Rectangle.Fill>
<VisualBrush Visual="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Source}" />
</Rectangle.Fill>
</Rectangle>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Related
It is stated in MSDN that
Starting with Windows 10, version 1809, you can use the x:Bind markup extension anywhere you use TemplateBinding in a ControlTemplate.
However, when I try to replace TemplateBinding with {x:Bind} whilst defining the style of a custom control, as so,
<Style TargetType="local:PomodoroTimer" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:PomodoroTimer">
<Grid Width="300" Height="300" Background="{x:Bind Background}">
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I get the following error: Unable to resolve symbol 'Background'. What am I missing?
x:Bind needs code-behind. (see here)
So, thanks to MainWindow.xaml.cs, this works:
<Window
x:Class="Bindings.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:local="using:Bindings"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<Grid.Resources>
<Style
x:Key="CustomButtonStyle"
TargetType="Button">
<Style.Setters>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border
BorderBrush="{x:Bind BorderBrush, Mode=OneWay}"
BorderThickness="{x:Bind BorderThickness, Mode=OneWay}">
<ContentControl Content="{x:Bind Content, Mode=OneWay}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
</Grid.Resources>
<Button
BorderBrush="SkyBlue"
BorderThickness="1"
Content="Custom Button"
Style="{StaticResource CustomButtonStyle}" />
</Grid>
</Window>
For custom (templated) controls, I'd go with:
Text="{TemplateBinding Text}"
or
Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
for TwoWay bindings.
If you want to do x:Bind inside the ControlTemplate, this answer might help.
I need a button with custom style and i would like to have an image on it.
So i have made CustomButton style with ControlTemlate containing StackPanel of TextBlock for text and Rectangle for image, i want to use DrawingImage from my Icons.xaml, it is SVG converted to XAML.
I have also made CustomButton class, it is derived from the regular Button class and has DrawingImageProperty which is dependency property.
In my view i want to create this button with DrawingImage property and then bind to this property in my style, something like this:
<controls:CustomButton DrawingImage="{StaticResource Add}" Content="Add" Style="{StaticResource CustomButton}" />
But unfortunately the button image is missing. I am not sure about binding to the dependency property in the style and also i am not sure about the types, because Drawing property of the DrawingBrush is of type Drawing, but in my Icons.xaml resources i have DrawingImage, couldn't this be also problem?
CustomButton.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Torch.Controls">
<Style x:Key="CustomButton" TargetType="{x:Type controls:CustomButton}">
<Setter Property="Foreground" Value="{StaticResource IconicWhiteBrush}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:CustomButton}">
<Border
Name="Border"
Background="{StaticResource IconicBlueLittleDarkBrush}"
BorderBrush="{StaticResource IconicBlackBrush}"
BorderThickness="1">
<StackPanel Orientation="Horizontal">
<Rectangle Width="20" Height="20">
<Rectangle.Fill>
<DrawingBrush Drawing="{TemplateBinding DrawingImage}" />
</Rectangle.Fill>
</Rectangle>
<TextBlock
Margin="0,0,5,0"
VerticalAlignment="Center"
Text="{TemplateBinding Content}" />
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
CustomButton.cs
public class CustomButton : Button
{
public static readonly DependencyProperty DrawingImageProperty =
DependencyProperty.Register("DrawingImage", typeof(DrawingImage), typeof(CustomButton),
new FrameworkPropertyMetadata(OnDrawingImageChanged));
public DrawingImage DrawingImage
{
get => (DrawingImage)GetValue(DrawingImageProperty);
set => SetValue(DrawingImageProperty, value);
}
private static void OnDrawingImageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((CustomButton)d).DrawingImage = (DrawingImage)e.NewValue;
}
}
Icons.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DrawingImage x:Key="Add">
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V24 H24 V0 H0 Z">
<GeometryDrawing Brush="#FF00ACC1" Geometry="F1 M24,24z M0,0z M19,13L13,13 13,19 11,19 11,13 5,13 5,11 11,11 11,5 13,5 13,11 19,11 19,13z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</ResourceDictionary>
Thank you.
A DrawingImage is not a Drawing, hence
Drawing="{TemplateBinding DrawingImage}"
can not work. Use an Image element instead, and bind its Source property.
<Image Source="{TemplateBinding DrawingImage}"/>
Besides that, the OnDrawingImageChanged callback is pointless. It assigns a value to the property which it already has. You can safely remove it.
I'd also use ImageSource instead of DrawingImage as type of the dependency property. You could use it more flexibly and also assign other image types like BitmapImage.
public static readonly DependencyProperty ImageProperty =
DependencyProperty.Register(nameof(Image), typeof(ImageSource), typeof(CustomButton));
public ImageSource Image
{
get => (ImageSource)GetValue(ImageProperty);
set => SetValue(ImageProperty, value);
}
In the ControlTemplate:
<Image Source="{TemplateBinding Image}"/>
I'd like to create a UserControl (in this case a square-Button with defined Backgroundcolors) which can host it's own content.
UserControl:
<UserControl x:Class="SGDB.UI.Controls.ModernButton"
xmlns:local="clr-namespace:SGDB.UI.Controls"
xmlns:converter="clr-namespace:SGDB.UI.Converter"
x:Name="_modernButton">
<Button>
<Button.Resources>
<converter:EnumToColorConverter x:Key="ColorConverter"/>
</Button.Resources>
<Button.Template>
<ControlTemplate>
<Border Width="{Binding Size, ElementName=_modernButton}" Height="{Binding Size, ElementName=_modernButton}" BorderBrush="Black" BorderThickness="0.8,0.8,3,3">
<Grid Background="{Binding BackgroundColor, ElementName=_modernButton, Converter={StaticResource ColorConverter}}">
<ContentPresenter/>
</Grid>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
Now, as you may expect it, if I use this Control inside my MainView everthing works just fine until I define some Content.
Using:
<control:ModernButton Size="200" BackgroundColor="Light">
TEST
</control:ModernButton>
In this case "TEST" will override the whole Content of the UserControl (the whole Button Template). I guess this happens because The Button inside the UserControl is defined as "Content" itself and it will get overridden when defining new Content.
So the final question is: Is it possible to achieve what I'm looking for? if yes: How? How could I "redirect" the Content I'm defining in my MainView into the self-defined ContentPresenter inside my Button Template instead of the UserControls's ContentPresenter?
If possible I don't want to create a new dp-propery which hosts my Content, e.g.:
<controls:MordernButton Size="200" BackgroundColor="Light">
<controls:ModernButton.Content>
I don't want this, if possible
</controls:ModernButton.Content>
</controls:ModernButton>
Use the ContentPropertyAttribute to instruct the xaml to set this property instead of the actual Content property.
[ContentProperty("InnerContent")]
public partial class ModernButton : UserControl
{
public ModernButton()
{
InitializeComponent();
}
public static readonly DependencyProperty InnerContentProperty =
DependencyProperty.Register("InnerContent", typeof(object), typeof(ModernButton));
public object InnerContent
{
get { return (object)GetValue(InnerContentProperty); }
set { SetValue(InnerContentProperty, value); }
}
}
Then in your xaml, Bind the Content Presenter to use InnerContent property instead.
<ContentPresenter Content="{Binding InnerContent, ElementName=_modernButton}"/>
This way you can do the following without replacing the actual content.
<control:ModernButton Size="200" BackgroundColor="Light">
TEST
</control:ModernButton>
Here we go.
<UserControl x:Class="SGDB.UI.Controls.ModernButton"
xmlns:local="clr-namespace:SGDB.UI.Controls"
xmlns:converter="clr-namespace:SGDB.UI.Converter"
x:Name="_modernButton">
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<Button Content="{TemplateBinding Content}">
<Button.Resources>
<converter:EnumToColorConverter x:Key="ColorConverter"/>
</Button.Resources>
<Button.Template >
<ControlTemplate TargetType="Button">
<Border Width="{Binding Size,
ElementName=_modernButton}"
Height="{Binding Size,
ElementName=_modernButton}"
BorderBrush="Black"
BorderThickness="0.8,0.8,3,3">
<Grid Background="{Binding BackgroundColor, ElementName=_modernButton, Converter={StaticResource ColorConverter}}">
<ContentPresenter />
</Grid>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
</ControlTemplate>
</UserControl.Template>
</UserControl>
Let's assume that youre UserControl is:
<UserControl x:Class="QuickAndDirtyAttempt.Decorator" ....
<UserControl.Template>
<ControlTemplate TargetType="{x:Type local:Decorator}">
<StackPanel Orientation="Vertical">
<Label>Foo</Label>
<ContentPresenter/>
<Label>Bar</Label>
</StackPanel>
</ControlTemplate>
</UserControl.Template>
</UserControl>
Note the TargetType property on the template: without it the project will happily compile, but the ContentPresenter will not work.
And then:
<Window ... >
<StackPanel Orientation="Vertical">
<local:Decorator>
<Label Background="Wheat">User supplied content here</Label>
</local:Decorator>
</StackPanel>
</Window>
I strongly recommend you to read this before implementing anything
Simple; Just circumvent and replace the UserControl's Template.
<UserControl.Template>
<ControlTemplate TargetType="{x:Type UserControl}">
<Button Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}">
<Button.Resources>
<converter:EnumToColorConverter x:Key="ColorConverter"/>
</Button.Resources>
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Border Width="{Binding Size,
ElementName=_modernButton}"
Height="{Binding Size,
ElementName=_modernButton}"
BorderBrush="Black"
BorderThickness="0.8,0.8,3,3">
<Grid Background="{Binding BackgroundColor, ElementName=_modernButton, Converter={StaticResource ColorConverter}}">
<ContentPresenter />
</Grid>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
</ControlTemplate>
</UserControl.Template>
All a user control is (at least it terms of XAML and its template), is a Border with a ContentPresenter inside it. The ContentPresenter being the only important part, really.
So all you do is gut out its Template and feed the Content property the UserControl has into something a little different; in this case, your button.
This is the difference between making a usercontrol out of other controls, and shoving some controls into a user control.
Making the usercontrol out of other controls gives you much more power.
My example for dialog box
<UserControl
x:Class="CyberpunkModManager.Controls.DialogBox"
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:local="clr-namespace:CyberpunkModManager.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="450"
d:DesignWidth="800"
Foreground="{StaticResource ThemeForeground}"
mc:Ignorable="d">
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<Grid Background="{StaticResource ThemeTransparentColor}">
<Border
MinWidth="400"
Padding="12"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="{StaticResource ThemeElement}"
CornerRadius="4">
<ContentPresenter />
</Border>
</Grid>
</ControlTemplate>
</UserControl.Template>
I got the following setup:
<Button x:Name="DeleteFilter" Margin="5" Grid.Column="1" Padding="2">
<StackPanel Orientation="Horizontal">
<Rectangle Height="9" Width="9" Stretch="Fill" Margin="5 3">
<Rectangle.Fill>
<VisualBrush Visual="{StaticResource appbar_delete}"/>
</Rectangle.Fill>
</Rectangle>
<TextBlock Text="{Resx DeleteFilter}"/>
</StackPanel>
</Button>
However, when launching my application I get the following result which is not what I want. All font properties seem to be ignored when I set the Content property of my button manually.
Live example:
I'd like to have the same fontstyle and fontsize as the right button. I tried to specify the style manually by using StaticResource and DynamicResource as follows:
<Button Style="{StaticResource MetroButton}"....
but nothing changed.
I guess that I need to implement a style which overrides the existing one and transfers the formatting to the TextBlock element but I have no clue how to do that.
The working "LOAD FILTERS" button in the right:
<Button x:Name="LoadFilter" Content="{Resx LoadFilters}" Margin="5" Grid.Column="2"/>
MahApps.Metro's standard button (MetroButton) is included in this file.
The style I applied to my icon button:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="MetroIconButton" BasedOn="{StaticResource MetroButton}" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<StackPanel Orientation="Horizontal">
<Rectangle Height="9" Width="9" Margin="5 3" Stretch="Fill">
<Rectangle.Fill>
<VisualBrush Visual="{Binding Tag, RelativeSource={RelativeSource TemplatedParent}}"/>
</Rectangle.Fill>
</Rectangle>
<ContentPresenter/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
In your setup the StackPanel is used as a content which is not so ideal, you may create a style containing the template and the required property setters for font so it remain consistent for the desired buttons across the application.
So if I try to create a button style for you that would be
<Style x:Key="MetroButton" TargetType="{x:Type Button}">
<Setter Property="FontSize" Value="13"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<StackPanel Orientation="Horizontal">
<Rectangle Height="9" Width="9" Margin="5 3" Stretch="Fill">
<Rectangle.Fill>
<VisualBrush Visual="{Binding Tag, RelativeSource={RelativeSource TemplatedParent}}"/>
</Rectangle.Fill>
</Rectangle>
<ContentPresenter/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
then I would use this style on button as
<Button Content="Delete" Style="{StaticResource MetroButton}" Tag="{StaticResource appbar_delete}"/>
Update
leveraging the ContentTemplate to achieve the same while utilizing the existing template.
<Style x:Key="MetroIconButton" BasedOn="{StaticResource MetroButton}" TargetType="{x:Type Button}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate >
<StackPanel Orientation="Horizontal">
<Rectangle Height="9" Width="9" Margin="5 3" Stretch="Fill">
<Rectangle.Fill>
<VisualBrush Visual="{Binding Tag, RelativeSource={RelativeSource FindAncestor, AncestorType=Button}}"/>
</Rectangle.Fill>
</Rectangle>
<ContentControl Content="{Binding}"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
usage remain quite same except the style MetroIconButton
<Button Content="Delete" Style="{StaticResource MetroIconButton}" Tag="{StaticResource appbar_delete}"/>
I am using Tag property to hold the icon so it is plug and play for you, but better is to use Attached properties for the same. l:ExtraProperties.Icon={StaticResource appbar_delete}", I can provide a sample if you need that too.
Actually in previous style we override the Template defined in the MetroButton style so it failed. After looking at the original implementation of MetroButton style I come up with the ContentTemplate way to actieve the same. So instead of setting Template we will set the content template which will be picked up by MetroButton style and applied to the content.
Using Attached Properties
declare a class inheriting DependencyObject or any of its derived class along with the desired property as mentioned below
class ExtraProperties: DependencyObject
{
public static Visual GetIcon(DependencyObject obj)
{
return (Visual)obj.GetValue(IconProperty);
}
public static void SetIcon(DependencyObject obj, Visual value)
{
obj.SetValue(IconProperty, value);
}
// Using a DependencyProperty as the backing store for Icon. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IconProperty = DependencyProperty.RegisterAttached("Icon", typeof(Visual), typeof(ExtraProperties), new PropertyMetadata(null));
}
add namespace to your xaml
<Window x:Class="Example.MainWindow"
...
xmlns:l="clr-namespace:Example">
then change the style as
<VisualBrush Visual="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Button}, Path=(l:ExtraProperties.Icon)}"/>
and usage as
<Button Content="Delete" Style="{StaticResource MetroIconButton}" l:ExtraProperties.Icon="{StaticResource appbar_delete}"/>
using Attached properties is more WPF approach, instead of hacking other properties which may not be guaranteed to behave as expected.
I have a custom control which is basically a contentcontrol
public class PromoAlarmBox : ContentControl
{
static PromoAlarmBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PromoAlarmBox), new FrameworkPropertyMetadata(typeof(PromoAlarmBox)));
}
}
I add it to the containing user control
<controls:PromoAlarmBox Grid.Row="9" Grid.Column="1" />
If I add the style to the containing usercontrols resources everything works fine
<UserControl.Resources>
<Style TargetType="{x:Type controls:PromoAlarmBox}">
<Setter Property="ContentControl.ContentTemplate">
<Setter.Value>
<DataTemplate >
<Rectangle Fill="Blue" Stroke="Black" Height="20" Width="20"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
But if I add it to generic.xaml in the custom controls project , nothing is show
<Style TargetType="{x:Type local:PromoAlarmBox}">
<Setter Property="ContentControl.ContentTemplate">
<Setter.Value>
<DataTemplate >
<Rectangle Fill="Blue" Stroke="Black" Height="20" Width="20"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
I know the style is applied as I have other controls in same project whos styles are defined in generic.xaml, Anyone have any ideas?
A simple static should do the trick...
static PromoAlarmBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PromoAlarmBox), new FrameworkPropertyMetadata(typeof(PromoAlarmBox)));
}
Although im not sure why there is a difference when you use a style as a local resource and when you use generic , this works for me
<Style TargetType="{x:Type local:PromoAlarmBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<Rectangle VerticalAlignment="Stretch" Fill="Yellow" Stroke="Black" Height="20" Width="20"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>