How to resuse the same instance of a style - wpf

I’m just testing some XAML stuff, and I am wondering why a style which comes from a resource dictionary is created multiple times when used inside a data template for listbox.
Let me give you an example
<UserControl x:Class="WpfApplication1.UserControl1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ListBox ItemTemplate="{DynamicResource foo}" ItemsSource="{Binding Names}"/>
</UserControl>
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wpfApplication1="clr-namespace:WpfApplication1">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary1.xaml" />
</ResourceDictionary.MergedDictionaries>
<DataTemplate x:Key="foo">
<TextBlock Style="{StaticResource TextBlockStyle}" Text="{Binding}" Loaded="TextBlock_Loaded"/>
</DataTemplate>
</ResourceDictionary>
</Window.Resources>
<wpfApplication1:UserControl1 />
</Window>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="TextBlockStyle" TargetType="TextBlock">
<Setter Property="Background" Value="Red" />
<Setter Property="Foreground" Value="Pink" />
</Style>
</ResourceDictionary>
Now I’ve done a simple test in code behind to see whether the textblocks get the same style,
and it is surprising that each one of them gets a new instance of the same style, so if I had 50 records then I would have 50 instances of the same style.
Is that how people do it, or is there a pattern to reuse the same instance as many times as needed?
Thanks for looking :)

Related

Style an activation indicator from material design

I want to style an activation indicator from material design in WPF. I want the styling to happen in an external styling.xaml file, so the textbox I'm using can be binded to that style.
The textbox:
<TextBox materialDesign:HintAssist.Hint="Search:" Grid.Column="1" Margin="35 8 20 5"
Width="200" Style="{"STYLE style"}/>
You could set it as a StaticResource:
File: styling.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:YourNamespace">
<Style TargetType="{x:Type TextBox}" x:key="YourCustomTextBoxStyle">
<Setter Property="Margin" Value="35 8 20 5"/>
....
</Style>
</ResourceDictionary>
In your View (or Application) add a reference to the styling ResourceDictionary and use the style as a static resource:
<UserControl
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:YourNamespace.Wpf"
x:Class="YourView" mc:Ignorable="d">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/YourNamespace;component/Themes/styling.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<TextBox materialDesign:HintAssist.Hint="Search:" Grid.Column="1" Width="200" Style="{StaticResource YourCustomTextBoxStyle}/>
</UserControl>

Resource "x" could not be resolved WPF

Im new at WPF and im using some DevExpress controls
Im trying to implement an style to some buttons but always shows the error that the Resource cannot be resolved.
MainWindow:
<dx:DXWindow
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dxb="http://schemas.devexpress.com/winfx/2008/xaml/bars"
xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors" x:Class="LicenceManagerWPF.MainWindow"
xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core" dx:ThemeManager.ThemeName="Office2016"
Title="MainWindow" Height="746.218" Width="1139.154"
WindowStartupLocation="CenterScreen">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="80"/>
</Grid.RowDefinitions>
<StackPanel x:Name="Stack_Top" Orientation="Horizontal" Grid.Row="1" >
<dx:SimpleButton x:Name="btnRefresh" Style="{StaticResource ResourceKey=CustomStyles}" Width="55" ToolTip="Refresh" Margin="10,10,10,10" Glyph="{dx:DXImage Image=Refresh_32x32.png}" Content="Resfresh" />
<dx:SimpleButton x:Name="btndNew" Width="55" ToolTip="New Customer" Margin="10" Glyph="{dx:DXImage Image=NewContact_32x32.png}" Content="New Customer" />
<dx:SimpleButton x:Name="btnDelete" ToolTip="Delete Customer" Width="55" Margin="10" Content="Delete" Glyph="{dx:DXImage Image=Cancel_32x32.png}"/>
</StackPanel>
</Grid>
This is the App.xaml
<Application x:Class="LicenceManagerWPF.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml"
Startup="OnAppStartup_UpdateThemeName">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary x:Name="CustomStyles" Source="StyleResource.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
This is my Styles file
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:LicenceManagerWPF"
xmlns:dxb="http://schemas.devexpress.com/winfx/2008/xaml/bars"
xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors" x:Class="LicenceManagerWPF.MainWindow"
xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core">
<Style x:Name="HeaderButtons" TargetType="dx:SimpleButton">
<Setter Property="Margin" Value="10"/>
<Setter Property="Width" Value="55"/>
</Style>
I was searching and everything looks like fine but i dont get it why it cannot be resolved.
Regards
There is no need to name ResourceDictionary , just provide its Source:
<ResourceDictionary Source="StyleResource.xaml"/>
ResourceDictionary items should have x:Key. In case of a Style if there is no explicit key, TargetType will be used as a key. It is a way to create default styles.
If you want named style, then set x:Key
<Style x:Key="HeaderButtons" TargetType="dx:SimpleButton">
<Setter Property="Margin" Value="10"/>
<Setter Property="Width" Value="55"/>
</Style>
And finally StaticResource extension references resources by resource key, not by names:
Style="{StaticResource HeaderButtons}"
Also: when you set a Style for a button, Margin and Width settings (Width="55" Margin="10,10,10,10") becomes redundant. They can be used to override style setting, but in this case they are the same so why write them?

