WPF Menu Items Styles - wpf

I have an application resource of the following
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Background" Value="{DynamicResource windowTextBackColor}"/>
<Setter Property="Foreground" Value="{DynamicResource windowsTextForeColor}"/>
</Style>
So all the text blocks in my application should assume those colours.
However the Menu and its containing MenuItems on my Main Window does not take these colours?
I have to do the XAML
for it to assume those colours, Is there a reason why setting a style that targets Text blocks does not work?
Thanks

I think you have to style the menu and menuitems separately. A MenuItem is a HeaderedContentControl, and its Header property is not a TextBlock, but an object, so it wouldn't be affected by a style for TextBlock.
You might also try changing that style to target Control instead of TextBlock. (Control is where Foreground and Background are defined.) I can't say for sure that it'll work, but if it does, it'll make every Control (TextBlocks, MenuItems, Buttons...) have those background and foreground colors.
Also, you might consider using BasedOn so that you can "inherit" the styles. If you don't, then styles defined farther up the hierarchy won't affect controls that have a style defined lower in the hierarchy. Basically, the lower ones mask the higher ones, unless you used BasedOn. Use it in this fashion:
BasedOn="{StaticResource {x:Type <your type here>}}"

Related

Not all styles are overwritten in my WPF controls

I have a system where I use my WPF UI as a class library. I also use different usercontrols to control what the user see during the span of the UIs life cycle. These are all set in code. I then added a theme system where you could create a XAML ResourseDictionary file and use that to change the look on the UI. To apply the style, everytime I create the window or a user control, that FrameworkElement goes through this code:
public void ApplyStyle(FrameworkElement element)
{
var targetDir = element.Resources.MergedDictionaries.FirstOrDefault(d => d.Contains("SonaStyleDocument"));
if (targetDir != null && loadedResource != null)
{
element.Resources.MergedDictionaries.Remove(targetDir);
element.Resources.MergedDictionaries.Add(loadedResource);
}
}
In my view I do set a standard style document via the xaml code. I locate the default style in the code, remove it and add the new one. Now this works, and I can see the changes when I apply a external ResourceDictionary. However, for some reason my buttons does not react to the changes. They keep the same styles, even though it has been removed. Here is one of my buttons code:
<Button Style="{StaticResource KeyboardToggleButton}" Command="{Binding KeyboardToggleCommand}">
<Button.Content>...</Button.Content>
</Button>
It uses the style KeyboardToggleButton, which has the follow style in my default style document:
<Style TargetType="Button" x:Key="SonaButton">
...
</Style>
<Style TargetType="Button" x:Key="SonaPrimaryButton" BasedOn="{StaticResource SonaButton}">
<Setter Property="Template" Value="{StaticResource DxcPrimaryButtonTemplate}" />
...
</Style>
<Style TargetType="Button" x:Key="ManipulationButton" BasedOn="{StaticResource SonaPrimaryButton}">
...
</Style>
<Style TargetType="Button" BasedOn="{StaticResource ManipulationButton}" x:Key="KeyboardToggleButton" />
But I replace it with the following style(s):
<Style TargetType="Button" x:Key="SonaButton">
<Setter Property="Template" Value="{StaticResource RoundCornerTemplate}"></Setter>
</Style>
<Style TargetType="Button" x:Key="ManipulationButton" BasedOn="{StaticResource SonaButton}">
...
</Style>
<Style TargetType="Button" x:Key="KeyboardToggleButton" BasedOn="{StaticResource ManipulationButton}"/>
What could be going on here? They both have the same key for KeyboardToggleButton, though the templating is different and I can see that my other controls react fine to the new styles they get. I even tested just adding the new style and let the old one remain and that has the same result. The buttons just won't accept the new style.
Update:
So I was reading various articles about styles to see if I find some more information, and some article mentioned Dynamic resources. To isolate the problem I first remade my default style of one of my buttons to be very basic:
<Style TargetType="ButtonBase" x:Key="KeyboardToggleButton" />
And then changed the style I want to overwrite the default style, to just change the background:
<Style TargetType="Button" x:Key="KeyboardToggleButton">
<Setter Property="Background" Value="Yellow"/>
</Style>
With this setup nothing happened, but when I changed the Style from a StaticResource to DynamicResource, then it worked. However, this presented another problem. I tried testing this result on one of my other buttons with all substyles and control templates activated and the system throwsan exception in the code that adds the style:
System.InvalidOperationException: 'Property can not be null on Trigger.'
The style I try to use instead of the default style has a control template with triggers, to handle hover events, click event and more. My theory at this point is that I have had this problem also with the StaticResource, but the error is hidden and the system defaults directly to the old style. My issue with this theory is that I actively remove the default style before I enter in the new. Not removing the old style does not help.
I found the problem. The exception was indeed the answer, but only when I changed the code to apply each style individually. I should have followed the exception a bit more, but I had tunnel vision. The answer came from here: Why is the WPF property IsDefaulted not found?
I have first tried to change to buttonbase, but that does not work with the trigger "IsDefaulted". That will not resolve and the property will be null. Changing back to TargetType="Button" worked. No more exceptions. Then I also changed all style references to be dynamic and now all buttons (Except one, which I am looking into) have the correct style. It makes sense that it should be Dynamic as I change it during runtime.

