Extend Custom TreeView itemcontainers style? - wpf

How can I extend upon the style I have declared in CustomTreeView? so that I have a lightgray foreground and a green background?
CustomTreeView.xaml
<TreeView x:Class="WpfApplication17.CustomTreeView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="Foreground" Value="LightGray"/>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
Window.xaml
<Window x:Class="WpfApplication17.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication17">
<local:CustomTreeView ItemsSource="{Binding Data}">
<local:CustomTreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource {x:Type TreeViewItem}}">
<Setter Property="Background" Value="Green"/>
</Style>
</local:CustomTreeView.ItemContainerStyle>
</local:CustomTreeView>
</Window>

Not sure if this is the right approach, but I ended up using it.
<TreeView x:Class="WpfApplication17.CustomTreeView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TreeView.Resources>
<Style x:Key="m_itemContainerStyle" TargetType="{x:Type TreeViewItem}">
<Setter Property="Foreground" Value="LightGray"/>
</Style>
</TreeView.Resources>
<TreeView.ItemContainerStyle>
<Style BasedOn="{StaticResource m_itemContainerStyle}" TargetType="{x:Type TreeViewItem}">
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
<Window x:Class="WpfApplication17.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication17">
<local:CustomTreeView ItemsSource="{Binding Data}">
<local:CustomTreeView.ItemContainerStyle>
<Style BasedOn="{StaticResource m_itemContainerStyle}" TargetType="{x:Type TreeViewItem}">
<Setter Property="Background" Value="Green"/>
</Style>
</local:CustomTreeView.ItemContainerStyle>
</local:CustomTreeView>
</Window>

Related

How to put ContextMenu into Window.Resources

As you can see I am able to put Height property and Foreground property to the Window.Resources
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Height" Value="50"/>
<Setter Property="Foreground" Value="Green"/>
</Style>
</Window.Resources>
<Grid>
<TextBox Text="StackOverFlow">
<TextBox.ContextMenu>
<ContextMenu Background="Blue"/>
</TextBox.ContextMenu>
</TextBox>
</Grid>
</Window>
How can I put <ContextMenu Background="Blue"/> to the Window.Resources?
You can just put the context menu into separate resource
<Window.Resources>
<ContextMenu x:Key="ContextMenu" Background="Blue"/>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="Height" Value="50"/>
<Setter Property="Foreground" Value="Green"/>
<Setter Property="ContextMenu" Value="{StaticResource ContextMenu}"/>
</Style>
</Window.Resources>
<Grid>
<TextBox Text="StackOverFlow"/>
</Grid>

Binding to MainWindowViewModel property from app.xaml

I am trying to change the font-size globally. For this, I added styles in app.xaml. Here my FontSz property is in MainWindowViewModel. Is there any way to make this binding possible?
<Application.Resources>
<Style TargetType="{x:Type Control}" x:Key="baseStyle">
<Setter Property="FontSize" Value="{Binding Path=???.FontSz}" />
</Style>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource baseStyle}"/>
<Style TargetType="{x:Type Label}" BasedOn="{StaticResource baseStyle}"/>
</Application.Resources>
You will need to use DynamicResouce for this. Add the system namespace as below
xmlns:system="clr-namespace:System;assembly=mscorlib"
<Application.Resources>
<system:Double x:Key="FontSz">20</system:Double>
<Style x:Key="baseStyle"
TargetType="{x:Type Control}">
<Setter Property="FontSize"
Value="{DynamicResource FontSz}"/>
</Style>
<Style TargetType="{x:Type Button}"
BasedOn="{StaticResource baseStyle}"/>
<Style TargetType="{x:Type Label}"
BasedOn="{StaticResource baseStyle}"/>
</Application.Resources>
MainWindowViewModel
In your command execution, add the following code:
Application.Current.Resources["FontSz"] = 18d;
You can change the fontsize from 18d to the fontsize selected by the user in your MainViewModel.

Why doesn't my TextBlock/TextBox apply values from a Base Style?

