WPF - Use static resource in multiple windows [duplicate] - wpf

This question already has answers here:
How do I use global resources in WPF?
(4 answers)
Closed 5 months ago.
I have an application with many Windows, and I want to use the same templates and styles in all of these windows.
Warning: This is NOT a "WPF Application", it's a "class library" using WPF windows. I do not have an "App.xaml" file!!!
What is the easiest way to do that in WPF?
Currently, I have this in a Window, working fine:
<Window.Resources>
<ControlTemplate x:Key="ErrorTemplate">
<Grid ToolTip="{Binding Path=/ErrorContent}">
....
</Grid>
</ControlTemplate>
<Style TargetType="Control" x:Key="ErrorStyle">
<Setter Property="Validation.ErrorTemplate" Value="{x:Null}"/>
<Style.Triggers>
...
</Style.Triggers>
</Style>
</Window.Resources>
And I use it as
<TextBox Style="{StaticResource ErrorStyle}" .../>
But this is clearly declared in a single Window. How do I declare it in a way that it could be used by many windows (considering I do not have an App.xaml file)

Do it in the App.Xaml, will be available for all items in the application
Alternatively you can create ResourceDictionaries and merge those in the App.Xaml or anywhere you need them
DOCS:
Application.Resources
https://learn.microsoft.com/en-us/dotnet/desktop/wpf/systems/xaml-resources-how-to-use-application?view=netdesktop-6.0
Merged Dictionaries
https://learn.microsoft.com/en-us/dotnet/desktop/wpf/systems/xaml-resources-merged-dictionaries?view=netdesktop-6.0

Related

What is the exact effect of declaring a resource?

When I create a style using XAML:
<Style x:Key="tbxWithValidation" TargetType="TextBox">
<Style.Setters>
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource errorTemplate}"/>
...
</Style.Setters>
</Style>
what does mean this declaration? Do I create a class or an instance?
I assume I create an instance of class Style, but I wonder in this case if this instance will be used each time I use the resource.
In other words, does Style="{StaticResource tbxWithValidation}" reuse the same instance, or does it create a new instance so that each control has its own style instance?
I'm asking this question, because while this may be not important for a style (maybe controls can share the same style instance without problems, not sure...), it seems to me there would be a problem with declaring a control template and using it multiple times (this template is used in the style above):
<ControlTemplate x:Key="errorTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Margin="0,0,5,0" Foreground="Red" FontWeight="Bold" Text="!"/>
<AdornedElementPlaceholder/>
</StackPanel>
</ControlTemplate>
Can you help me clarifying this (I'm learning WPF)?
<Style x:Key="TbxWithValidation" TargetType="TextBox">
<Style.Setters>
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource ErrorTemplate}"/>
...
</Style.Setters>
</Style>
This declaration instructs the XAML parser create an instance of the class Style.
In this case, the Style (or the resource in general) and all nested ResourceDictionary or referenced objects (and therefore also the the ErrorTemplate) is 'reused' for every reference to it.
This is because of the x:Shared attribute. This attribute is implicitly set and true by default. When true this attribute instructs the XAML parser to reuse the instance of the object. You can set it explicitly to false:
<Style x:Shared="False" x:Key="TbxWithValidation" TargetType="TextBox">
...
</Style>
By design each instance of an object is allowed to exist only once in the object graph. 'Reuse' or sharing (x:Shared="True") instructs the XAML parser to internally create a copy of the shared instances, so that the XAML parser can insert them in various places in the element tree. But since this are copies they are actually referencing the same shared instance.
An exception is made to all objects that extend UIElement. Instances of those objects can only exist once in the object graph: that's why elements like System.Windows.Controls.Image will magically disappear when used in multiple positions in the graph e.g. like when a single icon is used with multiple Button elements. In this case only one icon at time would be visible.
Instances of UIElement can not be shared (referenced by more than one resource instance) - they are unique. This means the author has to create the required number of instances explicitly.
This is why e.g. when creating a Button instance in C# (code-behind) and then add it to e.g. two different Grid elements the following exception is thrown:
Specified element is already the logical child of another element.
So, this means a shared resource like a Style is only critical when it declares UIElement objects (like Image) that are referenced in more than one resource:
<Style x:Key="SaveButton" TargetType="ButtonBase">
<Setter Property="Content">
<Setter.Value>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Save"/>
<Image Source="Resources\icons\save.png" />
</StackPanel>
</Setter.Value>
</Setter>
</Style>
Here the XAML parser will reuse the same instance of Style (x:Shared is true by default). To do so it creates copies. But the Image can't be copied: it will only appear on one Button.
To solve this you would have to mark the Style as not shared:
<Style x:Shared="False" x:Key="SaveButton" TargetType="ButtonBase">
<Setter Property="Content">
<Setter.Value>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Save"/>
<Image Source="Resources\icons\save.png" />
</StackPanel>
</Setter.Value>
</Setter>
</Style>
Now the XAML parser must create a new instance of the Style for each reference.
Something somehow similar applies to ControlTemplate. It is also shared by default but not its content.
For each reference to the ControlTemplate, new instances of the content elements are created.
Therefore declaring the content of the Button as ControlTemplate or ContentTemplate (instead of setting the Button.Content directly via a Style like above), would also solve the problem described above.
StaticResource does not mean that the resource is static. It's a markup extension that instructs the XAML parser to lookup the resource tree to find a predefined instance. Same does DynamicResource. The only difference is that StaticResource instructs the XAML parser to resolve the reference to a resource at compile time, whereas DynamicResource let's the XAML parser create an expression instead, that will be evaluated at run time (deferred). DynamicResource therefore resolves the resource at run time.

