XAML in WP8.1: Child Element Styles - wpf

I have a Grid and TextBlocks. I want to style all TextBlocks within the Grid. So I do this:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.Resources>
<Style TargetType="TextBlock">
<Setter Property="Margin" Value="0,0,0,15" />
</Style>
</Grid.Resources>
<StackPanel Grid.Column="0">
<TextBlock Text="myText" Style="{StaticResource TitleTextBlockStyle}" />
<TextBlock Text="myText" Style="{StaticResource TitleTextBlockStyle}" />
</StackPanel>
<StackPanel Grid.Column="1">
<TextBlock Text="123456" Style="{StaticResource TitleTextBlockStyle}" Foreground="{ThemeResource PhoneAccentBrush}" />
<TextBlock Text="123456" Style="{StaticResource TitleTextBlockStyle}" Foreground="{ThemeResource PhoneAccentBrush}" />
</StackPanel>
</Grid>
1) It's not working. TextBlocks don't get any Margins. Why?
2) How can I set the Style and Foreground properties of TextBlocks in the <Grid.Resources> tag?

1) It's not working. TextBlocks don't get any Margins. Why?
It's not working because you're assigning the style "TitleTextBlockStyle" to the TextBlocks. So the implicit style you defined in Grid.Resources doesn't come in to play. Remove the Style="{StaticResource TitleTextBlockStyle}" parts from the TextBlocks, and your margins will appear.
2) How can I set the Style and Foreground properties of TextBlocks in the <Grid.Resources> tag?
The same as you set everything else:
<Setter Property="Foreground" Value="AliceBlue"/>
or if you have a more elaborate brush:
<Setter Property="Foreground">
<Setter.Value>
<!-- Whatever brush you want -->
<Setter.Value/>
</Setter>
I assume that with "Set the style property of TextBlocks", you actually want your new style to inherit from an already defined style. In that case you can base your new style on an already existing style:
<Style TargetType="TextBlock"
BasedOn="{StaticResource StyleToInheritFrom}">
or, in your case, presumably:
<Style TargetType="TextBlock" BasedOn="{StaticResource TitleTextBlockStyle}">
<Setter Property="Margin" Value="0,0,0,15" />
</Style>
The full thing would look something like:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.Resources>
<Style TargetType="TextBlock" BasedOn="{StaticResource TitleTextBlockStyle}">
<Setter Property="Margin" Value="0,0,0,15" />
<Setter Property="Foreground" Value="{ThemeResource PhoneAccentBrush}"/>
</Style>
</Grid.Resources>
<StackPanel Grid.Column="0">
<TextBlock Text="myText" />
<TextBlock Text="myText" />
</StackPanel>
<StackPanel Grid.Column="1">
<TextBlock Text="123456" />
<TextBlock Text="123456" />
</StackPanel>
</Grid

What sort of margins are you looking for? If you are looking for left right margins, its due to your margin declaration. Declare like this:
<object Margin="left,top,right,bottom"/>
- or -
<object Margin="left,top"/>
- or -
<object Margin="thicknessReference"/>
Right now, you're just adding a bottom margin. You could also just add
Margin="15"
which will be interpreted as a thickness reference and set all values to 15

Related

How to keep a button to the right of a datagrid header

I want to add a button to the datagrid header column and keep it at the right-most edge of the header column... no matter how wide it is. In my Xaml code I am using a DataTemplate where I attach the header column title and add a toggle button with a popup window.
<DataGrid>
<DataGrid.Resources>
<DataTemplate x:Key="HeaderTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<DataGrid.Resources>
<ContentControl Content="{Binding}" VerticalAlignment="Center"/>
<!--TODO: THIS IS THE BUTTON I WANT TO ANCHOR TO THE RIGHT-->
<ToggleButton Name="FilterButton" Grid.Column="1" Content="▼" Margin="2, 1, 1, 1" Padding="1, 0"/>
<Popup IsOpen="{Binding ElementName=FilterButton, Path=IsChecked}" PlacementTarget="{Binding ElementName=FilterButton}" StaysOpen="False">
<Border Background="White" Padding="3">
<TextBox Width="300"/>
</Border>
</Popup>
</Grid>
</DataTemplate>
</DataGrid.Resources>
When I launch my application I do see the header column with the toggle button right next to it. But I need it to be in the rightmost of any column header. Like this:
Can someone help me understand how to go about doing this with the code I currently have?
After a bit of fiddling, here's what I did to get it to work:
<DataGrid>
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
<DataTemplate x:Key="HeaderTemplate">
<Grid Margin="0, 0, -5, 0">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<ContentControl Content="{Binding}" VerticalAlignment="Center"/>
<!--TODO: THIS IS THE BUTTON I WANT TO ANCHOR TO THE RIGHT-->
<ToggleButton Name="FilterButton" Grid.Column="1" Content="▼" Margin="2, 1, 1, 1" Padding="1, 0"/>
<Popup IsOpen="{Binding ElementName=FilterButton, Path=IsChecked}" PlacementTarget="{Binding ElementName=FilterButton}" StaysOpen="False">
<Border Background="White" Padding="3">
<TextBox Width="300"/>
</Border>
</Popup>
</Grid>
</DataTemplate>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn HeaderTemplate="{StaticResource HeaderTemplate}" Header="Test"/>
</DataGrid.Columns>
</DataGrid>
There are two key changes.
First, I added this to DataGrid.Resources:
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
Which lets the HeaderTemplate fill the the entire header.
Second, I added a negative right margin to the Grid:
<Grid Margin="0, 0, -5, 0">
This compensates for the internal padding of the header's control template, moving the button fully to the right.
The problem here is that the content inside the header is Autosized. What you need to do is to change the Horizontal Alignment of the content. You can define a style for Column header and that will resolve the issue.
<DataGrid.Resources>
<Style TargetType="DataGridColumnHeader">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</DataGrid.Resources>

