WPF: Use multiple resources to target the same element or control - wpf

I would like to know if it is possible to use multiple resources to target the same element or control in WPF? I noticed that the XAML file cascade and the next XAML file in the resources list will overtake the next one if the same elements are targeted.
is it possible to get around this?
What I am trying to do is have one XAML file be my layout and positioning and one be strictly used for colors.
In my App.xaml My resources area as follows:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Views/LayoutAndPositioning/LayoutAndPositioning.xaml"/>
<ResourceDictionary Source="/Views/Theme/DefaultColors.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
LayoutAndPositioning.xaml for element
<Style x:Key="MyElement" TargetType="{Rectangle}">
<Setter Property="Margin" Value="200,200,200,200" />
</Style>
DefaultColors.xaml for element
<Style x:Key="MyElement" TargetType="{Rectangle}">
<Setter Property="Fill" Value="Green" />
<Setter Property="Width" Value="400" />
<Setter Property="Height" Value="200" />
</Style>
But when I try to target the same element in the 2 different files. The LayoutAndPositioning.xaml, which is first in the list, does not apply to the element since the DefaultColors.xaml does not have position styles in it. The DefaultColors.xaml does not have margin so my element just ends up having no margin property.
I have tested taking out the DefaultColors.xaml from the App.xaml resource list and the positioning returns. So it seems to be a cascading thing.
Does anyone have any ideas if it is possible to target the same element in 2 different Xaml files.

Try doing the following:
Merge LayoutAndPositioning.xaml into DefaultColors.xaml by doing the following at the to op DefaultColors.xaml
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Views/LayoutAndPositioning/LayoutAndPositioning.xaml"/>
</ResourceDictionary.MergedDictionaries>
Remove LayoutAndPositioning.xaml from your Application.Resources
Then change:
<Style x:Key="MyElement" TargetType="{Rectangle}">
<Setter Property="Fill" Value="Green" />
<Setter Property="Width" Value="400" />
<Setter Property="Height" Value="200" />
</Style>
To
<Style x:Key="RectStyle" TargetType="{Rectangle}" basedOn="{StaticResource MyElement}">
<Setter Property="Fill" Value="Green" />
<Setter Property="Width" Value="400" />
<Setter Property="Height" Value="200" />
</Style>

Related

Overriding single property setter from ResourceDictionary

I have a style defined in a file called MyStyles.xaml:
<Style TargetType="{x:Type igDP:XamDataGrid}">
<Setter Property="FontSize" Value="10" />
<Setter Property="FontFamily" Value="Arial" />
<EventSetter Event="CellUpdating" Handler="grid_CellUpdating"/>
</Style>
In one of my views, I have a XamDataGrid defined:
<igDP:XamDataGrid>
<igDP:XamDataGrid.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/MyProject.TheViews;component/Views/MyStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="{x:Type igDP:XamDataGrid}" BasedOn="{StaticResource {x:Type igDP:XamDataGrid}}">
<Setter Property="FontSize" Value="70"/>
</Style>
</ResourceDictionary>
</igDP:XamDataGrid.Resources>
Basically, I want to keep everything that is defined in the style for XamDatagrid in MyStyles.xaml except for the font size, which I want to be set to 70.
I can't seem to get it to work. With the above, the font is set to 70 but I lose the other settings that are defined in MyStyles (such as the event handling and font family).
What am I doing wrong here?
(Extracting an answer from comments above.)
For overriding the style, I would suggest the following:
Define 2 styles in MyStyles.xaml: a named one which contains the style, and the unnamed one (this will be the default style) simply based on the named one
<Style x:Key="XamDataGridDefaultStyle" TargetType="{x:Type igDP:XamDataGrid}">
<Setter Property="FontSize" Value="10" />
<Setter Property="FontFamily" Value="Arial" />
<EventSetter Event="CellUpdating" Handler="grid_CellUpdating"/>
</Style>
<Style TargetType="{x:Type igDP:XamDataGrid}"
BasedOn="{StaticResource XamDataGridDefaultStyle}"/>
This will define the needed default style for all the views.
For the resources of the view where the customization is needed, define the following override:
<Style TargetType="{x:Type igDP:XamDataGrid}"
BasedOn="{StaticResource XamDataGridDefaultStyle}">
<Setter Property="FontSize" Value="70"/>
</Style>
You'll perhaps need to reference MyStyles.xaml as merged dictionary in the resources of the customized view for StaticResource to work.

