Custom button user control style overwritten when content is set - wpf

I am currently using Blend and some tutorials I found online to try to make my own button user control. Normally, I would just use a custom style and apply it to the controls I want, but I wrote in some dependency properties as well so I decided to write my own user control.
Something that I can't get my head around is how to set the Content property without overwriting the styling of the button control. I thought it might have been my code, but I started brand new with another button and I have the same thing happen - when the Content property is set, the button simply turns white and has black text in the upper left corner.
Here is the XAML code that Blend generated for me:
<UserControl x:Class="MyUI.Controls.MyButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="25" d:DesignWidth="100">
<UserControl.Resources>
<Style x:Key="MyButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Rectangle/>
<ContentPresenter
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsFocused" Value="True"/>
<Trigger Property="IsDefaulted" Value="True"/>
<Trigger Property="IsMouseOver" Value="True"/>
<Trigger Property="IsPressed" Value="True"/>
<Trigger Property="IsEnabled" Value="False"/>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid>
<Button Content="Button" Height="25" Style="{DynamicResource MyButtonStyle}" Width="100"/>
</Grid>
Now, if I reference the button in my main window like this, it reverts any styling that was done within the user control:
<local:MyButton Content="test" />
What do I need to change in order to make the button accept a different Content tag?

What you need is to connect your UserControl level Content property to your Button level Content property. By default UserControl's Content property is its only child element, which is Grid in your case. You can either create your own Content property or another one with different name. In your UserControl's .cs file:
/// <summary>
/// Interaction logic for MyButton.xaml
/// </summary>
public partial class MyButton : UserControl
{
public new static DependencyProperty ContentProperty =
DependencyProperty.Register("Content", typeof (object),
typeof (MyButton));
public new object Content
{
get { return GetValue(ContentProperty); }
set { SetValue(ContentProperty, value); }
}
public MyButton()
{
InitializeComponent();
}
}
On your UnserControl's Xaml:
<Button Content="{Binding Path=Content, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
Height="25" Style="{DynamicResource MyButtonStyle}" Width="100"/>
Now Button's Content binds to your UserControl level Content property.

Related

WPF ToggleButton style that changes text of TextBlock within a StackPanel based on IsChecked trigger

