Reuse ControlTemplate in DataTriggers - c#

I'm using WPF 4.0 to develop windows and want to reuse a ControlTemplate in my Resources for various Label controls.
I define a generic base Label Style with the ControlTemplate and then define derived Label Styles to control colors and label text.
I then apply these styles to data triggers based on a property value.
What I have tried so far throws an IllegalArgument exception: 'Style object is not allowed to affect the Style property of the object to which it applies'.
Is there a valid way to do this?
This is what I have so far that produces the exception:
<Style x:Key="BaseLabelStyle" TargetType="{x:Type Label}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Background="{TemplateBinding Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="24"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="24"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="1"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
Foreground="{TemplateBinding Foreground}"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="AvailableLabelStyle" TargetType="{x:Type Label}" BasedOn="{StaticResource BaseLabelStyle}">
<Style.Resources>
<Style>
<Setter Property="Label.Background" Value="#FF567E4A"/>
<Setter Property="Label.Foreground" Value="White"/>
<Setter Property="TextBlock.Text" Value="Available"/>
</Style>
</Style.Resources>
</Style>
I want to expand the derived styles to define other color and label text changes.
This derived Style is applied here:
<Label x:Name="Avail_Out_LBL"
HorizontalAlignment="Left" Margin="111,44,0,0"
VerticalAlignment="Top" Width="124" Height="18"
VerticalContentAlignment="Center"
HorizontalContentAlignment="Center" SnapsToDevicePixels="False"
Grid.Column="1" Padding="0">
<Label.Style>
<Style TargetType="{x:Type Label}">
<Style.Triggers>
<DataTrigger Binding="{Binding MonitorAndControlData.Availability}" Value="Available">
<Setter Property="Style" Value="{StaticResource AvailableLabelStyle}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
The exception points to the closing /DataTrigger in the Label. I can't tell if the problem is in the Style's use or in the definition up top in the Resources.
Any help would be greatly appreciated.

The problem is that you are trying to change the style from the style, which is not permitted.
What I would do in your situation is create a custom UserControl for your label, which would look like this :
<UserControl ...>
<UserControl.Resources>
<Style TargetType="{x:Type Label}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Background="{TemplateBinding Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="24"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="24"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="1"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
Foreground="{TemplateBinding Foreground}"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"/>
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding Availability, RelativeSource={RelativeSource AncestorType={x:Type theTypeOfYourControl}}}" Value="Available">
<Setter Property="Label.Background" Value="#FF567E4A"/>
<Setter Property="Label.Foreground" Value="White"/>
<Setter Property="TextBlock.Text" Value="Available"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Label x:Name="Avail_Out_LBL"
HorizontalAlignment="Left" Margin="111,44,0,0"
VerticalAlignment="Top" Width="124" Height="18"
VerticalContentAlignment="Center"
HorizontalContentAlignment="Center" SnapsToDevicePixels="False"
Grid.Column="1" Padding="0"/>
</UserControl>
The setters in the trigger are probably not good, you'll have to target the right property to make it work. Also, you will need to make a dependency property named Availability or any other relevant name (I just used the name in your binding) to expose it outside the UserControl. You will need to bind to this DependencyProperty when using your UserControl.
Here are some links on how to do it, with more détails :
http://www.codeproject.com/Articles/32825/How-to-Creating-a-WPF-User-Control-using-it-in-a-W
http://www.wpftutorial.net/dependencyproperties.html

Related

How to Remove The White Area in Datagrid WPF [duplicate]

This question already has answers here:
How Do I Hide wpf datagrid row selector
(4 answers)
Closed 10 months ago.
I tied to remove this white area from datagrid's row.
The reason of white area unwanted is for design purposes. I want to change the color of this place or remove it completely from datagrid.
Short Way
In Your DataGrid object, Change HeadersVisibility property to Column
<DataGrid HeadersVisibility="Column" ... \>
Long Way (More Styling)
You have to apply new styling for `RowStyle` in `DataGrid`, This way allow you to change the color or customize the entire row header.
Focus on DataGridRowHeader, Delete the line makes it disappear, Change Background property to make it black or the color you need.
<Style x:Key="DataGridRowStyle1" TargetType="{x:Type DataGridRow}">
<Setter Property="Background" Value="{DynamicResource {x:Static Colors.Red}}"/>
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="Validation.ErrorTemplate" Value="{x:Null}"/>
<Setter Property="ValidationErrorTemplate">
<Setter.Value>
<ControlTemplate>
<TextBlock Foreground="Red" Margin="2,0,0,0" Text="!" VerticalAlignment="Center"/>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridRow}">
<Border x:Name="DGR_Border" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" SnapsToDevicePixels="True">
<SelectiveScrollingGrid>
<SelectiveScrollingGrid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</SelectiveScrollingGrid.ColumnDefinitions>
<SelectiveScrollingGrid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</SelectiveScrollingGrid.RowDefinitions>
<DataGridCellsPresenter Grid.Column="1" ItemsPanel="{TemplateBinding ItemsPanel}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
<DataGridDetailsPresenter Grid.Column="1" Grid.Row="1" SelectiveScrollingGrid.SelectiveScrollingOrientation="{Binding AreRowDetailsFrozen, Converter={x:Static DataGrid.RowDetailsScrollingConverter}, ConverterParameter={x:Static SelectiveScrollingOrientation.Vertical}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" Visibility="{TemplateBinding DetailsVisibility}"/>
<!--HERE: Change the background color property for the color, Or remove the whole line to make it disapper-->
<DataGridRowHeader Grid.RowSpan="2" Background="Black" SelectiveScrollingGrid.SelectiveScrollingOrientation="Vertical" Visibility="{Binding HeadersVisibility, Converter={x:Static DataGrid.HeadersVisibilityConverter}, ConverterParameter={x:Static DataGridHeadersVisibility.Row}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
</SelectiveScrollingGrid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsNewItem" Value="True">
<Setter Property="Margin" Value="{Binding NewItemMargin, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
</Trigger>
</Style.Triggers>
</Style>

