Why does my ControlTemplate for Grid not work? - wpf

I want to set the ControlTemplate of grid to look like this:
Here is the markup:
<Grid>
<Grid.Style>
<Style TargetType="Grid">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.1*"></ColumnDefinition>
<ColumnDefinition Width="0.8*"></ColumnDefinition>
<ColumnDefinition Width="0.1*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="0.1*"></RowDefinition>
<RowDefinition Height="0.8*"></RowDefinition>
<RowDefinition Height="0.1*"></RowDefinition>
</Grid.RowDefinitions>
<ContentPresenter Grid.Row="1" Grid.Column="1"></ContentPresenter>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Style>
<Border Background="Red"></Border>
</Grid>
I don't know why the ControlTemplate doesn't work. Is there something wrong with my markup?

Grid.RowDefinitions and Grid.ColumnDefinitions are no Dependency properties, and can't be set by a Style. I guess this is why you used a ControlTemplate instead of setting it directly. But the default Style of the ControlTemplate does not show any Borders/Lines, therefore you may want to use a ContentPresenter (Wrap it around your Grid and not inside of it).
Additionally: To place the Border in the Center of the Grid, you must set the Row and Column, otherwise the Border is spread across the whole Grid. And place it right there where you have your ContentPresenter inside the Controltemplate, not outside of it.
Edit
Due to the clarification in the comments i suggest to use a Border which shrinks the Content with a RenderTransform.
Style
<Style x:Name="Shrink80pcBorder" TargetType="{x:Type Border}">
<Setter Property="RenderTransformOrigin" Value="0.5,0.5"/>
<Setter Property="RenderTransform">
<Setter.Value>
<ScaleTransform ScaleX="0.8" ScaleY="0.8"/>
</Setter.Value>
</Setter>
</Style>
Usage
<Border Background="Red" Style="{StaticResource Shrink80pcBorder}">
<Your Item/Content/>
</Border>

Related

Button Style in Resource not Applied to Buttons

Can someone please explain to me why this doesn't work? The Buttons in the ToolBar are not getting the Black BorderBrush property setting. I've tried TargetType="Button" and TargetType="{x:Type Button}" but neither work. I've done almost exactly the same thing for a series of Labels and it worked fine. I'm pretty new to WPF. Is there something I'm not understanding about style precedence here? Thanks!
...Window Definition...
<Grid>
<Grid.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="BorderBrush" Value="Black" />
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ToolBar Grid.Column="0" Grid.Row="0" Margin="0">
<Button>
<StackPanel Orientation="Horizontal" Height="Auto">
<Rectangle Width="16" Height="16" Fill="LightBlue" VerticalAlignment="Center"></Rectangle>
<Label Padding="0" VerticalAlignment="Center" HorizontalAlignment="Left">Redraw</Label>
</StackPanel>
</Button>
... More Buttons ...
</ToolBar>
</Grid>
... End Window Definition ...
here you go
<Style x:Key="{x:Static ToolBar.ButtonStyleKey}"
TargetType="{x:Type Button}">
<Setter Property="BorderBrush"
Value="Black" />
</Style>
from How to: Style Controls on a ToolBar
The ToolBar defines ResourceKey objects to specify the style of controls within the ToolBar. To style a control in a ToolBar, set the x:key attribute of the style to a ResourceKey defined in ToolBar.
The ToolBar defines the following ResourceKey objects:
ButtonStyleKey
CheckBoxStyleKey
ComboBoxStyleKey
MenuStyleKey
RadioButtonStyleKey
SeparatorStyleKey
TextBoxStyleKey
ToggleButtonStyleKey

Nested ContentControls with template