It's not uncommon for me to write something like below for styling a data entry form, but my problem is that TextBox and TextBlock don't seem to implement the Setters that are in the BaseElementStyle. Usually I need to define them separately.
Why is this? And is there a way around it?
I am guessing it has to do with the fact they are usually used in other control templates (for example TextBlock is used in most controls and TextBox is used in DatePickers and ComboBoxes)
<Style x:Key="BaseElementStyle" TargetType="{x:Type FrameworkElement}">
<Setter Property="Margin" Value="5" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource BaseElementStyle}" />
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource BaseElementStyle}" />
<Style TargetType="{x:Type Label}" BasedOn="{StaticResource BaseElementStyle}" />
<Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource BaseElementStyle}" />
<Style TargetType="{x:Type DatePicker}" BasedOn="{StaticResource BaseElementStyle}" />
<Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource BaseElementStyle}" />
I would like to suggest the two possible workarounds. It seems that each of Key and Type can be used but both of them cannot be used together as your question case, x:Key="BaseElementStyle" TargetType="{x:Type FrameworkElement}".
using x:Key
<Style x:Key="BaseElementStyle">
<Setter Property="FrameworkElement.Margin" Value="5" />
<Setter Property="FrameworkElement.VerticalAlignment" Value="Center" />
</Style>
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource BaseElementStyle}" />
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource BaseElementStyle}" />
<Style TargetType="{x:Type Label}" BasedOn="{StaticResource BaseElementStyle}" />
<Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource BaseElementStyle}" />
<Style TargetType="{x:Type DatePicker}" BasedOn="{StaticResource BaseElementStyle}" />
<Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource BaseElementStyle}" />
using x:Type
<Style TargetType="{x:Type FrameworkElement}">
<Setter Property="Margin" Value="5" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource {x:Type FrameworkElement}}" />
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type FrameworkElement}}" />
<Style TargetType="{x:Type Label}" BasedOn="{StaticResource {x:Type FrameworkElement}}" />
<Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource {x:Type FrameworkElement}}" />
<Style TargetType="{x:Type DatePicker}" BasedOn="{StaticResource {x:Type FrameworkElement}}" />
<Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource {x:Type FrameworkElement}}" />
Also keep in mind that WPF considers a ControlTemplate to be an inflation boundary and does NOT apply default styles inside of templates. The exception to the rule: anything that inherits from Control WILL BE inflated with the default style. Since TextBlock inherits from FrameworkElement and not from Control, if you use of it inside of a ControlTemplate you will also have to apply it's style manually. This is true for both TextBlocks that are added by hand, or by TextBlocks added by WPF for string Content. A quick example:
<Window x:Class="ImplicitStyles.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<StackPanel.Resources>
<Style x:Key="BaseElementStyle">
<Setter Property="FrameworkElement.Tag" Value="Hello World" />
</Style>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource BaseElementStyle}" />
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource BaseElementStyle}" />
<!-- Default style for TextBlock will not be applied, Tag will be null -->
<ControlTemplate x:Key="MyContentControlTemplateOne" TargetType="{x:Type ContentControl}">
<Border BorderBrush="Red" BorderThickness="2">
<TextBlock Text="{Binding RelativeSource={RelativeSource Self}, Path=Tag}" />
</Border>
</ControlTemplate>
<!-- Default style for Button will be applied, Tag will be Hello World -->
<ControlTemplate x:Key="MyContentControlTemplateTwo" TargetType="{x:Type ContentControl}">
<Border BorderBrush="Red" BorderThickness="2">
<Button Content="{Binding RelativeSource={RelativeSource Self}, Path=Tag}" />
</Border>
</ControlTemplate>
</StackPanel.Resources>
<ContentControl Template="{StaticResource MyContentControlTemplateOne}" />
<ContentControl Template="{StaticResource MyContentControlTemplateTwo}" />
</StackPanel>
</Window>
For more information, see this blog post:
http://blogs.msdn.com/b/wpfsdk/archive/2009/08/27/implicit-styles-templates-controls-and-frameworkelements.aspx