Defining WPF Window style in class library

Currently I am developing some WPF class library, which will have several WPF Windows and trying to create my own window ControlTemplate for these Windows to make more nice design of these windows (inspired by this article: Reusing Control Templates in Resource Dictionaries).
Problem is, then it's a WPF class library not an application assembly, where i can use app.xaml and to define my resource dictionary reference & etc...
Using code below i getting an error: StaticResource reference 'MyWindowStyle' was not found
<Window x:Class="SomeERP.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"
Style="{StaticResource MyWindowStyle}">
<Window.Resources>
<!-- My Window Style -->
<Style x:Key="MyWindowStyle" TargetType="Window">
<Setter Property="Background" Value="Transparent" />
<Setter Property="WindowStyle" Value="None" />
<Setter Property="AllowsTransparency" Value="True" />
<Setter Property="Opacity" Value="0.95" />
<Setter Property="Template" Value="{StaticResource MyWindowTemplate}" />
</Style>
<!-- Window Template -->
<ControlTemplate x:Key="MyWindowTemplate" TargetType="{x:Type Window}">
<Grid>
</Grid>
</ControlTemplate>
</Window.Resources>
</Window>
I suspect i get this error because in my case it's not predeclared before Window declaration as in application's case in app.xaml which i don't have in class libary. I am pretty new in WPF and just starting to use WPF design possibilities.
If you need the style only once, the solution is pretty simple: Just define the style in-place
<Window.Style>
<!-- My Window Style -->
<Style TargetType="Window">
...
</Style>
</Window.Style>
However, if you need the style in more than one window, it is reasonable to define the style in a resource dictionary. Then you can integrate the resource dictionary in the window's resources and set the style accordingly:
<Window.Resources>
<!-- My Window Style -->
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary1.xaml"/>
<!-- path to the resource dictionary -->
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resource>
<Window.Style>
<StaticResource ResourceKey="MyWindowStyle"/>
</Window.Style>
Looks like i've found solution to my problem in this post: Assembly-wide / root-level styles in WPF class library and according to this post What's the difference between StaticResource and DynamicResource in WPF?
A StaticResource will be resolved and assigned to the property during the loading of the XAML which occurs before the application is actually run. It will only be assigned once and any changes to resource dictionary ignored.
A DynamicResource assigns an Expression object to the property during loading but does not actually lookup the resource until runtime when the Expression object is asked for the value. This defers looking up the resource until it is needed at runtime. A good example would be a forward reference to a resource defined later on in the XAML. Another example is a resource that will not even exist until runtime. It will update the target if the source resource dictionary is changed.
That was what i needed, as i have class library, i don't have app.xaml and can't predeclare resources for Window. I just need to use DynamicResource rather than StaticResource to get it working.
Thanks for attention :)
Just add the external assembly:
<Application.Resources>
<ResourceDictionary>
Source="/MyAssemblyName;component/MyResources.xaml"
</ResourceDictionary>
</Application.Resources>