I have a custom WindowStyle, the XAML looks like this:
<Style TargetType="{x:Type Window}"
x:Key="WindowStyle">
/** Some setters **/
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<AdornerDecorator>
<Grid Background="#88000000"
x:Name="WindowBackgroundGrid">
<Border x:Name="WindowContentBorder"
Background="{DynamicResource WindowBackground}"MaxHeight="{Binding Source={x:Static SystemParameters.FullPrimaryScreenHeight}}"
MaxWidth="{Binding Source={x:Static SystemParameters.FullPrimaryScreenWidth}}"
Margin="20">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Header -->
<Border BorderBrush="{DynamicResource BorderBrushColor}"
Background="{DynamicResource PaneHeader_Background}"
Grid.Row="0">
<TextBlock Text="Title"Foreground="{DynamicResource DefaultForeground}"
FontSize="16"
FontWeight="Bold"
Margin="5,5,2,5" />
</Border>
<!-- Content -->
<ScrollViewer Grid.Row="1"
Margin="5">
<ContentPresenter Content="{TemplateBinding Content}" />
</ScrollViewer>
</Grid>
</Border>
</Grid>
</AdornerDecorator>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Now I want the inner Grid in a seperate Style so that I can use it elsewhere.
<Style x:Key="WindowContentStyle"
TargetType="{x:Type ContentPresenter}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Header -->
/** Border control **/
<!-- Content -->
<ScrollViewer Grid.Row="1"
Margin="5">
<ContentPresenter Content="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}" />
</ScrollViewer>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
And I use a ContenPresenter in my WindowStyle to present it:
<ContentPresenter>
<ContentPresenter.Style>
<Style TargetType="{x:Type ContentPresenter}"
BasedOn="{StaticResource WindowContentStyle}" />
</ContentPresenter.Style>
</ContentPresenter>
Problem
The edit above didn't give me any errors, but it doesn't present my WindowContentStyle.
When I set the Content property of the Window control and load the style
this.window.Content = view;
this.window.Style = (Style)Application.Current.TryFindResource("WindowStyle");
the content is shown in the ContentPresenter in the WindowStyle and not in WindowContentStyle. Because of this, the Template is not used and I don't have a header with a title.
How can I make my outer ContentPresenter pass on the Content to my inner ContentPresenter (the one in WindowContentStyle)?
Thanks in advance!
Greetings
Loetn
You should use a ContentControl to display your content, not a ContentPresenter. From the ContentPresenter Class page on MSDN:
You typically use the ContentPresenter in the ControlTemplate of a ContentControl to specify where the content is to be added.
From the ContentControl Class page on MSDN:
A ContentControl has a limited default style. If you want to enhance the appearance of the control, you can create a new DataTemplate.

Silverlight create control template for TabControl

I use Silverlight 5 and want to use control template for TabControl. how can do it.
In WPF you can use below code for control template of TabControl
<Style TargetType="{x:Type TabControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<TabPanel Grid.Column="1" Name="HeaderPanel" IsItemsHost="True"/>
<ContentPresenter Grid.Column="0" ContentSource="SelectedContent"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Thanks in advance.
By far the easiest way to customise the TabControl template is with Expression Blend.
However, the ControlTemplate for a Silverlight TabControl should look mostly the same as your example. There are a couple of notable differences though.
TargetType syntax is different
TargetType="TabControl"
There is also no ContentSource property on the ContentPresenter

How to specify 3/4th of are for one content presenter?

