How to apply DependencyProperty values to child user controls? - wpf

I have multiple instances of the same custom user control in a StackPanel. Each instance needs the same DependencyProperty "ControlWidth". Instead of setting each user control with the same property, I want to set it only once in the parent StackPanel
<StackPanel>
<propwin:PropertyEditControl Label="First" ControlWidth="180" />
<propwin:PropertyEditControl Label="First" ControlWidth="180" />
...
</StackPanel>
I used to do this with Style properties
<StackPanel>
<StackPanel.Resources>
<Style TargetType="{x:Type propwin:PropertyEditControl}">
<Setter Property="ControlWidth" Value="180" />
</Style>
</StackPanel.Resources>
<propwin:PropertyEditControl Label="First" />
<propwin:PropertyEditControl Label="Second" />
...
</StackPanel>
Update:
Thanks to Anatoliy, who mention that my code (the one I showed here) should work. I now tracked down the problem. Inside my PropertyEditControl.xaml I define a validation style:
<UserControl x:Class="MyModule.PropertyEditControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MyModule">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/MyModule;component/UI/ResourceDictionaries/ResourceLibrary.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style TargetType="local:PropertyEditControl">
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource ValidationErrorTemplate}" />
</Style>
<Style x:Key="PropertyNameStyle" TargetType="DockPanel">
<Setter Property="Width" Value="{Binding ControlWidth}" />
<Setter Property="DockPanel.Dock" Value="Left" />
</Style>
...
If I remove the <Style TargetType="local:PropertyEditControl"> style it works!

It turned out that my original approach should have worked. The reason why it hasn't was a misplaced Style Resource inside the user control. Anyway, the correct answer to my initial question is: To set a DependencyProperty value for multiple controls only once, you have to set it inside the container style definition:
<StackPanel>
<StackPanel.Resources>
<Style TargetType="{x:Type propwin:PropertyEditControl}">
<Setter Property="ControlWidth" Value="180" />
</Style>
</StackPanel.Resources>
<propwin:PropertyEditControl Label="First" />
<propwin:PropertyEditControl Label="Second" />
...
</StackPanel>

Related

Overriding application wide style

I want to define a global style for textblock in the application but I also want to be able to override this default style. I always thought that the local override of style has more priority than the global one but it doesn't seems to be the case?
In the following example, the Button with content "Test" will have a "Red" foreground when I expect it to be "Aqua". If I remove the global style in Application.Resources, than it will works. Did I'm missing something?
App.xaml
<Application x:Class="ContextMenuTest.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="Red" />
</Style>
</Application.Resources>
MainWindow.xaml
<Window x:Class="ContextMenuTest.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 MenuItem}" x:Key="DefaultMenuItemStyle">
<Setter Property="Foreground" Value="DarkGreen" />
</Style>
<Style TargetType="{x:Type Button}" x:Key="DefaultButtonStyle">
<Setter Property="Foreground" Value="DarkGreen" />
</Style>
</Window.Resources>
<Grid Background="Black">
<Grid.ContextMenu>
<ContextMenu>
<MenuItem Header="Menu 1" Style="{StaticResource DefaultMenuItemStyle}" />
<MenuItem Header="Menu 2" Style="{StaticResource DefaultMenuItemStyle}" />
<MenuItem Header="Menu 3" Style="{StaticResource DefaultMenuItemStyle}" />
<MenuItem Header="Menu 4" Style="{StaticResource DefaultMenuItemStyle}" />
<MenuItem Header="Menu 5" Style="{StaticResource DefaultMenuItemStyle}" />
</ContextMenu>
</Grid.ContextMenu>
<Button Content="Test" Style="{StaticResource DefaultButtonStyle}" Foreground="Aqua" />
</Grid>
Implicit TextBlock defined in App.xaml will not be overrided by other TextBlock styles. It's therefore recommended that you move your default TextBlock style to for example <Window.Resources>.
Please refer to the following links for more information about this.
Implicit styles in Application.Resources vs Window.Resources?
Over ride the Property setting in App.xaml: https://social.msdn.microsoft.com/Forums/vstudio/en-US/f6822a5e-09c7-489b-b85d-833f1f9356dc/over-ride-the-property-setting-in-appxaml?forum=wpf
Or simply don't define any implicit TextBlock style. Define a default Style for each Control instead.
Your problem is in defining your application level resources for the TextBlock instead of the Button. Most of WPF controls use TextBlocks as default way to display text content, so by trying to override your Button Foreground, you are doing it, but then it gets overriden again by TextBlock default style.
Change your App.xaml to this and you will get the result you wanted to achieve:
<Application.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="Red" />
</Style>
</Application.Resources>

ComponentOne DataGridColumnHeaderPresenter Style Inheritance does not work (Silverlight)