Where is DataGridHeaderBorder for WPF DataGrid? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
WPF4 DataGridHeaderBorder in a xaml Style
I found some styles for WPF DataGrid online and all of them are for pre-release DataGrid. Now, I'm using .NET4 DataGrid, I got a compile error complaining DataGridHeaderBorder cannot be found. Based on Microsoft, it is in Microsoft.Windows.Themes namespace. No matter what I try, I can't make it work.
This seems to be bug in .NET4 according to here. There is also a workaround. Just add a namespace reference like this:
xmlns:dg="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero">
You may have to manually add a reference to PresentationFramework.Aero in your project.
you can also try this.. (in this case to change the foreground of the hearder)
<Style x:Key="Consulta_Grilla_HeaderStyle" TargetType="{x:Type DataGridColumnHeader}" >
<Style.Resources>
<Style TargetType="{x:Type Grid}" >
<Setter Property="TextBlock.Foreground" Value="Yellow"/>
</Style>
</Style.Resources>
</Style>

Do custom controls in Silverlight 4 need to be in separate DLL's?

I am creating a number of custom controls for a Silverlight 4 project. I have successfully created one control and am wondering if I can define more in the same project and then have all the controls bundled into one .DLL.
Right now, I have the standard files for the first control:
/Resources/icon.png
/themes/generic.xaml
/CustomControl1.cs
/CustomControl1EventArgs
I am thinking it's not possible, as there can only be one "generic.xaml".
Thanks,
Scott
Yes you can create multiple controls in the same project, you simply have to place the all the default templates in a single /themes/generic.xaml file. Each controls template is identified by the TargetType. So your generic.xaml file would look something like:-
<ResourceDictionary ... blah namespace stuff ...>
<Style TargetType="local:CustomControl1">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:CustomControl1">
<!-- Template for Custom control 1 -->
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="local:CustomControl2">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:CustomControl2">
<!-- Template for Custom control 2 -->
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- and so on -->
</ResourceDictionary>
The Silverlight Toolkit chapies do have a neat tool which allows you to place each control template in its own file. The tool dynamically constructs the generic.xaml from the contents of all these files. I really wish they'd blog about it so we could find out how to use it ourselves. Hello any of you Msofties lurky listening in?

Silverlight generic.xaml

Can I use generic.xaml in Silverlight to set the style of all TextBlock in the application?
<ResourceDictionary xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="TextBlock">
<Setter Property="Foreground"
Value="White" />
<Setter Property="FontSize"
Value="24" />
</Style>
</ResourceDictionary>
I was expecting this to work but it doesn't :-(
Whats the simplest way to apply styles across a whole application??
Thanks,
Mark
EDIT
Thanks for your response. I'm not getting an error, the styles just aren't being applied. All the examples that I found on the internet (including the ones you have listed) are all for styling custom controls. This I can do, but I'd like to just style the default controls:
<TextBlock Text="Style me!!" Grid.Row="2" />
Do I need to add reference to the generic.xaml from page.xaml??
Do I need to name and reference the generic.xaml style as a resource??
Thanks again, Mark
In Silverlight 4, you can use implicit styling!
Setting Styles generically/automatically by setting the TargetType and omitting a ResourceKey only works in WPF, not Silverlight.
If you want to have a Style available throughout your application you can add it to the Resources collection in your App.xaml, but to use it it will need a x:Key and you will have to apply it individually as a StaticResource binding to each instance of your target type that you want to use it.
I do believe this is in Silverlight 3. But the other guys are right, you need to style each one by hand in Silverlight 2.
Note that you could also use the ImplicitStyleManager from the Silverlight Toolkit to do this:
http://www.codeplex.com/Silverlight/Wiki/View.aspx?title=Silverlight%20Toolkit%20Overview%20Part%203&referringTitle=Home
Apply the style to the top level control in your hierarchy and it will propagate down to all child controls.
What exactly doesn't work about it? Do you get an error, or do your text boxes just not get themed?
Your method is the correct way to theme controls, so just work at ironing out the problems you're having with it.
This is a good tutorial, as is this, though note that in Silverlight 2 you need to put the generic file in
themes\generic.xaml
which differs from many tutorials you might find (including the ones given above
Edit: Another tutorial here
Try something along the lines of.
<UserControl.Resources>
<Style TargetType="TextBlock" x:Name="tbStyle">
<Setter Property="Foreground" Value="White" />
<Setter Property="FontSize" Value="24" />
</Style>
</UserControl.Resources>
Then when using your TextBlock.
<TextBlock Style="{StaticResource tbStyle}" />

Resources