How can I access the default styles for a theme?

In our WPF application, we have a custom listbox that when unstyled, matches the default Windows theme for things like the highlighted, hovered or selected items (i.e. nice blue translucent gradient.)
However, when we try creating our own ListBoxItem template and use values like in this code...
<Trigger Property="Selector.IsSelected" Value="True">
<Setter TargetName="Bd" Property="Panel.Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}" />
</Trigger>
...the control loses all traces of the Aero theme reverting to the old Win95/Classic look. How can we say 'Hey... apply the theme's 'highlighted' style to our border.'?
Again, the resources are obviously loaded as they're there until we re-template the control, but how are we supposed to access the built-in styles of the theme? After all, that 'selection' look is all over the place... ListBox, ComboBox, ListView, everywhere. We just want it in our control too without having to reinvent the wheel.
Note: We used the ShowMeTheTemplate.exe app to get the default 'Aero' style, but again, that's not what we're seeing when we run it.
You can use BasedOn="{StaticResource {x:Type ItemType}}" in your Style to modify the existing one however there is no way to merge part of a default template with your custom template, templates are monolithic.
Your answer appears to be here:
How to change WPF Listbox/ListBoxItem DataTemplate for selected item WITHOUT affecting style & theming?
....you should use ItemsContainerStyle instead of just defining a replacement ItemTemplate...and define your Style using BasedOn to inherit the default style defined for your FrameworkElement element by the theme.
There are also some other techniques you can use to leverage the default style defined by a theme (...just gives you extra options).
http://corneliutusnea.wordpress.com/2009/12/07/merging-wpfthemes-with-your-own-styles/
And yet another technique not covered above that uses a markup extension to merge together some styles (i.e. you could merge the default style and your style).
http://www.zagstudio.com/blog/384#.UDpfPqVum6M
XAML Combine Styles
http://swdeveloper.wordpress.com/2009/01/03/wpf-xaml-multiple-style-inheritance-and-markup-extensions/

WPF - Global Style?

Is there a way to setup global styles for my WPF application?
What I'm hoping to do is apply a style to all my Buttons that also have an Image child.
Well, sort of - it's a catch-all approach you can do - put the following element in your App.xaml - all your buttons will change (except the ones you apply a style to, manually).
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="LightPink"/> <!-- You should notice that one... -->
</Style>
However, if you want to hit only buttons with images - you have to inherit from Button everytime you do and then apply a style like this:
public class CustomImageButton:Button{}
<Style TargetType="{x:Type local:CustomImageButton}">
<Setter Property="Background" Value="LimeGreen"/>
</Style>
<local:CustomImageButton Content="ClickMe"/>
It is a very coarse-grained global styling - and you need to follow the convention to make it work.
An alternative is to use Themes - read more about that here.
You can do implicit styles in WPF which are applied by type
for instance
<Style TargetType="Button">
Will be applied to ALL the buttons within the scope of that style (If the style is in App.XAML it will apply to all buttons, if it is lower in the chain it will apply to all buttons underneath it)
If you want to apply it to only certain types of buttons (say imagebuttons) create a type that derives from button (call it ImageButton) and then create a style targeted to that type.
Put the style into a ResourceDictionary tag inside your App.xaml and it will apply to the entire app.