Silverlight Style : custom style based on custom style

Someone has done a custom style for the buttons of the application. Now I want to create a custom style based on this custom style. For example I want to make a "close button" that I want to reuse all other the application. I tried this :
<Style x:Key="GlassButtonClose" TargetType="Button" BasedOn="{StaticResource GlassButton}">
<Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Grid.Row="0" Source="/Balisage;component/Images/Close.png" Width="24" Height="24" />
<TextBlock Grid.Column="1" VerticalAlignment="Center" Text="{Binding Source={StaticResource LocCommonStrings}, Path=ButtonLabelClose}" Margin="0" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
But this doesn't keep the GlassButton settings. How can I just extend the settings, keeping the existing ones ?
Thanks for your help
Based on the shown template and your answer in the comments it looks like you only need to have a spacific GlassButton with a fixed icon and text. And you want to use this button without the need to specify its content again and again.
Solution:
Prepare your own type GlassStyleCloseButton.
public class GlassStyleCloseButton : Button
{
public GlassStyleCloseButton() {
DefaultStyleKey = typeof(GlassStyleCloseButton); }
}
and a style for the new type (can be placed in app.xaml or generic.xaml):
<Style TargetType="GlassStyleCloseButton" BasedOn="{StaticResource GlassButton}">
<Setter Property="Content" Value="{Binding Path=ButtonLabelClose,
Source={StaticResource LocCommonStrings}}"/>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image
Source="/Balisage;component/Images/Close.png"
Width="24"
Height="24"/>
<TextBlock
Grid.Column="1"
VerticalAlignment="Center"
Text="{TemplateBinding Content}"/>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
and you can use it like this:
<SomewhereInMyApp>
...
<GlassStyleCloseButton/>
</SomewhereInMyApp>

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.

Show "pop up window" when is mouser over listBox item

I bind observable collection on listBox. I have data tempate on listbox item. It consit one image control and som textBlock.
If is mouse over on some listBox item I would like achieve this behavior:
Show PopUp/ToolTip (some "rectangle" with controls) and bind values from listBox current item.
And on textBox in item data template I have style, I would like change color of text in textBlock, for example from black to green.
Style is here:
<Style x:Key="FriedNickStyle" TargetType="TextBlock">
<Setter Property="Margin" Value="2,2,2,2"/>
<Setter Property="FontSize" Value="13"/>
<Setter Property="FontWeight" Value="Medium"/>
<Setter Property="Foreground" Value="Black"/>
</Style>
Sory for my english, I have problem how describe this behavior correct. I try many thing but any of them doesn’t work good.
Here is it my style:
<DataTemplate x:Key="FriendListBoxItemTemplate">
<Grid Name="RootLayout">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.3*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="60"></RowDefinition>
</Grid.RowDefinitions>
<Image Margin="4,4,4,2" Grid.Column="0">
<Image.Source >
<MultiBinding Converter="{StaticResource avatarConverter}">
<Binding Path="ProfilePhoto"></Binding>
<Binding Path="StatusInfo.IsLogged"></Binding>
</MultiBinding>
</Image.Source>
</Image>
<Grid Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock
Text="{Binding Path=Nick}"
Style="{StaticResource FriedNickStyle}"
Grid.Column="0" Grid.Row="0">
</TextBlock>
</Grid>
</Grid>
<DataTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<!--SHOW SOME POP UP WINDOW and bind properties from ITEM (VALUE)-->
<!--Change color of textBlock-->
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
Thank everybody who help me.
Well, I found this turorial, this article, by the MSDN and another stack overflow's question.
Basically, here's how:
<Popup Margin="10,10,0,13"
Name="Popup1"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="194"
Height="200"
IsOpen="True"> // change this to open it
<TextBlock Name="McTextBlock" Background="LightBlue" >
This is popup text
</TextBlock>

How to center a WPF CheckBox within a ListBoxItem