How to style heading labels in WPF/Silverlight/XAML?

This seems simple enough, but I'm having difficulty finding an answer.
I have a WPF window that requires use of headings and sub-headings for different areas. Of course I could include the stlying inline for each element, but I'd really like to keep the styling separate. What's the right way to semantically differentiate the various heading / sub-heading / "normal" label classes so that they can be properly styled in a separate XAML document?
Thanks!
You could just set styles for each of the "label classes" you want in a resource dictionary as follows:
<Style x:Key="heading" TargetType="Label">
<Setter Property="FontSize" Value="24" />
</Style>
<Style x:Key="subHeading" TargetType="Label">
<Setter Property="FontSize" Value="16" />
</Style>
<Style x:Key="normal" TargetType="Label">
<Setter Property="FontSize" Value="12" />
</Style>
And then in your views, you would just have to call the resource and use it as follows:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="Resources/MyResources.xaml">
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Label Style="{StaticResource heading}" Content="This is a heading!" />
</Grid>

How to create a brush that supports both dark and light themes?

I'm working with WP7, and i'd like to create a custom brush (as a local resource) that uses different colors for dark and light themes (for instace, red if the theme is black and blue if it's white).
How do i do it?
Thanks!
The integrated/system brushes do not change their properties based on the theme, a different set of brushes is included based on the current theme. You can see the various versions of this in %programfiles%\Microsoft SDKs\Windows Phone\v7.1\Design
I wrote a custom ResourceDictionary that implements theme support in the exact same way: by loading the appropriate theme dictionary depending on the light/dark theme.
Here is a sample that uses it. It works in the Visual Studio designer as well as Blend, but doesn't support white theme preview in Blend because Blend loads resources in a way that cannot be reproduced.
<Application.Resources>
<custom:ThemeResourceDictionary>
<custom:ThemeResourceDictionary.LightResources>
<ResourceDictionary Source="/ThemeManagement;component/Resources/Light.xaml" />
</custom:ThemeResourceDictionary.LightResources>
<custom:ThemeResourceDictionary.DarkResources>
<ResourceDictionary Source="/ThemeManagement;component/Resources/Dark.xaml" />
</custom:ThemeResourceDictionary.DarkResources>
</custom:ThemeResourceDictionary>
</Application.Resources>
The above code loads in the resources from two different files, but they could just as easily be declared inline like any other ResourceDictionary.
The source for ThemeResourceDictionary is available on my original blog post, but it's also on a different Stack Overflow question in case my blog ever implodes.
You will have to manage brushes you apply to your elements yourself from code. Currently, I have found this to be the only way of adjusting to a different PhoneBackgroundColor.
For example:
In xaml
<TextBlock Text="Some text" Foreground="{Binding VariableTextColor}"/>
In code
var backgroundColor = (System.Windows.Media.Color)Application.Current.Resources["PhoneBackgroundColor"];
if(backgroundColor == "#FF000000") //Dark theme selected
VariableTextColor = RedBrush;
else
VariableTextColor = WhiteBrush;
Another aproach using PhoneDarkThemeVisibility resource:
/// <summary>
/// Determines if the application is running in the dark theme
/// </summary>
private bool IsDarkTheme
{
get
{
if (IsDesignMode)
{
return true;
}
else
{
return (Visibility)Application.Current
.Resources["PhoneDarkThemeVisibility"] == Visibility.Visible;
}
}
}
The approach described by Richard Szalay didn't work in my case either because I needed it in a UserControl or because of something else, however it is really close to the answer. My project is Silverlight Windows Phone 8.1 project and I'm using Visual Studio 2013 with the latest updates. Probably that was the problem. This is what helped in my case
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Application;component/Controls/NumberKeyboard.Dark.xaml" />
<windows:ThemeSelector>
<windows:ThemeSelector.Dark>
<ResourceDictionary Source="/Application;component/Controls/NumberKeyboard.Dark.xaml" />
</windows:ThemeSelector.Dark>
<windows:ThemeSelector.Light>
<ResourceDictionary Source="/Application;component/Controls/NumberKeyboard.Light.xaml" />
</windows:ThemeSelector.Light>
</windows:ThemeSelector>
</ResourceDictionary.MergedDictionaries>
<Style x:Key="KeyboardButton" TargetType="controls:SimpleButton">
<Setter Property="FontSize" Value="45" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Margin" Value="0" />
<Setter Property="Padding" Value="0" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
</Style>
<Style x:Key="NumberButton" TargetType="controls:SimpleButton" BasedOn="{StaticResource KeyboardButton}">
<Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}" />
<Setter Property="Background" Value="{StaticResource ButtonBrush}" />
</Style>
<Style x:Key="ControlButton" TargetType="controls:SimpleButton" BasedOn="{StaticResource KeyboardButton}">
<Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}" />
<Setter Property="Background" Value="{StaticResource ButtonBrush}" />
</Style>
<Style x:Key="ActionButton" TargetType="controls:SimpleButton" BasedOn="{StaticResource KeyboardButton}">
<Setter Property="Foreground" Value="{StaticResource PhoneBackgroundBrush}" />
<Setter Property="Background" Value="{StaticResource PhoneForegroundBrush}" />
</Style>
</ResourceDictionary>
</UserControl.Resources>
The key line is <ResourceDictionary Source="/Application;component/Controls/NumberKeyboard.Dark.xaml" /> right before <windows:ThemeSelector>. That line is necessary for the VS designer to display everything right and ThemeSelector overrides the styles in runtime accordingly to the current theme dark or light.