I am creating a new template for Tab control
in which I need to arrange items like attached image. The style given below is to have main tabs ..and contents... While mentioning the content (content presenter) I have to specify the grid column/row...So if I use row column/row as "0","0"..then all my contents will in the left top area...
Please tell me how do I specify a content presenter with 3/4 area of the grid.
<Style x:Key="OutlookTabControlStyle" TargetType="{x:Type TabControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid ClipToBounds="true" SnapsToDevicePixels="true"
KeyboardNavigation.TabNavigation="Local">
<Grid.RowDefinitions>
<RowDefinition x:Name="RowDefinition0" Height="Auto"/>
<RowDefinition x:Name="RowDefinition1" Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="ColumnDefinition0"/>
<ColumnDefinition x:Name="ColumnDefinition1" Width="0"/>
</Grid.ColumnDefinitions>
<Grid x:Name="ContentPanel" Grid.Column="0" Grid.Row="1">
<ContentPresenter SnapsToDevicePixels=
"{TemplateBinding SnapsToDevicePixels}" Margin="2,2,2,2"
x:Name="PART_SelectedContentHost"
ContentSource="SelectedContent"/>
</Grid>
<StackPanel HorizontalAlignment="Stretch" Margin="0,-2,0,0"
x:Name="HeaderPanel" VerticalAlignment="Bottom" Width="Auto"
Height="Auto" Grid.Row="1" IsItemsHost="True"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground"
Value="{DynamicResource
{x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
My question is how do I allocate the remaining part (other than main tabs area) as content paresenter... I can see Canvas as one option. please help me if you know more about this.
Create a Grid with two Columns: one column with a width of * and one with a width of 3*. This will make make your 2nd column 3 times the size of the first column, or 3/4 of the total size
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="3*" />
</Grid.ColumnsDefinitions>
</Grid>
As an alternative you don't want to use a Grid, I usually use a MathConverter which allows me to adjust a bound value by a mathematical formula. The code for the MathConverter can be found here
<Grid Canvas.Left="{Binding ElementName=ParentPanel, Path=ActualWidth,
Converter={StaticResource MyMathConverter},
ConverterParameter=#VALUE*.75}" />

How do I Show/Hide a Grid Row and Grid Splitter based on a Toggle Button?

Currently I have a toggle button that is bound to a boolean property (DualLayout) in my code behind. When the boolean is set to True, then I want my second row in my grid (and grid splitter) to hide and have the first row take up the entire space of the grid. Once the boolean is set to False, I want the grid splitter and bottom row to appear.
Here is a snippet of my xaml
<ToggleButton Name="toggleLayout" Margin="66,1,0,1" Width="25" HorizontalAlignment="Left" IsChecked="{Binding DualLayout}" Checked="toggleLayout_Clicked" Unchecked="toggleLayout_Clicked">
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Style.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type ToggleButton}">
<Image Source="Images/PlayHS.png"/>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="ToolTip" Value="Receive and Transmit Windows Split."/>
</Trigger>
<Trigger Property="IsChecked" Value="false">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type ToggleButton}">
<Image Source="Images/PauseHS.png"/>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="ToolTip" Value="Receive and Transmit Windows Combined."/>
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
<Grid x:Name="transmissionsGrid" Margin="0,28,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*" MinHeight="100" />
</Grid.RowDefinitions>
<transmission:TransmissionsControl x:Name="transmissionsReceive" TransmissionType="Receive" Margin="0,0,0,5" />
<GridSplitter Name="gridSplitter1" Grid.Row="0" Background="White" Cursor="SizeNS" Height="4" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Foreground="Firebrick" />
<transmission:TransmissionsControl x:Name="transmissionsTransmit" TransmissionType="Transmit" Grid.Row="1" />
</Grid>
This is untested, but I believe it should work.
First, if you want your first row to take up the whole space, you'll want to define your RowDefinitions as
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto" /> <!-- Edit: Removed MinHeight="100" -->
</Grid.RowDefinitions>
For showing/hiding the controls, you'll need to bind their Visibility property either to your DualLayout property (if the class properly implements INotifyPropertyChanged), or (perhaps more simply) to the IsChecked property of the ToggleButton.
For instance (the same applies to the GridSplitter):
<!-- EDIT: Added MinHeight="100" here instead -->
<transmission:TransmissionsControl x:Name="transmissionsTransmit"
TransmissionType="Transmit"
Grid.Row="1"
MinHeight="100"
Visibility={Binding ElementName=toggleLayout,
Path=IsChecked,
Converter={StaticResource boolToVis}}" />
At some level above the controls in question (here I am doing it at the window level) you need to add built-in BooleanToVisibilityConverter resource:
<Window.Resources>
<BooleanToVisibilityConverter x:Key="boolToVis" />
</Window.Resources>

Resources