Button Style in Resource not Applied to Buttons - wpf

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

Related

Why does my ControlTemplate for Grid not work?

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>

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.

Apply style to Silverlight control only when that control is inside another control with specific style

I have a Grid control where each row contains a stackpanel, and each stackpanel contains one or more textblocks (while not the core of the question, if there's a better way to achieve a custom grid of textblocks - i.e. rows of "header label: content", I'd appreciate some tips)
Anyway... I want to have a header row, where the stackpanel has a dark background and the textblock has white, bold text, and then each other row to have black text. Note that only the first row is defined with Style HeaderRow. I've used the "BasedOn" to define that only textblocks within a header row should be bold/white, however I'm finding that this impacts all textblocks in other rows too (that don't have another style defined).
I'd effectively like to be able to do
Sample XAML
Styles:
<Style x:Key="TitleLabel" TargetType="TextBlock">
<Setter Property="FontFamily" Value="Verdana"/>
<Setter Property="Margin" Value="5 0 0 0"/>
<Setter Property="Width" Value="105"/>
<Setter Property="FontWeight" Value="Bold"/>
</Style>
<Style x:Key="AlternatingRow" TargetType="StackPanel">
<Setter Property="Background" Value="#f0f1ff"/>
</Style>
<Style x:Key="HeaderRow" TargetType="StackPanel">
<Setter Property="Background" Value="#666666"/>
</Style>
<Style TargetType="TextBlock" BasedOn="StaticResource HeaderRow" >
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontWeight" Value="Bold"/>
</Style>
XAML
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Grid.Row="0" Style="{StaticResource HeaderRow}">
<TextBlock Text="Header Row" />
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Row="1" Style="{StaticResource AlternatingRow}">
<TextBlock Text="HeaderLabel:" Style="{StaticResource TitleLabel}" />
<TextBlock Text="Content" />
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Row="2">
<TextBlock Text="HeaderLabel" Style="{StaticResource TitleLabel}" />
<TextBlock Text="Content" />
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Row="3" Style="{StaticResource AlternatingRow}">
<TextBlock Text="HeaderLabel" Style="{StaticResource TitleLabel}" />
<TextBlock Text="Content" />
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Row="4">
<TextBlock Text="HeaderLabel" Style="{StaticResource TitleLabel}" />
<TextBlock Text="Content" />
</StackPanel>
</Grid>
You are not using Style BasedOn property correctly. All it does is indicate that one style 'extends' another, i.e. it copies all its setter values. (Note, your example will also fail because you are trying to base on style on another where the TargetTypes are not compatible) It does not indicate that a style is applied when one element is nested inside another.
Unfortunately Silverlight does not have the feature you require, you cannot style based on element location within the visual tree. You are going to have to style each TextBlock explicitly.
Although, I did create a mechanism for using CSS for styling a while back:
http://www.scottlogic.co.uk/blog/colin/2009/03/using-css-selectors-for-styling-in-wpf/
This allows you to create selectors based on parent elements.

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>

Does anyone have a simple example of a UserControl with a single ContentPresenter?

So far, I have this:
<UserControl
x:Class="MyConcept.ExpanderPanel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Border
Style="{StaticResource Border_PanelStyle}"
CornerRadius="3" />
<ContentPresenter />
</Grid>
</UserControl>
Sample usage of this UserControl:
<nc:ExpanderPanel
Grid.Row="0">
<Expander
IsExpanded="True"
Header="NMT Users">
<StackPanel>
...
</StackPanel>
</Expander>
</nc:ExpanderPanel>
Discussion
If I run this, I see nothing. No content is presented, not even the border that is built into the UserControl.
I thought maybe I needed to make the ContentPresenter a dependency property, but I couldn't figure out how I would link the property to the ContentPresenter in the UserControl's XAML.
Can someone provide a simple example that shows how to build a UserControl (or some kind of custom control) with a single ContentPresenter?
ContentPresenters are main used in ControlTemplates and bound with a TemplateBinding to the ContentControl.Content.
from this site... a control template for a button that uses a ContentPresenter
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="White" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Rectangle Fill="{TemplateBinding Property=Background}" />
<ContentPresenter
Content="{TemplateBinding Property=ContentControl.Content}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Resources