I have a WPF style for a toggle button that uses a stack panel to achieve stacked, vertical text. I want the button text to change based on the toggle button's IsChecked state.
Additionally, the number of characters changes so I need to hide one of the text blocks in the stack panel. I tried setting the Visibility property of the Letter4 text block to hidden but the text was not vertically centered.
The code below works but it's just a cheesy workaround — I change the font size to 1 so it seems to disappear. (I pulled out all the formatting to make it simpler.) What is the correct way to do what I need?
Thanks.
<Style x:Key="RunStopToggle" TargetType="ToggleButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<StackPanel VerticalAlignment="Center">
<TextBlock x:Name="Letter1"/>
<TextBlock x:Name="Letter2"/>
<TextBlock x:Name="Letter3"/>
<TextBlock x:Name="Letter4"/>
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="TextBlock.Text" TargetName="Letter1" Value="S"/>
<Setter Property="TextBlock.Text" TargetName="Letter2" Value="T"/>
<Setter Property="TextBlock.Text" TargetName="Letter3" Value="O"/>
<Setter Property="TextBlock.Text" TargetName="Letter4" Value="P"/>
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="TextBlock.Text" TargetName="Letter1" Value="R"/>
<Setter Property="TextBlock.Text" TargetName="Letter2" Value="U"/>
<Setter Property="TextBlock.Text" TargetName="Letter3" Value="N"/>
<Setter Property="TextBlock.Text" TargetName="Letter4" Value=""/>
<Setter Property="TextBlock.FontSize" TargetName="Letter4" Value="1"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
IMHO, the biggest problem with the code is that you're trying to do everything in XAML instead of letting a view model mediate the changeable values. A smaller issue is how you're actually implementing the vertically-stacked text.
There is already another question with good advice about vertically-stacked text. See Vertical Text in Wpf TextBlock
We can combine the advice there, where they use ItemsControl to display the text vertically, along with a view model to provide the actual text, and a placeholder ItemsControl that is hidden, but not collapsed (so that it still takes up space), to display the toggle button much more simply than in the code you have now.
First, the view model:
class ViewModel : INotifyPropertyChanged
{
private bool _isChecked;
public bool IsChecked
{
get => _isChecked;
set => _UpdateField(ref _isChecked, value, _OnIsCheckedChanged);
}
private string _buttonText;
public string ButtonText
{
get => _buttonText;
set => _UpdateField(ref _buttonText, value);
}
public ViewModel()
{
ButtonText = _GetTextForButtonState();
}
public event PropertyChangedEventHandler PropertyChanged;
private void _OnIsCheckedChanged(bool previous)
{
ButtonText = _GetTextForButtonState();
}
private string _GetTextForButtonState()
{
return IsChecked ? "STOP" : "RUN";
}
private void _UpdateField<T>(ref T field, T newValue,
Action<T> onChangedCallback = null,
[CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, newValue))
{
return;
}
T oldValue = field;
field = newValue;
onChangedCallback?.Invoke(oldValue);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
This view model just provides a property to receive the toggle button's state, as well as to provide the appropriate button text for that state.
Next, the XAML to use this view model:
<Window x:Class="TestSO68091382ToggleVerticalText.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:l="clr-namespace:TestSO68091382ToggleVerticalText"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<l:ViewModel/>
</Window.DataContext>
<Grid>
<ToggleButton IsChecked="{Binding IsChecked}"
HorizontalAlignment="Left" VerticalAlignment="Top">
<ToggleButton.Content>
<Grid>
<ItemsControl ItemsSource="STOP" Visibility="Hidden"/>
<ItemsControl ItemsSource="{Binding ButtonText}" VerticalAlignment="Center"/>
</Grid>
</ToggleButton.Content>
</ToggleButton>
</Grid>
</Window>
The ToggleButton.IsChecked property is bound to the IsChecked property in the view model, so that it can update the text as necessary. Then the content of the ToggleButton includes the ItemsControl that will display the text vertically.
Note that button's direct descendent is actually a Grid. This is so that two different ItemsControl elements can be provided: one shows the text itself, and is bound to the ButtonText property; the other has hard-coded the longer of the two strings that might be displayed. This ensures that the ToggleButton's size is always the same, large enough for that longer text. The bound ItemsControl is then centered vertically; you can of course use whatever aligment you like there, but the way your question is worded it sounds like you want the text vertically centered.
For what it's worth, if you really want to do everything in XAML, that's possible to. I personally prefer to avoid this kind of use for triggers, but I admit there's no hard and fast rule that says you can't. My preference mainly has to do with my desire to keep the XAML as simple as possible, as I find it a less readable language, and harder to mentally keep track of all the different related elements, which adding triggers tends to make more complex.
If you do prefer a XAML-only solution, it would look like this:
<Window x:Class="TestSO68091382ToggleVerticalText.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:l="clr-namespace:TestSO68091382ToggleVerticalText"
xmlns:s="clr-namespace:System;assembly=netstandard"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<s:String x:Key="runText">RUN</s:String>
<s:String x:Key="stopText">STOP</s:String>
</Window.Resources>
<Grid>
<ToggleButton HorizontalAlignment="Left" VerticalAlignment="Top">
<ToggleButton.Content>
<Grid>
<ItemsControl ItemsSource="STOP" Visibility="Hidden"/>
<ItemsControl VerticalAlignment="Center">
<ItemsControl.Style>
<Style TargetType="ItemsControl">
<Setter Property="ItemsSource" Value="{StaticResource runText}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, RelativeSource={RelativeSource AncestorType=ToggleButton}}" Value="True">
<Setter Property="ItemsSource" Value="{StaticResource stopText}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ItemsControl.Style>
</ItemsControl>
</Grid>
</ToggleButton.Content>
</ToggleButton>
</Grid>
</Window>
Mechanically, this is very similar to the view model-based example above, just using a DataTrigger to respond to the changes in the ToggleButton.IsChecked state instead of doing it in the view model.
Note that you really only need one trigger. You can use a Setter to provide the unchecked state's value, and then use a single trigger to override that value for the checked state.
You need to change Visibility:
<Style x:Key="RunStopToggle" TargetType="ToggleButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<StackPanel VerticalAlignment="Center">
<TextBlock x:Name="Letter1"/>
<TextBlock x:Name="Letter2"/>
<TextBlock x:Name="Letter3"/>
<TextBlock x:Name="Letter4" Text="P"/>
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="TextBlock.Text" TargetName="Letter1" Value="S"/>
<Setter Property="TextBlock.Text" TargetName="Letter2" Value="T"/>
<Setter Property="TextBlock.Text" TargetName="Letter3" Value="O"/>
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="TextBlock.Text" TargetName="Letter1" Value="R"/>
<Setter Property="TextBlock.Text" TargetName="Letter2" Value="U"/>
<Setter Property="TextBlock.Text" TargetName="Letter3" Value="N"/>
<Setter Property="TextBlock.Visibility" TargetName="Letter4" Value="Collapsed"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
But I agree with #Peter Duniho - you'd better use a different approach for vertical text.
For permanent text, to print it one letter on each line, it is enough to insert newline characters & # xA; between the letters.
Example:
<Style x:Key="RunStopToggle" TargetType="ToggleButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<StackPanel VerticalAlignment="Center">
<TextBlock x:Name="PART_TextBlock" Text="R
U
N"/>
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="TextBlock.Text" TargetName="PART_TextBlock" Value="S
T
O
P"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Also see my answer with a converter for vertical text: https://stackoverflow.com/a/68094601/13349759

WPF: decide where to show the contentPresenter in your User control

I have a very simple UserControl with some borders and some decorations that react to mouseOver, pressed and some nice things.
I want to allow people to set the content of the text from outside, but when I set the content, the generated content presenter overwrites my whole WPF structure.
This is what I tried so far:
<UserControl tags tags tags>
<!-- This is the only way I found to style the textblock that WPF -->
<!-- generates to encapsulate the content string -->
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<TextBlock Background="Green"
HorizontalAligment="Center"
VerticalAlignment="Center"
Text = "{TemplateBinding Content}"/>
</ControlTemplate>
</UserControl.Template>
<!-- Here my borders and fancy things. I want to add animations -->
<!-- and react to mouseOver and Pressed like a button -->
<Border x:Name="SuperNiceBorder" tag tag tag>
<HERE I WANT THE CONTENTPRESENTER>
</Border>
</UserControl>
Is there a way to tell WPF I want the text set by the user in the Content just there ???
Move all your animations and triggers inside the ControlTemplate.
Replace your TextBlock with a ContentPresenter:
<UserControl x:Class="MySolution.MyControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<Border x:Name="MyBorder" Background="Green">
<ContentPresenter
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content = "{TemplateBinding Content}"/></Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="MyBorder" Property="Background" Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</UserControl.Template>
</UserControl>
And you can use the UserControl like these examples:
1:
<local:MyControl Content="Test Testing tester"/>
2:
<local:MyControl>
<TextBlock Text="Another test from a TextBlock"/>
</wpfAllPurposesTest:MyControl>

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.

Mouseover border in a custom control for a textblock

I am trying to create a custom control for a text block that when moused over, a border will appear. I am pretty new to WPF and have only made some very simple custom controls. I need to implement this in a XAML UserControl.
Any suggestions would be greatly appreciated. Thanks again, StackOverflow.
EDIT: I am going to have to bind a persistence property to several different controls, so I really need to do this in a custom control. This is what I have, and it isn't working:
xmlns:customControls="clr-namespace:****.CustomControls"
....
<customControls:MouseOverBorder>
<TextBlock Style="{StaticResource ResourceKey=HomePageButtonText}"
Height="100"
Width="100"
Margin="5"
Text="View Reports" />
</customControls:MouseOverBorder>
And the UserControl:
<UserControl
x:Class="****.MouseOverBorder"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d">
<UserControl.Resources>
<ResourceDictionary>
<Style x:Key="MouseOverBorder" TargetType="{x:Type Border}">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="CornerRadius" Value="3" />
<Style.Triggers>
<Trigger Property="Border.IsMouseOver" Value="true">
<Setter Property="BorderBrush" Value="White" />
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
</UserControl.Resources>
<Border Style="{DynamicResource MouseOverBorder}" BorderThickness="1" CornerRadius="3" SnapsToDevicePixels="True"/>
No need to make a UserControl. I've managed to accomplish this with the following markup:
<Border Style="{DynamicResource BorderStyle1}" BorderThickness="1" CornerRadius="3" >
<TextBlock Text="TextBlock" />
</Border>
Here's the style:
<Style x:Key="BorderStyle1" TargetType="{x:Type Border}">
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="CornerRadius" Value="3"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" Value="#FF123BBA"/>
</Trigger>
</Style.Triggers>
</Style>
EDIT:
Still don't get it why do you need a UserControl (please don't call it custom control - these are different things), but let's consider your example.
When you write the following
<customControls:MouseOverBorder>
<TextBlock Style="{StaticResource ResourceKey=HomePageButtonText}"
Height="100"
Width="100"
Margin="5"
Text="View Reports" />
</customControls:MouseOverBorder>
you are actually setting MouseOverBorder.Content property. Originally it's Content is defined in MouseOverBorder.xaml file. So you are replacing all your UserControl structure with TextBlock. But still I got your idea and have solution for it.
First, add custom DependencyProperty and CLR wrapper for it to MouseOverBorder class:
public static readonly DependencyProperty MyContentTemplateProperty =
DependencyProperty.Register("MyContentTemplate", typeof(DataTemplate), typeof(MouseOverBorder), null);
[Browsable(true)]
[Category("Other")]
public DataTemplate MyContentTemplate
{
get { return (DataTemplate)GetValue(MyContentTemplateProperty); }
set { SetValue(MyContentTemplateProperty, value); }
}
Second, make something inside MouseOverBorder use this property, e.g.
<ContentPresenter ContentTemplate="{Binding MyContentTemplate, ElementName=userControl}"/>
<!-- userControl is the Name of MouseOverBorder, defined in xaml -->
At last, you can use your UserControl as following:
<customControls:MouseOverBorder>
<customControls:MouseOverBorder.MyContentTemplate>
<DataTemplate>
<TextBlock Style="{StaticResource ResourceKey=HomePageButtonText}"
Height="100"
Width="100"
Margin="5"
Text="View Reports" />
</DataTemplate>
</customControls:MouseOverBorder.MyContentTemplate>
</customControls:MouseOverBorder>