WPF Datagrid with multiple Column Header Templates [duplicate]

Trying to style my datagrid column headers, I encounter two problems.
What I want : I'd like my headers to be written in a border with the border drawn and a margin. See the picture :
What I get : I found that the border are drawn between 2 headers, plus I can't get rid of the shadow of the grip (white grip, grey shadow), as you as see in the picture
Here is my style for the headers :
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Height" Value="30" />
<Setter Property="SeparatorBrush" Value="{StaticResource ScbWhite}" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Foreground" Value="{StaticResource ScbBlue1}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid Margin="{TemplateBinding Padding}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Border x:Name="columnHeaderBorder"
TextBlock.FontWeight="Bold"
TextBlock.Foreground="{StaticResource ScbBlue1}"
BorderThickness="2"
BorderBrush="{StaticResource ScbBlue1}"
Background="{StaticResource ScbWhite}"
Width="{TemplateBinding Width}"
Margin="3,3,3,3"
Padding="3,0,3,0">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
<!--BorderBrush="{Binding VerticalGridLinesBrush, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"-->
<Thumb x:Name="PART_RightHeaderGripper" Grid.Column="1"
HorizontalAlignment="Right"
Width="6" BorderThickness="0"
BorderBrush="{StaticResource ScbWhite}"
Background="{StaticResource ScbWhite}"
Cursor="SizeWE">
<Thumb.BitmapEffect>
<DropShadowBitmapEffect Color="Transparent" Opacity="0"/>
</Thumb.BitmapEffect>
</Thumb>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Please, what can I do to get what I want?
DataGrid adds empty column header to fill space for situations when other columns don't cover full width. That header has null Content. I added a ControlTemplate Trigger to make border transparent for header without content.
To change Thumb apperance I changed Thumb.Template and made it a flat white rectangle
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid Margin="{TemplateBinding Padding}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Border x:Name="columnHeaderBorder"
TextBlock.FontWeight="Bold"
TextBlock.Foreground="blue"
BorderThickness="2"
BorderBrush="blue"
Background="white"
Width="{TemplateBinding Width}"
Margin="3,3,3,3"
Padding="3,0,3,0">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
<!--BorderBrush="{Binding VerticalGridLinesBrush, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"-->
<Thumb x:Name="PART_RightHeaderGripper" Grid.Column="1"
HorizontalAlignment="Right"
Width="6" BorderThickness="0"
Margin="0,3"
BorderBrush="white"
Background="white"
Cursor="SizeWE">
<Thumb.Template>
<ControlTemplate>
<Border Background="{TemplateBinding Background}"></Border>
</ControlTemplate>
</Thumb.Template>
</Thumb>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="Content" Value="{x:Null}">
<!--<Setter Property="BorderBrush" Value="Red" TargetName="columnHeaderBorder"/>-->
<Setter Property="BorderBrush" Value="Transparent" TargetName="columnHeaderBorder"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
// I replaced some StaticResources in a template to make my project compile. please restore them back or copy only modified parts of template

