Why doesn't my WPF style work? - wpf

Trying to put a style in app.xaml. My app.xaml reads:
<Application x:Class="TestApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Resources>
<Style x:Key="TestStyle" TargetType="Button">
<Setter Property="Background" Value="Red"/>
</Style>
</Application.Resources>
</Application>
My XAML for the button is as follows:
<Button Content="Click Me!" Style="{StaticResource TestStyle}" />
In the designer all looks OK but when I run the code it fails with:
Provide value on 'System.Windows.StaticResourceExtension' threw an exception.
I've stared at it for ages but can't spot the problem!
EDIT
It seems to be something to do with the application overall. If I copy my code into another fresh project it works fine. The only difference is that the window is loaded using the "StartupUri="MainWindow.xaml". In the one that doesn't work I load the window up during the App.Startup as follows:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
new TestWindow().Show();
}
SOLUTION
Found the problem - I was missing an InitializeComponent call. Now the styles work in the final product but not in the designer. I'm going to ask a separate question about it.

Workaround: Just define a Name for the Application object:
< Application x:Name="App" ...
It worked for me!

Based on your edit: if you've got StartupUri="MainWindow.xaml" in the original xaml, but (as your code snippet suggests) you actually have a file called TestWindow.xaml, this could be the problem! Try changing it to StartupUri="TestWindow.xaml" in the original project....

You can make a try with {DynamicResource TestStyle}. Maybe TestStyle is not yet created when you apply it to the Button.

try this...
<Style x:Key="TestStyle" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Red"/>
</Style>
usually, in WPF, you want your TargetType to be of the form {x:Type ...}
in silverlight, you would use TargetType="Button"

Related

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>

Using Resource Dictionaries in a Class Library

I'm using this (excellent) flowchart diagram designer in my application, but I'd like to use it as a UserControl.
To convert the Application into a UserControl I've changed the only window the application had:
<Window x:Class="DiagramDesigner.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:DiagramDesigner"
xmlns:c="clr-namespace:DiagramDesigner.Controls"
WindowStartupLocation="CenterScreen"
Title="Diagram Designer"
Height="850" Width="1000">
<Window.Resources>
<ContextMenu x:Key="DesignerCanvasContextMenu">
...
</ContextMenu>
</Window.Resources>
...
</Window>
into an user control:
<UserControl x:Class="DiagramDesigner.DiagramDesignerWPFControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:DiagramDesigner"
xmlns:c="clr-namespace:DiagramDesigner.Controls"
Height="850" Width="1000">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
...
</ResourceDictionary.MergedDictionaries>
<ContextMenu x:Key="DesignerCanvasContextMenu">
...
</ContextMenu>
</ResourceDictionary>
</UserControl.Resources>
...
</UserControl>
I took the ResourceDicctionary from the contents of App.xaml and added it to the control. Then I deleted the App.xaml file, as it can't be used in Class Library compilations.
My problem is:
When I add that new User Control to a WPF Form in another project, I can run the new application, I can add chart components and move them, but when I join/link the following exception raises:
Cannot find resource named '{SolidBorderBrush}'. Resource names are case sensitive.
What am I doing wrong with the resources or their location in my User Control?
Edition after accepting the answer:
The risen exception also pointed to a line where the '{SolidBorderBrush}' was called. I didn't initially put it in this question, as it was a call and not a declaration. This is the piece of code which linked the exception:
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="Border" Property="Background" Value="{DynamicResource ToolbarSelectedBackgroundBrush}" />
<Setter TargetName="Border" Property="BorderBrush" Value="{DynamicResource SolidBorderBrush}" />
</Trigger>
Im guessing here, because your question doesn't actually show any of the code which seems to be causing the issue, but you probably need to use DynamicResource.
{DynamicResource SolidBorderBrush}
You can only use StaticResource under very particular circumstances. You get a big performance boost most of the time, but it's very easy to end up in a situation where it can't be used (which may be what has happened).

Silverlight: Change style for state