Could this custom WPF TextBox control be replaced with an Attached Property?

I have a simple control that extends the WPF TextBox control. The basic idea is to save space in the UI, by enabling the TextBox to display its own label inside it when it is empty.
I have declared one DependencyProperty called Label in it and have set the TextBox.Template property to a ControlTemplate. The ControlTemplate is the default Windows Aero XAML with the addition of a TextBlock placed behind the control that displays the value of the TextBox.Text property. Its Visibility property is bound with a Converter to be visible whenever the Text property is empty. (There's a lot and mostly uninteresting, so please excuse the scrollbar).
<ControlTemplate x:Key="LabelTextBoxTemplate" TargetType="{x:Type TextBoxBase}" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Aero="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero">
<Aero:ListBoxChrome Background="{TemplateBinding Panel.Background}" BorderBrush="{TemplateBinding Border.BorderBrush}" BorderThickness="{TemplateBinding Border.BorderThickness}" RenderMouseOver="{TemplateBinding UIElement.IsMouseOver}" RenderFocused="{TemplateBinding UIElement.IsKeyboardFocusWithin}" Name="Border" SnapsToDevicePixels="True">
<Grid>
<TextBlock Text="{Binding Label, ElementName=This}" Visibility="{Binding Text, ElementName=This, Converter={StaticResource StringToVisibilityConverter}}" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" FontWeight="Normal" FontStyle="Italic" Foreground="#99000000" Padding="3,0,0,0" />
<ScrollViewer Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</Grid>
</Aero:ListBoxChrome>
<ControlTemplate.Triggers>
<Trigger Property="UIElement.IsEnabled" Value="False">
<Setter TargetName="Border" Property="Panel.Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
(The Name property of the control is set to This for the binding)
So anyway, this all works nicely but I was wondering if I could replace this functionality with an Attached Property. I created an Attached Property called Label and added a callback delegate that gets called when the property is set. In this method, I planned to find the ControlTemplate from the Application.Resources and set the TextBox.Template property to it... I couldn't find a way to access the ControlTemplate so this is my first question.
How can I access a ControlTemplate in the Application.Resources in App.xaml from an Attached Property?
The rest of the question is how can I then bind to the Attached Property in the 'ControlTemplate'?
I have tried several things like
Text="{Binding Path=(Attached:TextBoxProperties.Label),
Source={x:Static Attached:TextBoxProperties}, FallbackValue=''}"
but the TextBoxProperties class that contains the Attached Property is not static.
UPDATE >>>
Thanks to H.B. I found that I could access the ControlTemplate using the following code.
ControlTemplate labelControlTemplate =
(ControlTemplate)Application.Current.FindResource("LabelTextBoxTemplate");
You should be able to access the Application.Resources from: Application.Current.Resources.
The binding should probably be this:
{Binding (Attached:TextBoxProperties.Label),
RelativeSource={RelativeSource AncestorType=TextBox}}
It should not matter if the class containing the property is static, the bindng engine will see whether the property is set on the TextBox, it does not care about the declaring class.

Resources