Problems with DataGridColumnHeader Style

Trying to style my datagrid column headers, I encounter two problems.
What I want : I'd like my headers to be written in a border with the border drawn and a margin. See the picture :
What I get : I found that the border are drawn between 2 headers, plus I can't get rid of the shadow of the grip (white grip, grey shadow), as you as see in the picture
Here is my style for the headers :
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Height" Value="30" />
<Setter Property="SeparatorBrush" Value="{StaticResource ScbWhite}" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Foreground" Value="{StaticResource ScbBlue1}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid Margin="{TemplateBinding Padding}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Border x:Name="columnHeaderBorder"
TextBlock.FontWeight="Bold"
TextBlock.Foreground="{StaticResource ScbBlue1}"
BorderThickness="2"
BorderBrush="{StaticResource ScbBlue1}"
Background="{StaticResource ScbWhite}"
Width="{TemplateBinding Width}"
Margin="3,3,3,3"
Padding="3,0,3,0">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
<!--BorderBrush="{Binding VerticalGridLinesBrush, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"-->
<Thumb x:Name="PART_RightHeaderGripper" Grid.Column="1"
HorizontalAlignment="Right"
Width="6" BorderThickness="0"
BorderBrush="{StaticResource ScbWhite}"
Background="{StaticResource ScbWhite}"
Cursor="SizeWE">
<Thumb.BitmapEffect>
<DropShadowBitmapEffect Color="Transparent" Opacity="0"/>
</Thumb.BitmapEffect>
</Thumb>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Please, what can I do to get what I want?
DataGrid adds empty column header to fill space for situations when other columns don't cover full width. That header has null Content. I added a ControlTemplate Trigger to make border transparent for header without content.
To change Thumb apperance I changed Thumb.Template and made it a flat white rectangle
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid Margin="{TemplateBinding Padding}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Border x:Name="columnHeaderBorder"
TextBlock.FontWeight="Bold"
TextBlock.Foreground="blue"
BorderThickness="2"
BorderBrush="blue"
Background="white"
Width="{TemplateBinding Width}"
Margin="3,3,3,3"
Padding="3,0,3,0">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
<!--BorderBrush="{Binding VerticalGridLinesBrush, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"-->
<Thumb x:Name="PART_RightHeaderGripper" Grid.Column="1"
HorizontalAlignment="Right"
Width="6" BorderThickness="0"
Margin="0,3"
BorderBrush="white"
Background="white"
Cursor="SizeWE">
<Thumb.Template>
<ControlTemplate>
<Border Background="{TemplateBinding Background}"></Border>
</ControlTemplate>
</Thumb.Template>
</Thumb>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="Content" Value="{x:Null}">
<!--<Setter Property="BorderBrush" Value="Red" TargetName="columnHeaderBorder"/>-->
<Setter Property="BorderBrush" Value="Transparent" TargetName="columnHeaderBorder"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
// I replaced some StaticResources in a template to make my project compile. please restore them back or copy only modified parts of template