Setting an Elements.Resource Style using BasedOn within a Resource Dictionary

I have a Resource Dictionary that I am using to define the look-and-feel (style) for my application.
I have just created another Resource Dictionary that contains DataTemplates that I am using on several different screens (and even multiple times within the same screen) to display my business objects.
I would like to change some of the default styles within my DataTemplates so that the controls fit better; however I would like the controls to inherit the same style as the rest of the screen. So, naturally I want to use the BasedOn property for this task.
The problem that I am having is that I'm not sure what to set the BasedOn property to.
For example, in the resource dictionary that contains my styles (called "myStyle.xaml") I have:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:primatives="clr-namespace:System.Windows.Controls.Primitives;assembly=PresentationFramework"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="{x:Type Label}">
<Setter Property="Foreground" Value="#F5F5F5" />
<Setter Property="FontSize" Value="12"></Setter>
<Setter Property="Width" Value="120"></Setter>
<Setter Property="FontFamily" Value="Arial"></Setter>
</Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="FontSize" Value="12"></Setter>
<Setter Property="Width" Value="120"></Setter>
<Setter Property="Height" Value="25"></Setter>
<Setter Property="Background" Value="Black"></Setter>
</Style>
<!-- .... and so on .... -->
</ResourceDictionary>
I am using this resource in the following window:
<Window x:Class="SiteSetupWindow4"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:primatives="clr-namespace:System.Windows.Controls.Primitives;assembly=PresentationFramework"
Title="A Screen">
<Window.Resources>
<ResourceDictionary x:Key="defaultStyleX">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary x:Name="DefaultStyles" Source="Resources/myStyle.xaml" />
<ResourceDictionary x:Name="Templates" Source="Resources/myTemplates.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
Now, I have another Resource Dictionary that contains DataTemplates that I am using within my window. It is called "myTemplates". The style is applied to the DataTemplate as expected; however, I would like to overwrite some aspects of the style within the DataTemplate (Like width for example).
This is what I have tired, however I cannot get the BasedOn property to work...
(myTemplate.xaml)
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DataTemplate x:Key="PanelInfo">
<StackPanel>
<StackPanel.Resources>
<Style TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="Width" Value="120" />
</Style>
<Style TargetType="Label">
<Setter Property="Width" Value="180" />
</Style>
<Style TargetType="ComboBox">
<Setter Property="Width" Value="120" />
</Style>
<StackPanel.Resources>
<StackPanel Orientation="Horizontal">
<Label Content="Type:"></Label>
<ComboBox>
<ComboBoxItem Content="{Binding Path=Type}" IsSelected="True"></ComboBoxItem>
</ComboBox>
<!--...and so on -->
</StackPanel>
</StackPanel>
</ResourceDictionary>
This fails....I have also tried using DynamicResource, but this also fails.
I'm not sure how to get around this.
Any advise would be greatly appreciated!
Thanks,
-Frinny
I was having the same problem with an extended Button Style.
The ResourceKey= is what solved it for me.
This worked:
<Style x:Name="ButtonVisibility"
TargetType="{x:Type Button}"
BasedOn="{StaticResource ResourceKey={x:Type Button}}">
The way you have BasedOn for a type is correct. This will work in theory as long as, at run time, the style that you are basing it on is merged into the tree correctly. Make sure you have the "myStyles.xaml" merged in correctly. You can check this by removing your style you tried to modify and make sure it displays correctly from your style in "myStyles.xaml."
If it isn't there are a lot of places you can go wrong, but it always helps to try merging the styles in the file you are working on, then work up the tree to see where it's missing.
This utility will help you look at what is happing in the tree at run time.
http://blois.us/Snoop/