I'm using ComponentOne C1DataGrid control for Silverlight. Standard StyleInheritance does not work.
Here is the code:
<UserControl x:Class="TestSLStyles.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:c1="http://schemas.componentone.com/winfx/2006/xaml"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"
xmlns:sys="clr-namespace:System.Collections.ObjectModel;assembly=mscorlib"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<UserControl.Resources>
<Style x:Key="BaseStyle" TargetType="Button">
<Setter Property="Background" Value="Yellow" />
</Style>
<Style x:Key="InheritedStyle" TargetType="Button" BasedOn="{StaticResource BaseStyle}">
<Setter Property="Foreground" Value="Red" />
</Style>
<Style x:Key="dchpBase" x:Name="dchpBase" TargetType="c1:DataGridColumnHeaderPresenter">
<Setter Property="Background" Value="Yellow"/>
</Style>
<Style x:Key="dchpInherited" x:Name="dchpInherited" TargetType="c1:DataGridColumnHeaderPresenter" BasedOn="{StaticResource dchpBase}">
<Setter Property="Foreground" Value="Red"/>
</Style>
</UserControl.Resources>
<StackPanel>
<Button Content="HelloWorld" x:Name="btn1" />
<Button Content="HelloWorld" x:Name="btn2" Style="{StaticResource BaseStyle}" />
<Button Content="HelloWorld" x:Name="btn3" Style="{StaticResource InheritedStyle}" />
<c1:C1DataGrid x:Name="grd1">
<c1:C1DataGrid.Columns>
<c1:DataGridTextColumn Header="Column1" x:Name="cln1" />
<c1:DataGridTextColumn Header="Column2" x:Name="cln2" HeaderStyle="{StaticResource dchpBase}" />
<c1:DataGridTextColumn Header="Column3" x:Name="cln3" HeaderStyle="{StaticResource dchpInherited}" />
</c1:C1DataGrid.Columns>
</c1:C1DataGrid>
</StackPanel>
</UserControl>
As you can see on screen below, this code works fine for Button's style inheritance, but not for grid's column header:
The last column supposed to be with Yellow background and Red foreground, but base style is not inherited. Tested on Silverlight 5 and ComponentOne version 4.0.20103.86
Question was posted to ComponentOne's forum as well
The issue was fixed with the C1Silverlight Build : 5.0.20133.381
The latest build can be downloaded from the following link :http://prerelease.componentone.com/hotfixes/silverlight/C1Silverlight_5.0.20141.399_RC1.msi

Extend UserControl.Resources

I want to provide a simple default style for a UserControl, but still be able to extend or override the style when using the control. Below is a sample scenario with a simple UserControl and a Window containing the control. The intention is for the style for the Button provided in the Window to override the default style defined in the UserControl.
UserControl
<UserControl x:Class="Sample.TestControl" ... >
<UserControl.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Margin" Value="2" />
<Setter Property="Foreground" Value="Orange" />
</Style>
<Style TargetType="{x:Type StackPanel}">
<Setter Property="Background" Value="Black" />
</Style>
</UserControl.Resources>
<StackPanel>
<Button Content="Press Me" />
<Button Content="Touch Me" />
<Button Content="Tap Me" />
</StackPanel>
</UserControl>
Window
<Window x:Class="Sample.MainWindow" ... >
<Grid>
<local:TestControl>
<local:TestControl.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Margin" Value="2" />
<Setter Property="Foreground" Value="Green" />
</Style>
</local:TestControl.Resources>
</local:TestControl>
</Grid>
</Window>
Problem
The above code will result in:
Exception: Set property 'System.Windows.ResourceDictionary.DeferrableContent' threw an exception.
InnerException: Item has already been added.
The above code is trying to submit two styles with the same key into the same ResourceDictionary, so obviously it wasn't going to work. My guess that I am not going to be able to provide a default style for the buttons...
Insufficient Workaround: Override default ResourceDictionary
<Window x:Class="Sample.MainWindow" ... >
<Grid>
<local:TestControl>
<local:TestControl.Resources>
<ResourceDictionary>
<Style TargetType="{x:Type Button}">
<Setter Property="Margin" Value="2" />
<Setter Property="Foreground" Value="Green" />
</Style>
</ResourceDictionary>
</local:TestControl.Resources>
</local:TestControl>
</Grid>
</Window>
By putting the custom Button style in a ResouceDictionary, I can override the default one. However, its not just overriding the Button style, its overriding all of the resources. So, the StackPanel will no longer have a black background. (obviously I could add that to the overriding style as well, but thats not practical on a bigger scale.)

WPF UserControl Style -- How do I set the style from the parent if the control is in an external assembly?

Basically I have the following structure:
<Window ...
xmlns:my="http://schemas.company.com/WPF/Controls"
>
<Window.Resources>
<Style x:Key="MyStyle1" TargetType={x:Type TextBlock}>
...
</Style>
</Window.Resources>
<Grid x:Name="LayoutRoot">
<my:MyUserControl1 />
<my:MyUserControl1 />
<my:MyUserControl2 />
<my:MyUserControl2 />
</Grid>
</Window>
<UserControl ...
>
<TextBlock Style={ ?? What Goes Here ??} />
</UserControl>
How do I apply the style declared in the Window resources so that it goes to the UserControl that is being pulled from an external assembly?
If you want the Style to be applied to all TextBlocks, including the ones in MyUserControl, just leave the x:Key out and it will be applied implictly
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="Green"/>
</Style>
If you want it to be set explicitly you can use DynamicResource in the UserControls
<Window.Resources>
<Style x:Key="MyStyle1" TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="Green"/>
</Style>
</Window.Resources>
<StackPanel>
<my:UserControl1 />
<my:UserControl1 />
<my:UserControl1 />
<my:UserControl1 />
</StackPanel>
<UserControl ...>
<TextBlock Style="{DynamicResource MyStyle1}" Text="TextBlock"/>
</UserControl>
Try this :
<TextBlock Style={ StaticResource MyStyle1} />
I hope this help you Introduction to Styles in WPF

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