Making a WPF combobox with rounded corners

In my application, I need to make the combobox that I am using have rounded corners. I started with the XAML posted in the answer to this question and have made some modifications. I decided I didn't like the way that one looked as much, so I tried to style it and make it look a bit more like the default combobox. Now my combobox looks like this: ,
and when dropped down:
The issue is that when the user places their mouse over the combobox, it looks like this: . If I use Snoop, I can see this info:
It says
that the value of that border background is being set to "#FFBEE6FD", which is the color that shows when the mouse is over the combobox. The value source is "ParentTemplateTrigger". My issue is that I don't know where this border is coming from or why it's getting that value. I have tried to add template triggers with setters to set the background to white, but I don't know where to set the value for this mysterious border.
Here is the XAML for my ComboBox:
<ComboBox x:Name="ScanSizesComboBox"
Style="{StaticResource roundedCornersComboBox}"
Grid.ZIndex="4"
ItemsSource="{Binding ScanSizes}"
SelectedItem="{Binding SelectedScanSize, Mode=TwoWay}"
ToolTip="{Binding (Validation.Errors)[0].ErrorContent}"
Margin="0,10,89,0"
HorizontalAlignment="Right"
Width="61"
Height="26"
VerticalAlignment="Top"
Grid.Row="4">
</ComboBox>
And here is the style:
<Style x:Key="ComboBoxTextBoxStyle" TargetType="{x:Type TextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid>
<Border Name="ComboBoxTextBoxStyleBorder" CornerRadius="2"
BorderThickness="0,1,0,1"
Margin="0,0,1,1"
Background="{TemplateBinding Background}">
<Border.Style>
<Style TargetType="Border">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<ScrollViewer x:Name="PART_ContentHost"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="IsReadOnly" Value="True"/>
</Style>
<!--Rounded corners combo box-->
<Style TargetType="{x:Type ComboBox}" x:Key="roundedCornersComboBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Border Name="roundedCornerComboBoxBorder" BorderBrush="#CCCCCC" BorderThickness="1" CornerRadius="3" ClipToBounds="True" Background="White">
<Border.Style>
<Style TargetType="Border">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<Canvas>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBox Name="PART_EditableTextBox"
Panel.ZIndex="0"
Style="{StaticResource ComboBoxTextBoxStyle}"
Padding="0,0,0,0"
IsHitTestVisible="False"
Height="{TemplateBinding Height}">
</TextBox>
<ToggleButton Grid.Column="1" Margin="0, 0, 0, 0"
Panel.ZIndex="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
BorderBrush="Transparent"
Background="Transparent"
Height="{TemplateBinding Height}"
Width="60"
IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
HorizontalContentAlignment="Right"
ClickMode="Press">
<ToggleButton.Style>
<Style TargetType="ToggleButton">
<Style.Triggers>
<Trigger Property="IsMouseOver"
Value="true">
<Setter Property="Background"
Value="White" />
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
<Path Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M 0 0 L 4 4 L 8 0 Z"
Fill="DodgerBlue" />
</ToggleButton>
<ContentPresenter Name="ContentSite"
Cursor="Arrow"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="3,0,0,0">
</ContentPresenter>
<Popup Name="Popup"
Placement="Bottom"
IsOpen="{TemplateBinding IsDropDownOpen}"
AllowsTransparency="True"
Focusable="False"
PopupAnimation="Slide">
<Grid Name="DropDown"
SnapsToDevicePixels="True"
MinWidth="{TemplateBinding ActualWidth}"
MaxHeight="{TemplateBinding MaxDropDownHeight}">
<Border
x:Name="DropDownBorder"
BorderThickness="1"
CornerRadius="5"
Background="White"
BorderBrush="Black"/>
<ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True">
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
</ScrollViewer>
</Grid>
</Popup>
</Grid>
</Canvas>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Ultimately, I would like for the user to be able to place his/her mouse over the combobox, and have it just look the same as it does when it is not highlighted. Any help is appreciated. Thanks.
Continuing from our comments conversation (which generally SO tries to avoid so much noise) this may get on you track.
So if I grab just all the template stuff to a bare bones basic default ComboBox and ComboBoxItem from a fresh WPF app, this is the output. Granted you won't need all of it, but it should ensure to an extent all expected functionality and DOM parts are here for reference so you have all the stuff like Triggers, Template Binding pieces etc, all available.
Notice the various Border and Rectangle elements in the various parts that would need to be altered in order to achieve the rounding of everything. I can't however provide any insight into how it would effect anything with MahApps as my experience with that is pretty limited since I've always just made my own stuff to accomplish what it essentially does.
Hope it helps. It's too long for SO's submission requirements though so here's the PasteBin link.
<Style x:Key="ComboBoxTextBoxStyle" TargetType="{x:Type TextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid>
<Border CornerRadius="5,0,0,5"
BorderThickness="1"
Background="{TemplateBinding Background}"
BorderBrush="Black">
<ScrollViewer x:Name="PART_ContentHost"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition MaxWidth="18"/>
</Grid.ColumnDefinitions>
<TextBox Name="PART_EditableTextBox"
Style="{StaticResource ComboBoxTextBoxStyle}"
Padding="5,0,0,0"
Height="{TemplateBinding Height}"/>
<ToggleButton Grid.Column="1" Margin="0"
Height="{TemplateBinding Height}"
Style="{StaticResource ComboBoxButtonStyle}"
Focusable="False"
IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
ClickMode="Press">
<Path Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M 0 0 L 4 4 L 8 0 Z"
Fill="DodgerBlue" />
</ToggleButton>
<ContentPresenter Name="ContentSite"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="5,0,0,0"/>
<Popup Name="Popup"
Placement="Bottom"
IsOpen="{TemplateBinding IsDropDownOpen}"
AllowsTransparency="True"
Focusable="False"
PopupAnimation="Slide">
<Grid Name="DropDown"
SnapsToDevicePixels="True"
MinWidth="{TemplateBinding ActualWidth}"
MaxHeight="{TemplateBinding MaxDropDownHeight}">
<Border
x:Name="DropDownBorder"
BorderThickness="1"
CornerRadius="5"
Background="Azure"
BorderBrush="Black"/>
<ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True">
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
</ScrollViewer>
</Grid>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Bind Property in Template

