In WPF I could apply a style to a target type without giving it a name. This would effectively style all elements of that type without explicitly setting the style on each button.
<Style TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="White" />
</Style>
<Button Content="Button1"></Button>
This seems to be giving me problems within WP7 SL as the style is not applied unless I give it an x:Name and set the style on each instance.
<Style x:Key="btnStyle" TargetType="Button">
<Setter Property="BorderBrush" Value="Red" />
</Style>
Is this a chore that I will have to suffer or is there a workaround?
As far as I know, what you have observed in WP7 XAML is inherited from Silverlight. WP7 Silverlight is based on Silverlight 3 and some bits of Silverlight 4.Styles need to be explicitly applied, although this may seem to be too verbose, I personally find defining styles and using them to be best for maintenance of the code.
HTH, indyfromoz
Related
As I researched ways to specify default values for inherited dependency properties on a custom control, I ended up being more confused than enlightened.
What I found is basically:
Using the Style in Generic.xaml: WPF ControlTemplate: How to provide a default value for TemplateBinding?
Using OverrideMetadata in the static constructor: How can I change the default value of an inherited dependency property?
Using an initializer based on DefaultInitializer: How to set default value to CustomControl inherited?
I guess I'd be happy if I knew only one of the possibilities, but now I wonder which approach is the best fit under normal circumstances / whether there are significant drawbacks to any of the approaches.
When building Custom Controls there's a clear separation between the abstract model (class) and its representation (Generic.xaml). As always we should keep the view as dumb as possible, but likewise it pays to keep the implementation in the representation layer (and not clutter the model).
The only reason I can think of for overriding the default value in the class, would be when the order of initialization matters. For example, in case the inherited default value would throw an exception during the initialization of your class (before the Generic style would be able to "override" it).
Generic XAML: the preferred method, this offers most flexibility. Provides a clear picture of the default implementation (see edit).
Method override: As mentioned, when the order of initialization matters. Leads to less clean code.
DefaultInitializer: Is used to provide default values for VS designer.
The DefaultInitializer extension is invoked when the user adds an object from the Toolbox to the design surface.
Derive from the DefaultInitializer class to configure default initial values for your object.
EDIT - Subclassing Custom Controls
This is another area where separation of concerns pays off, giving you a clear overview.
<Style TargetType="{x:Type local:MyButtonBase}">
<Setter Property="FontSize" Value="12"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
</Style>
<Style BasedOn="{StaticResource {x:Type local:MyButtonBase}}"
TargetType="{x:Type local:MyButton}">
<!--Override inherited default value-->
<Setter Property="FontSize" Value="18"/>
<!--Add default values-->
<Setter Property="IsDefault" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MyButton}">
...
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
In my WPF application I created a resource of type SolidColorBrush and a button style which uses this resource as a background.
In my UserControl I override the color resource with the same name but a different color.
Can I create it in a way that a button in that UserControl will use the application Style but with the color defined in the UserControl?
What you are trying to do here is a little bit against the idea of resources in WPF as you try to mix up the top-down nature of resource definitions. So even if you get it to work, it will lead to untypical behavior, making it hard for the next person working on the code (or the future-you) to understand what's going on.
I would suggest to do the following to get exactly the behavior you want, still keeping things in order:
Suppose your app level resource like this:
<SolidColorBrush x:Key="MyColor" Color="Blue" />
<Style x:Key="TextBlockStyle" TargetType="TextBlock">
<Setter Property="Foreground" Value="{StaticResource MyColor}" />
... (other setters)
</Style>
If you want to override the Foreground with a local brush, do this explicitly when using the TextBlock (might be your UserControl as well) and use BasedOn to inherit everything else from the app level style:
<SolidColorBrush x:Key="MyOverridingColor" Color="Red" />
<Style x:Key="OverridingTextBlockStyle" TargetType="TextBlock" BasedOn="{StaticResource TextBlockStyle}">
<Setter Property="Foreground" Value="{StaticResource MyOverridingColor}" />
</Style>
I would suggest to use a different name for the second color (MyOverridingColor in the example above) to make clear that it is a different color.
I am using themes from the Silverlight toolkit, however several of them have poor readonly textbox styles (i.e. there is no visual representation when the textbox's are readonly.
How can I use the themes, but tweak a textbox readonly style?
(Because I am extensivly using the dataform this can only apply when the textbox is readony)
Easy enough in Silverlight 4 (once I got a little more familer with styling.
<df:DataForm.ReadOnlyTemplate>
<DataTemplate>
<StackPanel Name="rootPanel"
Orientation="Vertical">
<StackPanel.Resources>
<Style TargetType="TextBox">
<Setter Property="Foreground" Value="LightGray" ></Setter>
<Setter Property="Background" Value="Red" ></Setter>
</Style>
You'd need to start with the XAML and use it (implicit style support is built into Silverlight 4 now), or otherwise rebuild starting with the Toolkit theme you like.
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?
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}" />