Is it possible to make customizable WPF styles?

I really like WPF because of its awesome skinning support by changing resourcedictionaries on the fly, but the catch is, the styles must be made by designers in XAML. My client needs a skinnable UI where the end users can make skins themselves. My question is -
In Photoshop, you can take any image, and add a color overlay to change all the colors to that hue. Can you do something similar in WPF? I'm just a beginner, and looking at several WPF styles, it seems like all the color values are hard-coded.
Here's a sample scenario - user selects two colors from color pickers, and all the controls have a gradient background from Color1 to Color2.
EDIT: Can the colors be saved to a XML file and loaded again too?
The key is to realize that a Style can contain a DynamicResource or a Binding, so if your style is:
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="{DynamicResource UserSelectedBackground}" />
...
</Style>
anything you set as a "UserSelectedBackground" resource will be applied to all buttons.
Alternatively you might bind to a view model object:
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="{Binding ButtonBackground, Source={x:Static my:SkinModel.Instance}" />
...
</Style>
Now whenever ButtonBackground in your SkinModel instance changes, all button backgrounds will automatically update. (This assumes your SkinModel uses DependencyProperties or implements INotifyPropertyChanged.)
To allow the user to separately control the two ends of a gradient fill, create two SolidColorBrush properties in your SkinModel which are bound from two-way by the color pickers. Whenever these properties change, recompute the ButtonBackground property (either in the PropertyChangedCallback of a DependencyProperty or in the setter of a CLR property).
Saving your state to the file is trivial: Just use XamlWriter to serialize your SkinModel to XAML, then write it to the file. To load it later, just use XamlReader.Parse.
You could store the color values in XML/DataBase (sqllite might be a good fit) and put them into a class that the controls will bind to. That way you can use a colorpicker for the user to change these data.

Applying a FontFamily to all Controls in Silverlight 4 Beta

I'd like to give every Control a certain FontFamily and FontWeight in Silverlight 4.0. I know that styles can now apply to all controls of a certain type, so I tried this:
<Style TargetType="Control">
<Setter Property="FontFamily" Value="Arial" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
Unfortunately, that doesn't appear to work. I can do this for types that derive from Control, however. For example, setting TargetType to Button applies those values to every Button in my application.
Why can't I do this for the Control base class, then?
The control styling being tied to the type system can be a bit misleading. Its actually based on the value of the controls DefaultStyleKey property. In the case of a Button the value is typeof(Button) and for a TextBox it is typeof(Textbox).
A default style will be applied to a control if the TargetType value equals the controls DefaultStyleKey value. There is no examination of whether the Type in the DefaultStyleKey is a derivative of the TargetType.
Font related properties are a special case since most controls will inherit the values for Font properties from the containing context. Hence you can effectively acheive the same result by specifying FontFamily and FontWeight on the UserControl element.
Edit
From a comment by the OP:-
I was hoping that I could set it in one place and have every UserControl in the entire application take on that style.
The closest you can get to that is to place a keyed style in the app resources and ensure all the usercontrols bind to that style. Of course this still requires some co-operation for each user control but at least the font choices remain in a single place.
For example in app.xaml:-
<Style x:Key="Common" TargetType="UserControl">
<Setter Property="FontFamily" Value="Arial" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Foreground" Value="Blue" />
Then in each usercontrol:-
<UserControl ...namespace stuff here...
Style="{StaticResource Common}">
<!-- ... content here ... -->
I do it by specifying FontFamily in my root visual. All child controls without explicit FontFamily set, derive FontFamily from the root visual.
Only ChildWindow needs extra FontFamily setting, because it is hosted in "über" root visual (as popup).
This would be of help:
this.RootVisual = New MainPage();
(MainPage)this.RootVisual.FontFamily
= New System.Windows.Media.FontFamily(
"/SLApplication;component/Fonts/segoeui.ttf#Segoe UI");

Resources