I have the following HeaderTemplate for an Expander:
<Expander.HeaderTemplate>
<DataTemplate>
<Grid Background="#939393">
<Grid.RowDefinitions>
<RowDefinition Height="22"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.Resources>
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border HorizontalAlignment="Center" VerticalAlignment="Center" x:Name="border" CornerRadius="5,5,5,5"
Background="Transparent" BorderBrush="#FF000000" Margin="1" BorderThickness="1,1,1,1" SnapsToDevicePixels="True">
<ContentPresenter x:Name="contentPresenter"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter Property="Background" TargetName="border" Value="DarkGray"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<TextBlock Grid.Column="0" Background="#6E6E6E"/>
<ToggleButton Grid.Column="0" IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor, AncestorType=Expander}}" Focusable="False">
<Image Source="{Binding IsExpanded, RelativeSource={RelativeSource FindAncestor, AncestorType=Expander}, Converter={StaticResource boolToExpanderDirectionConverter}}"/>
</ToggleButton>
<TextBlock Grid.Column="1" Text="General" Margin="5,1,1,1" VerticalAlignment="Top" FontWeight="Bold"/>
</Grid>
</DataTemplate>
</Expander.HeaderTemplate>
This Headertemplate I have defined directly at one Expander. Now I want to move this Template to a Resource and apply it to all Expanders. My problem now is, that I don't know how to set the Header of the TextBlock in the Template to the Header of the Expander.
I knwo there's a way with TemplateBinding, but unfortunately I don't know how to use this.
TemplateBinding can only be used within a ControlTemplate.TemplateBinding is used for binding to the element properties within the template definition..
here in your example you have used controltemplate for toggleButton.
Example For TemplateBinding
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter TextElement.Foreground="{TemplateBinding Foreground}" x:Name="contentPresenter"/>
</Border>
<ControlTemplate.Triggers>
.....
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ToggleButton Grid.Column="0" Background="Red" BorderBrush="Black" BorderThickness="1" Foreground="White"/>
Here Border and Contentpresnter will bind properties of ToggleButton that is alreday defined in its defination.
But in your example you used Datatemplate..so you cant use TemplateBinding ..Please Follow This link for Binding Syntax.
Solution For Your example
Using Binding syntax we can bind Header property to different exapnder
Text="{Binding Path=Header,RelativeSource={RelativeSource AncestorType={x:Type Expander}}}"
<Window.Resources>
<DataTemplate x:Key="ExpanderHeaderTemplate">
<Grid Background="#939393">
<Grid.RowDefinitions>
<RowDefinition Height="22"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.Resources>
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border HorizontalAlignment="Center" VerticalAlignment="Center" x:Name="border" CornerRadius="5,5,5,5"
Background="{TemplateBinding Background}" BorderBrush="#FF000000" Margin="1" BorderThickness="1,1,1,1" SnapsToDevicePixels="True">
<ContentPresenter x:Name="contentPresenter"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter Property="Background" TargetName="border" Value="DarkGray"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<TextBlock Grid.Column="0" Background="#6E6E6E"/>
<ToggleButton Grid.Column="0" Background="Red" IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor, AncestorType=Expander}}" Focusable="False">
<Image Source="{Binding IsExpanded, RelativeSource={RelativeSource FindAncestor, AncestorType=Expander}, Converter={StaticResource boolToExpanderDirectionConverter}}"/>
</ToggleButton>
<TextBlock Grid.Column="1" Text="{Binding Path=Header,RelativeSource={RelativeSource AncestorType={x:Type Expander}}}" Margin="5,1,1,1" VerticalAlignment="Top" FontWeight="Bold"/>
</Grid>
</DataTemplate>
</Window.Resources>
<StackPanel>
<Expander Header="General1" HeaderTemplate="{StaticResource ExpanderHeaderTemplate}"/>
<Expander Header="General2" HeaderTemplate="{StaticResource ExpanderHeaderTemplate}"/>
</StackPanel>
you can have a idea of Template binding by below code i had implemented this when i was learning XAML.
<Button Template="{DynamicResource CircleButton}" Background="Green" Content="1"></Button>
<ControlTemplate x:Key="CircleButton" TargetType="{x:Type Button}">
<Grid HorizontalAlignment="Center" VerticalAlignment="Center" MinHeight="36" MinWidth="36">
<Ellipse Fill="{TemplateBinding Background}"></Ellipse>
<ContentPresenter TextBlock.FontFamily="Calibri" TextBlock.FontSize="24" TextBlock.Foreground="Wheat" HorizontalAlignment="Center" VerticalAlignment="Center"></ContentPresenter>
</Grid>
you have to give a x:Key to control Template and when you are binding it with some specific element define that x:key there like i did Template="{DynamicResource CircleButton}".
following is your case:
<Style TargetType="{x:Type Expander}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Expander}">
// Do your thing.
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
this will apply to all Expander throught your application. You can put this Style into App.xaml file for code cleanness. hope this'll help you.
Since you are specifying a HeaderTemplate via a DataTemplate, the DataContext of the template IS the Header. This simple example works:
<Expander Header="Test">
<Expander.HeaderTemplate>
<TextBlock Text="{Binding}"/>
</Expander.HeaderTemplate>
</Expander>

Categories

Resources