My App.xaml looks like this:
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="mySilverlightApp.App"
>
<Application.Resources>
<Style x:Name="ComboBoxStyle" TargetType="ComboBox">
<Setter Property="FontFamily" Value="Calibri.ttf#Calibri"></Setter>
</Style>
</Application.Resources>
As you can see, I'm trying to apply custom styling with <Setter> tags to ComboBoxes in my app. But I want to apply styling for different states of the ComboBox (MouseOver, etc).
How can I do this?
To accomplish this, you'll have to create a control template in your implicit style. Something like the following:
<Style x:Name="ComboBoxStyle" TargetType="ComboBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
....
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
You can refer to this link for the default styles/controltemplates for the combobox: http://msdn.microsoft.com/en-us/library/dd334408(v=vs.95).aspx
A great way to get started re-templating controls is using Blend. You can right click a control you have dragged onto the artboard and use the "Edit Template -> Edit a Copy" command. This will create a default controltemplate for you (the same one shown in the link I provided).
From there you can edit the mouse-over state in Blend by using the States tab.
There's alot going on here, but this should get you started on the right path.

Inheriting from Application Styles (WPF)

I am trying to inherit application-level styles for a certain Window in my WPF application, but I'm having trouble getting it to inherit rather than simply override the existing styles.
In App.xaml (under the App.Resources element) I define a style as such:
<Style TargetType="Button">
<Setter Property="Padding" Value="6"/>
<Setter Property="FontWeight" Value="Bold"/>
</Style>
And in the XAML fora a certain Window, I define the following under Window.Resources:
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Padding" Value="6"/>
<Setter Property="FontWeight" Value="Bold"/>
</Style>
The problem here is that the former (app) style is ignored as if the latter (window) style has overridden it. The BasedOn attribute is set, which is intended to indicate that existing styles should be inherited, as far as I know. Removing the attribute doesn't help either. The only potential cause of which I can think is that {StaticResource {x:Type Button}} only refers to the default WPF style and not the one I have define in App.xaml.
I am aware that this styling behaviour would be possible to accomplish using the x:Key attribute, but I was hoping for a more elegant way that allows me to apply styles with inheritance to all controls within a scope (i.e. application/window).
Update
Thanks for both of your replies. You are indeed right that things work as expected in a sample application. The difference is that I inadvertently failed to mention that the style in App.xaml is contained within a ResourceDictionary, as such:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="SettingsDictionary.xaml"/>
<ResourceDictionary>
<Style x:Key="DefaultButton" TargetType="Button">
<Setter Property="Padding" Value="4"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Any suggestion on how to remedy matters in this case?
EDIT
After some research, I've found that the x:Key is being automatically generated if TargetType is set. So, the style in App.xaml is correct. However, the wpf designer is lacking some resource handling skills, and is not displayng both styles. If you build and run the project, both styles will be applied.
If your machine and VS2008 behave like the one upon which I tested your code.
Hope this helps.
EDIT 2
The resources and merged dictionaries in App.xaml have always been quirky.
I've solved the problem by moving the first style declaration out of the merged dictionary, like this:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!--<ResourceDictionary Source="SettingsDictionary.xaml"/>-->
</ResourceDictionary.MergedDictionaries>
<Style TargetType="Button">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="Padding" Value="4"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
</ResourceDictionary>
</Application.Resources>
Note also that giving the style an explicitly set key other than the {x:Type Button} will make it a non-default style and make it not apply automatically.
It is generally recommended to specify merged dictionaries only for resources from another file, and coded resources in the default space as above.
I'd second Jeff Wains comment in being surprised that your approach is not working as desired. In fact I'm unable to reproduce your issue via the following steps:
Created a new project via VS 2008 C# WPF application wizard.
resulting in App.xaml and Window1.xaml just like your example
Added a standard button from the toolbox to Window1.
Pasted your snippets as is, but modified one property each to observe the desired effect in the first place (having identical properties/values each is not what you intended to demonstrate I guess).
Well, this is just working fine, i.e. the button in Window1 inherits properties from both styles and modifying properties in either one does properly affect the button. Consequently their must be something weird going on behind the scenes in your project/environment? Have you tried a simple repro case like this already?

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