I have a ListBox that uses an ItemContainerStyle. I have tried everything I can think of to get a CheckBox control to center vertically and horizontally. Any ideas?
<ListBox
IsSynchronizedWithCurrentItem="True"
Height="Auto" Width="Auto" DockPanel.Dock="Top"
ItemContainerStyle="{StaticResource lbcStyle}" />
<Style TargetType="ListBoxItem" x:Key="lbcStyle">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="ContentTemplate" Value="{StaticResource editable}"/>
</Trigger>
</Style.Triggers>
<Setter Property="ContentTemplate" Value="{StaticResource nonEditable}"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/> '//i have tried stretch here also
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
</Style>
CheckBoxes get this style:
<Style x:Key="editorCheckBox" TargetType="{x:Type CheckBox}">
<Setter Property="MinWidth" Value="67" />
<Setter Property="Height" Value="25" />
<Setter Property="Margin" Value="5,0,5,0" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Center" />
</Style>
Here are editable / non-editable:
<DataTemplate x:Key="editable">
<Border x:Name="brdEditable" Width="Auto" HorizontalAlignment="Stretch">
<DockPanel x:Name="dpdEditable" LastChildFill="True" Width="Auto" Height="Auto">
<Grid x:Name="grdEditable" Width="Auto" Height="Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25" />
<ColumnDefinition Width="25" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="80" />
<ColumnDefinition Width="110" />
<ColumnDefinition Width="110" />
<ColumnDefinition Width="60" />
<ColumnDefinition Width="90" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
'...
<CheckBox x:Name="chkActive" Grid.Column="7" Height="25" Style="{StaticResource editorCheckBox}" ToolTip="Is Construction Active?" IsEnabled="true" Validation.ErrorTemplate="{StaticResource validationTemplate}">
<CheckBox.IsChecked>
<Binding Path="Active">
<Binding.ValidationRules>
<DataErrorValidationRule></DataErrorValidationRule>
<ExceptionValidationRule></ExceptionValidationRule>
</Binding.ValidationRules>
</Binding>
</CheckBox.IsChecked>
</CheckBox>
'...
<ContentControl Name="ExpanderContent" Visibility="Collapsed" Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="14"></ContentControl>
</Grid>
</DockPanel>
</Border>
</DataTemplate>
<DataTemplate x:Key="nonEditable">
<Border x:Name="brdNonEditable" Width="Auto" HorizontalAlignment="Stretch">
<DockPanel Width="Auto" Height="25">
<Grid Width="Auto" Height="25">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25" />
<ColumnDefinition Width="25" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="80" />
<ColumnDefinition Width="110" />
<ColumnDefinition Width="110" />
<ColumnDefinition Width="60" />
<ColumnDefinition Width="90" />
</Grid.ColumnDefinitions>
<CheckBox x:Name="chkActive" Grid.Column="7" Height="25" Style="{StaticResource editorCheckBox}" ToolTip="Is Construction Active?" IsEnabled="false" Validation.ErrorTemplate="{StaticResource validationTemplate}">
<CheckBox.IsChecked>
<Binding Path="Active">
<Binding.ValidationRules>
<DataErrorValidationRule></DataErrorValidationRule>
<ExceptionValidationRule></ExceptionValidationRule>
</Binding.ValidationRules>
</Binding>
</CheckBox.IsChecked>
</CheckBox>
<Label Content="calCompDate" Style="{StaticResource editorLabelList}" Grid.Column="8" ToolTip="{Binding Path= CompDate}" />
</Grid>
</DockPanel>
</Border>
</DataTemplate>
And thanks so much to everyone who has tried to help me solve this!
Try setting the ScrollViewer.HorizontalScrollBarVisibility property to "Disabled" on the ListBox. This forces the item containers to have a fixed width; otherwise, they can have any horizontal size, and horizontal alignment cannot be calculated sensibly.
Vertical alignment should be a matter of modifying the ListBoxItem style, as per Donnelle's answer.
Edit: In your code snippets, the CheckBox is inside a Grid which is inside a DockPanel which is inside a Border. Which element are you trying to center exactly? Are you sure the rest of them don't interfere? Here's how it looks for me with my suggestion and HorizontalContentAlignment="Center", and only the checkbox in the data template:
One more edit: I copy/pasted your grid/dockpanel/border exactly as they appear in the snippets you pasted, and the result is exactly the same - items centered horizontally.
I've had the same issue to. Have you tried setting "HorizontalAlignment" directly on the ListBoxItem in the style? (not HorizontalContentAlignment)
Have you tried setting HorizontalContentAlignment to "Stretch" on the ListBox itself? I believe this is necessary to make each ListBoxItem fill the width of the ListBox.
Setting the height on the ListBoxItem style-- rather than the checkbox-- does what I think you're after.
The checkbox is aligned top-left. For a quick and dirty, I have updated the margin on the checkbox to 4,3,0,0 on a row heigh of 20. May need to be adjusted depending upon your row height and if you want a buffer on the left. The margin attribute can get you out of odd format situations if you don't have time to write your own template or use other controls/containers.

Resources