WPF, Font style for multiple controls - wpf

ok, I might be missing something really easy, But I want to use the same Font family, Font Size, and color for multiple controls.
Is there a way to create one style for this and apply it different controls?
Sorry if this has been asked before.
Thanks

Are the controls all in the same container? For example, in the same Window or StackPanel? If so, you can make set those properties on the parent container and they'll apply to any children. For example:
<StackPanel TextBlock.FontFamily="Comic Sans"
TextBlock.FontSize="14"
TextBlock.Foreground="Purple">
<TextBlock Text="Yeah, baby! I love me some Comic Sans!" />
<Button Content="Me too!" />
</StackPanel>
If you want to standardize the font across your entire app, you can use an implict style in your App.xaml file, like this:
<Style TargetType="TextBlock">
<Setter Property="FontFamily" Value="Comic Sans" />
<Setter Property="FontSize" Value="14" />
<Setter Property="Foreground" Value="Purple" />
</Style>

I wanted to add this for the newbies (like myself).
If you want to set a property for multiple items within a container:
You can set a "style" within the "resources" for a control like so:
<Grid>
<Grid.Resources>
<Style TargetType="TextBlock">
<Setter Property="FontSize" Value="22"/>
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="hello text" />
<TextBlock Grid.Row="1" Text="hello text1" />
<TextBlock Grid.Row="2" Text="hello text2" />
</Grid>

Related

Rational creation of XAML markup for readibility and sanity

Disclaimer: Not sure what to put in the title to make it clear as the words to be used are the ones that I don't know (yet) and am asking about. Feel free to correct.
Imagine a scenario with GUI consisting of 4x3 inputs, where every input consists of a label and a textbox. At the moment, it's done by explicitly declaring all the components and each component has the for as follows.
<Label x:Name="Label1"
Content="Text1"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="10,210,0,0" />
<TextBox x:Name="TextBox1"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="120"
Height="23" Margin="10,241,0,0"
TextWrapping="Wrap" Text="TextBox" />
Is there a recommended way to generate those from "something else", like a template or such, that's governing all the common attributes in it, eliminating the need for me to type them in over and over again (well, those were autogenerated but still...)? The alignments and sizes are tedious...
As for the margins, perhaps there's a layouting functionality? I've googled it but the hits related to XAML I've got were either suspiciously weird or relying on code behind. Is that the way to go or is it doable from XAML straight off?
To properly configure your layout, you should use WPF Layout Controls. In order to make the grid layout, you can use Grid, UniformGrid, etc., depending on your needs.
In order to apply several properties to the all controls inside the layout control, you can define the Style in the Resources of that control, as was mentioned already:
<Grid>
<Grid.Resources>
<Style TargetType="TextBox">
<Setter Property="Width" Value="120" />
<Setter Property="Height" Value="25" />
<!-- etc... -->
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<!-- Row definitions here. -->
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<!-- Column definitions here. -->
</Grid.ColumnDefinitions>
<!-- controls ... -->
<TextBox Text="{Binding YourProperty}"
Grid.Row="1"
Grid.Column="2"
/>
<!-- controls ... -->
</Grid>
Here the style will be applied to all TextBox's controls.
You're referring to a WPF "Style." With styles, you define a set of properties that will be the same between all instances of a control which use that style.
<Style x:Key="MyTextBoxStyle" TargetType="TextBox">
<Setter Property="Width" Value="120" />
<Setter Property="Height" Value="23" />
<Setter Property="TextWrapping" Value="Wrap" />
<!-- etc... -->
</Style>
<!-- This textbox will default its property values to those defined above -->
<TextBox Style="{StaticResource MyTextBoxStyle}" />

Grid ColumnDefinition.Width in DataTemplate