Applying a style to all derived classes in WPF

I want to apply a style to all classes derived from Control. Is this possible with WPF?
The following example does not work. I want the Label, TextBox and Button to have a Margin of 4.
<Window x:Class="WeatherInfo.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Wetterbericht" Height="300" Width="300">
<Window.Resources>
<Style TargetType="Control">
<Setter Property="Margin" Value="4"/>
</Style>
</Window.Resources>
<Grid>
<StackPanel Margin="4" HorizontalAlignment="Left">
<Label>Zipcode</Label>
<TextBox Name="Zipcode"></TextBox>
<Button>get weather info</Button>
</StackPanel>
</Grid>
</Window>
Here's one solution:
<Window.Resources>
<Style TargetType="Control" x:Key="BaseStyle">
<Setter Property="Margin" Value="4"/>
</Style>
<Style BasedOn="{StaticResource BaseStyle}" TargetType="Button" />
<Style BasedOn="{StaticResource BaseStyle}" TargetType="Label" />
<Style BasedOn="{StaticResource BaseStyle}" TargetType="TextBox" />
</Window.Resources>
<Grid>
<StackPanel Margin="4" HorizontalAlignment="Left">
<Label>Zipcode</Label>
<TextBox Name="Zipcode"></TextBox>
<Button>get weather info</Button>
</StackPanel>
</Grid>
This is not possible in WPF. You have a couple of options to help you out:
Create one style based on another by using the BasedOn attribute.
Move the common information (margin, in this case) into a resource and reference that resource from each style you create.
Example of 1
<Style TargetType="Control">
<Setter Property="Margin" Value="4"/>
</Style>
<Style TargetType="TextBox" BasedOn="{StaticResource {x:Type Control}}">
</Style>
Example of 2
<Thickness x:Key="MarginSize">4</Thickness>
<Style TargetType="TextBox">
<Setter Property="Margin" Value="{StaticResource MarginSize}"/>
</Style>

WPF UserControl Style

I want to set the background property of all the usercontrols of my project.
I tried with
<style TargetType={x:Type UserControl}>
<setter property="Background" Value="Red" />
</style>
It compiles but didn't work.
¿Any Idea?
Thanks!
You can only set a a style to a specific class, so this will work (create a UserControl object, not very useful):
<Window.Resources>
<Style TargetType="{x:Type UserControl}">
<Setter Property="Background" Value="Red" />
</Style>
</Window.Resources>
<Grid>
<UserControl Name="control" Content="content"></UserControl>
</Grid>
But this doesn't (Create a class derived from UserControl):
<Window.Resources>
<Style TargetType="{x:Type UserControl}">
<Setter Property="Background" Value="Red" />
</Style>
</Window.Resources>
<Grid>
<l:MyUserControl Name="control" Content="content"></l:MyUserControl>
</Grid>
What you can do is either explicitly set the style using the Style property:
<Window.Resources>
<Style TargetType="{x:Type UserControl}" x:Key="UCStyle">
<Setter Property="Background" Value="Red" />
</Style>
</Window.Resources>
<Grid>
<l:MyUserControl Name="control" Content="content" Style="{StaticResource UCStyle}"></l:MyUserControl>
</Grid>
or create a style for each derived class, you can use BasedOn to avoid duplicating the style content:
<Window.Resources>
<Style TargetType="{x:Type UserControl}" x:Key="UCStyle">
<Setter Property="Background" Value="Red" />
</Style>
<Style TargetType="{x:Type l:MyUserControl}" BasedOn="{StaticResource UCStyle}" />
</Window.Resources>
<Grid>
<l:MyUserControl Name="control" Content="content"></l:MyUserControl>
</Grid>
I think you're missing some double quotes:
Try this:
<Window.Resources>
<Style TargetType="{x:Type UserControl}">
<Setter Property="Background" Value="Red" />
</Style>
</Window.Resources>
<Grid>
<UserControl Name="control" Content="content"></UserControl>
</Grid>

Resources