Datagrid in Silverlight 4

I have a datagrid in silverlight 4 like below
<data:DataGrid x:Name="Test">
<data:dataGrid.Columns>
<data:DataGridColumnTextColumn Header="File Name" HeaderStyle="{StaticResource MyResource}"/>
</data:DataGrid.Columns>
</data:DataGrid>
Here's the Resource file property
<Style TargetType ="System_Windows_Controls_Primitives:DataGridColumnHeader" x:Name="MyResource">
<Setter Property="Foreground" Value="#FF"/>
</style>
the xmlns I use is xmlns:data = "clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" - This was working in Silverlight 3 but not in Silverlight 4
The issue is that the program is throwing an error that the given key is not present in the dictionary which is not true since it is there in the resource file. It can clearly get other keys for other properties like Header Name etc but not the HeaderStyle . Can someone tell me what I am doing wrong here.
Thanks
Simply creating a dictionary does not make your application incorporate it. Did you reference it in your App.xaml?
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SilverlightApplication5.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary1.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
[Edit]
I'm not sure then. Are the namespaces correct?
The below example works for me (note namespace names differ from your example):
MainPage.xaml:
<UserControl
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:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
x:Class="SilverlightApplication5.MainPage"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<sdk:DataGrid HorizontalAlignment="Left" Height="100" Margin="120,126,0,0" VerticalAlignment="Top" Width="120">
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn Header="File Name" HeaderStyle="{StaticResource MyResource}" />
</sdk:DataGrid.Columns>
</sdk:DataGrid>
</Grid>
Dictionary1.xaml:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">
<Style TargetType="sdk:DataGridColumnHeader" x:Name="MyResource">
<Setter Property="Foreground" Value="#FFFFFFFF"/>
</Style>
App.xaml is exactly as posted above.
Ok, I think I spotted the error:
You mistakenly have used the attribute x:Name and not x:Key, but you have to set the x:Key attribute for static resources. Yes, I have seen the x:Name actually working for resources before (seems Silverlight 3 wasn't too strict about it) and I think you can't do this for SL4 anymore.
<Style TargetType="DataGridColumnHeader" x:Name="MyResource">
versus
<Style TargetType="DataGridColumnHeader" x:Key="MyResource">

wpf merge multiple styles into one style

I have a UserControl that consists of a listview it looks like:
<UserControl
....
<UserControl.Resources>
<Style TargetType="Thumb">
<!-- Style Content -->
</Style>
<Style TargetType="GridViewColumnHeader">
<!-- Style Content -->
</Style>
<Style TargetType="{x:Type ScrollBar}">
<!-- Style Content -->
</Style>
<Style TargetType="{x:Type ScrollViewer}">
<!-- Style Content -->
</Style>
<Style TargetType="{x:Type ListViewItem}">
<!-- Style Content -->
</Style>
</UserControl.Resources>
<ListView Name="ListView1" >
<!-- ListViewContent -->
</Style>
</UserControl>
I have 3 of those userControls where the only thing that is different between them is the styles in <UserControl.Resources>. It makes no scene to have to create multiple controls that have the same functionality just because I need a different look and feel. What I want to do now is combine all the styles in <UserControl.Resources> into one style. If I manage to group all those styles into one I would be able to remove the 3 controls and change the style as:
<ListView Style={DynamicResource style1} ...
Currently if I do
<UserControl.Resources>
<Style x:Key="style1">
<!-- Place all styles in here -->
</Style>
</UserControl.Resources>
It does not work.
Edit
Thanks to iltzortz answer I now have:
Dictionary1.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="Grid">
<Setter Property="Background" Value="Green"></Setter>
</Style>
<SolidColorBrush x:Key="Foo" Color="Red"></SolidColorBrush>
</ResourceDictionary>
Dictionary2.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="Grid">
<Setter Property="Background" Value="Black"></Setter>
</Style>
<SolidColorBrush x:Key="Foo" Color="Orange"></SolidColorBrush>
</ResourceDictionary>
MyUserControl:
<UserControl x:Class="WpfApplication1.UserControl1"
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"
mc:Ignorable="d"
d:DesignHeight="97" d:DesignWidth="91">
<UserControl.Resources>
<ResourceDictionary Source="Dictionary1.xaml" ></ResourceDictionary>
</UserControl.Resources>
<Grid >
<Ellipse Fill="{DynamicResource Foo}" />
</Grid>
</UserControl>
And I change resource dictionaries dynamically like this: switching wpf resource dictionaries at runtime
Add a resource dictionary to your application named e.g. common.xaml
and put your common styles there
then you can reuse it with:
<UserControl.Resources>
<ResourceDictionary Source="common.xaml"/>
</UserControl.Resources>
You can create 3 resource dictionaries and merge them at runtime. In my example code I used two resource dictionaries.
Example:
Dictionary1.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="btnStyle" TargetType="Button">
<Setter Property="Margin" Value="0,10,0,0" />
</Style>
</ResourceDictionary>
Dictionary2.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="btnStyle" TargetType="Button">
<Setter Property="Margin" Value="50,50,0,0" />
</Style>
</ResourceDictionary>
In the start of application you can set default style in App.xaml file:
<Application x:Class="Example.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Dictionary1.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
If you want to change style, you can merge resource dictionaries:
ResourceDictionary dict = new ResourceDictionary();
dict.Source = new Uri("\\Dictionary2.xaml", UriKind.Relative);
this.Resources.MergedDictionaries.Add(dict);
And now binding looks like this:
<Button Style="{DynamicResource btnStyle}" Content="Click me!" />
Now if you invoke code to merge resource dictionaries, button style will be automatically changed.

WPF : Extend Theme's style - StackOverflowException

I want every button to have 5 points margin, in addition to Royale theme style.
Window1.xaml:
<Window x:Class="_styles.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/PresentationFramework.Royale;component/themes/royale.normalcolor.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Margin" Value="5"/>
</Style>
</ResourceDictionary>
</Window.Resources>
<StackPanel>
<Button Content="Button A"/>
<Button Content="Button B"/>
</StackPanel>
</Window>
It compiles but I get:
An unhandled exception of type 'System.StackOverflowException' occurred in PresentationFramework.dll
public Window1() {
InitializeComponent(); // <-- getting exception here
}
There are no exception details because:
{Cannot evaluate expression because the current thread is in a stack overflow state.}
This seems to be a circular reference between your style and the one defined in PresentationFramework.Royale. A workaroud would be to place resources at different levels:
<Window x:Class="_styles.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/PresentationFramework.Royale;component/themes/royale.normalcolor.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<StackPanel>
<StackPanel.Resources>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Margin" Value="5"/>
</Style>
</StackPanel.Resources>
<Button Content="Button A"/>
</StackPanel>
</Window>
I would remove the BasedOn attribute - it's not necessary. Think of it this way, merging the Royale theme will apply the button theme, and you just want to change the margin - styles are additive in nature, so it will combine the Royale theme and your own button theme without specifying the BasedOn attribute - does that make sense?
Cheers!
Please see this question and my answer for another solution that doesn't require you to specify a resource dictionary in every window and allows you to resolve the BasedOn style dynamically.

Resources