In my project, I've made a control that inherits from Control. It is called DialogHeader and, as its name stands, is for displaying a header on modal, non-resizable dialogs. In truth, it binds by default to its parent Window. The control has a property called IconLocation, i.e. whether the image should be displayed on the left or right side of the control's label:
[Image] [Label] -- or -- [Label] [Image]
The template used with DialogHeader is basically the following:
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="COLN_Left" Width="auto" />
<ColumnDefinition Width="auto" />
<ColumnDefinition x:Name="COLN_Right" Width="*" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Name="PART_Image" />
<Separator Grid.Column="1"
Visibility="Collapsed" Width="{TemplateBinding SpacerWidth}" />
<TextBlock Grid.Column="2" Name="PART_Text" />
</Grid>
<ControlTemplare.Triggers>
<Trigger Property="ImageLocation" Value="Right">
<Setter TargetName="PART_Image" Property="Grid.Column" Value="2" />
<Setter TargetName="PART_Text" Property="Grid.Column" Value="0" />
<!-- The following doesn't work! Help! -->
<Setter TargetName="COLN_Left" Property="Width" Value="*" />
<Setter TargetName="COLN_Right" Property="Width" Value="auto" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
Simply put, when the ImageLocation property is set to Location.Right, the widths of COLN_Left and COLN_Right should be exchanged. So instead of [auto][auto][*], I should have [*][auto][auto].
How can I make this work from the ControlTemplate? If not, is there are way that doesn't involve using C# code?
Thank you in advance.
That part does work, it possibly is just not what you want i presume. Try to remove it and the result should be different.

Use checkbox as togglebutton in expander

Im quite new to wpf and have to following problem.
I need to create a List (i am using a listbox) of items that can be expanded (expander).
The problem is, that they can be expanded, only if they have been 'selected'.
Each listboxitem should have a checkbox and some text.
So very basic example to illustrate what i mean:
<listbox>
<item>(checkbox) John Doe</item>
<item>(checkbox) Mike Murray</item>
</listbox>
If any (so multiple is allowed) of the checkboxes in the listbox are checked, then
the item expands showing more data.
Again an example:
<listbox>
<item>
(checkbox-checked) John Doe
Some extra data shown in expanded area
</item>
<item>
(checkbox-unchecked) Mike Murray</item>
</listbox>
I cant get a expander to use a checkbox as 'togglebutton'.
Could anyone help me out? Some example code would be very welcome...
This should do the trick:
<ListBox>
<ListBox.Resources>
<Style TargetType="Expander">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Expander">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<CheckBox
IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource TemplatedParent}}"
Content="{TemplateBinding Header}"
/>
<ContentControl
x:Name="body"
Grid.Row="1" Content="{TemplateBinding Content}"
/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="False">
<Setter TargetName="body" Property="Visibility" Value="Collapsed" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.Resources>
<Expander Header="One">
Content one
</Expander>
<Expander Header="Two">
Content two
</Expander>
</ListBox>
I've defined a Style here that changes the Template of any Expander controls to which the Style is applied. (And since I've put the Style in the ListBox.Resources it'll automatically apply to an Expander controls in the list.)
The trick to getting the CheckBox to work is that when you put it (or indeed any ToggleButton based control) into an Expander template, you need to use a data binding configured with its RelativeSource set to the TemplatedParent. This enables two-way binding - it means that not only does the CheckBox reflect the current state of the expander, it is also able to change the current state.
All you need to add a check box in the header is this code:
<telerik:RadExpander.Header>
<StackPanel Orientation="Horizontal">
<CheckBox VerticalAlignment="Center"/>
<TextBlock Margin="5,0,0,0">Legend</TextBlock>
</StackPanel>
</telerik:RadExpander.Header>
I am using Rad Control, The same can be done using the standard expander

Why does the style change when I add an an accelerator to my button?