WPF datagrid styling

I want to style a WPF datagrid and it seems to be really easy . As far as I understand I have to have code such as the following:
<Style x:Key="DataGridColumnHeaderStyle" TargetType="{x:Type Custom:DataGridColumnHeader}" >
<Setter Property="Background" Value="#88800080" />
<Setter Property="Foreground" Value="White" />
</Style>
But my question is ..where do I place this code and how do I let the datagrid know to use the style above ?
Regards,
S
Put it in the resource of the xaml (local or global). The easiest is to put it in the local resource of the current xaml file:
<Page Name="SomeName"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<Style x:Key="DataGridColumnHeaderStyle" TargetType="{x:Type Custom:DataGridColumnHeader}" >
<Setter Property="Background" Value="#88800080" />
<Setter Property="Foreground" Value="White" />
</Style>
</Page.Resources>
<!-- The rest of the xaml -->
</Page>
The best place to put styles is in a resource dictionary, referenced in App.xaml.
Resource dictionary ("StyleResources.xaml" in this example):
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="TextBlockRightAlign" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Right" />
</Style>
<Style x:Key="TextBlockTitle" TargetType="TextBlock">
<Setter Property="FontSize" Value="20" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
</ResourceDictionary>
Referencing the style dictionary in App.xaml:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="StyleResources.xaml"/>
</ResourceDictionary.MergedDictionaries>
<ValueConverters:PriceConverter x:Key="PriceConverter"/>
</ResourceDictionary>
</Application.Resources>
Using the definition in a datagrid (column formatting here, but should work for headers as well):
<data:DataGridTextColumn Header="Charge" Width="100"
Binding="{Binding Charge, Mode=TwoWay, Converter={StaticResource PriceConverter}}"
ElementStyle="{StaticResource TextBlockRightAlign}" />
Note that the element inside the cell is a TextBlock, so you can use a style with a target type of TextBlock.
As for the "Type DataGridColumnHeader was not found": you need a second xml namespace entry since the DataGridColumnHeader is in the System.Windows.Controls.Primitives namespace. You need something like
xmlns:dg="clr-namespace:Microsoft.Windows.Controls.Primitives;assembly=WPFToolkit"
and then reference the new namespace in your style, e.g.
<Style x:Key="DataGridColumnHeaderStyle" TargetType="{x:Type dg:DataGridColumnHeader}" >
Styles usually go:
<UserControl.Resources>
<Style x:Key="DataGridColumnHeaderStyle" TargetType="{x:Type Custom:DataGridColumnHeader}" >
<Setter Property="Background" Value="#88800080" />
<Setter Property="Foreground" Value="White" />
</Style>
</UserControl.Resources>
Use the appropriate container if this isn't within a UserControl you may use "Window" or whatever container you're in.
Also you need to reference it in your datagrid with:
<Custom:DataGrid ColumnHeaderStyle="{StaticResource DataGridColumnHeaderStyle}"/>

Resources