When I have my button's content as a normal string e.g. <Button Content="Ok" /> then button behaves as normal. But if I change the content to have a keyboard accelerator e.g. <Button Content="_Ok" /> the button's style changes to have different margins and sizes.
I have a TextBlock style that doesn't have a key so is being applied to all TextBlocks, my question is why is it applied when it the content has an accelerator and not when it doesn't?
Edit: For extra info: The default style is inside the resources of a StackPanel that is the button is inside. I guess the question is really, why doesn't the default TextBlock style get applied when the button has an accelerator?
WPF adds a TextBlock to each Button (and Menu) with an accelerator.
You can see this effect by running the following XAML (remember to hook up the Command if needed).
The key to fixing the problem, given the scope of your question, is to set the TextAlignment to a value of Center for the TextBlock. If you set the Width for the TextBlock style (my line is commented out below) the text will start to shift. Adding HorizontalAlignment = Center also helps center text in the TextBlock/Button, but this also impacts the other TextBlock controls.
<Window x:Class="ButtonAccelerator.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Main Window" Height="400" Width="800">
<Window.Resources>
<Style TargetType="TextBlock">
<!--<Setter Property="Width" Value="70"/>-->
<Setter Property="Height" Value="23"/>
<Setter Property="Background" Value="Pink"/>
<Setter Property="TextAlignment" Value="Center"/>
</Style>
<Style TargetType="Button">
<Setter Property="Width" Value="70"/>
<Setter Property="Height" Value="23"/>
</Style>
</Window.Resources>
<DockPanel>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<StackPanel
Grid.Row="1" Grid.Column="1"
HorizontalAlignment="Right"
Orientation="Horizontal">
<TextBlock Text="OK" />
<Button
Content="OK"/>
<Button
Content="_OK"/>
</StackPanel>
</Grid>
</DockPanel>
</Window>
You should verify this with Snoop but <Button Content="Ok" /> produces a TextBlock to handle the text within a button. Since TextBlock doesn't support accelerator keys I would bet that <Button Content="_Ok" /> causes it to produce a Label instead since a Label will take care of the accelerator key.

Setting VerticalAlignment property to all controls

My WPF UserControl contains two stack panels and each of them contains labels, text boxes and radio buttons.
I would like to set VerticalAlignment property to Center to all controls in my UserControl with as little code as possible.
Now I have following solutions:
brute force - put VerticalAlignment="Center" in each control
define one style for FrameworkElement and apply it directly
define styles for each type of the controls on user control (this needs 3 style definitions, but automatically applies style to the control)
These three solutions need too much code.
Is there any other way to write this?
I hoped that defining style for FrameworkElement would automatically set property to all controls, but it does not work.
Here is snippet of my current XAML (I omitted second, very similar stack panel):
<UserControl.Resources>
<Style x:Key="BaseStyle" TargetType="FrameworkElement">
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</UserControl.Resources>
<Grid>
<StackPanel Orientation="Horizontal">
<TextBlock Style="{StaticResource BaseStyle}" Text="Value:" />
<RadioButton Style="{StaticResource BaseStyle}">Standard</RadioButton>
<RadioButton Style="{StaticResource BaseStyle}">Other</RadioButton>
<TextBox Style="{StaticResource BaseStyle}" Width="40"/>
</StackPanel>
</Grid>
Edit:
Re Will's comment: I really hate idea of writing control formatting code in codebehind. XAML should be sufficient for this really simple user control.
Re Muad'Dib's comment: Controls I use in my user control are derived from FrameworkElement, so this is not an issue here.
I had come across the same conundrum awhile ago as well. Not sure if this is the "best" way, but it was easy enough to manage by defining your base style and then creating separate styles for each control on the page that inherited from the base style:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="500" Height="300" Background="OrangeRed">
<Page.Resources>
<Style TargetType="FrameworkElement" x:Key="BaseStyle">
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Margin" Value="0,0,5,0" />
</Style>
<Style TargetType="TextBlock" BasedOn="{StaticResource BaseStyle}" />
<Style TargetType="RadioButton" BasedOn="{StaticResource BaseStyle}" />
<Style TargetType="TextBox" BasedOn="{StaticResource BaseStyle}" />
</Page.Resources>
<Grid>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Value:" />
<RadioButton>Standard</RadioButton>
<RadioButton>Other</RadioButton>
<TextBox Width="75"/>
</StackPanel>
</Grid>
</Page>

Resources