Creating default style for custom control - wpf

Im currently creating a custom control (based on the WPF DataGrid). What i would like to do is to set default styling on the datagrid. Currently im setting the Style property which works. But my problem arrises when i create a style to change fx. the background color in the main applications app.xaml. Then all my "default" styling is lost and the DataGrid looks all standard only with the background property set.
I have tried using OverrideMetadata on each of the properties on the grid that i want to apply a default value to but with no luck. I also tried setting each property in the constructor but because of property precedence the styles from the main application then never is applied.

Did you set this in the static constructor?
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomType), new FrameworkPropertyMetadata(typeof(MyCustomType)));
Also, is the Key of your resource Style equal to your custom control's Type?
It mustn't have some other Key set, even with TargetType set to your control.
The Assembly should also be marked with the following attribute:
[assembly: ThemeInfo(
//where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.None,
//where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
ResourceDictionaryLocation.SourceAssembly
)]

If you create a style without a dictionary key, it will style all objects of the type you specify within the scope that you import your style dictionary (if you specify it in a Window.Resources, it will have scope for that Window... if you specify it in App.xaml... you get the picture).
<Style TargetType="{x:Type Button}">
<Setter Property="FontFamily" Value="Times New Roman" />
<Setter Property="FontSize" Value="30" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Background" Value="#FFCA5132" />
</Style>
This will give them all the same style.
This is a very powerful feature. It allows you to style any object, not just UI elements. You can style, say, one of your data entities like a "Person" object and when those elements are used visually, like databinding a list of type Person to a ListView, all of them will be styled how you specified, even though they are not natively UI elements. This is how WPF can be "lookless" about its controls.

Related

WPF - Set child controls of a user control to be readonly using binding

I have a WPF application with many different controls. I need to be able to set all child controls to be read only based on a property in my view model that I want to bind to.
There are a couple of challenges that I see:
How to ensure that setting the parent control to read only, also sets the child controls
Not all controls have a ReadOnly property - some IsReadOnly, some only have an IsEnabled
Has anyone any views on a generic solution rather than me having to bind the appropriate property (ReadOnly, IsReadOnly, etc) for each individual control?
Is there some way that I could use an attached property? Is there anyway, for example, that I could set a property on a grid, then in the code iterate through each child control setting it's appropriate property (if applicable at all)?
Any ideas welcomed.
David
I would recommend to do this using WPF implicit styles. The style would contain the Binding to the view model, for example:
<Style TargetType="{x:Type Button}">
<Setter Property="IsEnabled" Value="{Binding IsNotProcessing}" />
</Style>
As this style does not have the x:Key attribute set and uses the x:Type markup extension on the TargetType attribute, it is implicitly applied to all buttons in this case.
You would have to write an implicit style for each distinct control in your view as the following style would not be applied to all your buttons, text boxes and whatever controls you use (although the IsEnabled property is defined on FrameworkElement):
<!-- This implicit style is not applied as the x:Type must be the same type as
the targeted control; inheritance does not work here. -->
<Style TargetType="{x:Type FrameworkElement}">
<Setter Property="IsEnabled" Value="{Binding IsNotProcessing}" />
</Style>
Another option would be to make a single style that has a resource key an then reference this from every control, which is also quite cumbersome, but could be done relatively easy using Blend if you know all the controls at design time (you would select all controls and then apply the style using the properties window).
Hope this will help you.
Use the property IsHitTestVisible in xaml file to make real read only
<Grid IsHitTestVisible = "False">
//put a control
</Grid>

How to set font, background etc. to be inherited by all controls in page?

My intent is to override phone theme. By default page markup has following code:
<phone:PhoneApplicationPage
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
I replace it with a style reference:
<phone:PhoneApplicationPage
Style="{StaticResource stylePage}"
Style is defined in app resources like this:
<Application.Resources>
<Style x:Key="stylePage" TargetType="phone:PhoneApplicationPage">
<Setter Property="Background" Value="White" />
<Setter Property="Foreground" Value="DeepSkyBlue" />
<Setter Property="FontFamily" Value="Arial" />
</Style>
</Application.Resources>
But background is still black, and font is white. Debugger shows that the values were applied.
If I set VisualRoot Grid's background, it's applied, but I want to set fontfamily and foreground values to be used by all my controls by default. Is it possible?
According to this msdn article - only the following properties are inherited in the visual tree in Silverlight: FontFamily, FontSize, FontStretch, FontStyle, FontWeight, and Foreground. Normally - dependency properties are not inherited in Silverlight (they often are in WPF). This is likely why these are not mentioned in the Silverlight MSDN article on dependency property value precedence, but the WPF version of the article mentions inherited value as lower priority than the local value or style setters. Your solution in fact works to some degree, but by default - most controls have font properties set by their style - Buttons by their default style, TextBlocks in page templates use PhoneTextNormalStyle or PhoneTextTitle1Style. If you remove the XML attributes setting the style of your TextBlocks - your application-wide font properties will apply to the TextBlocks.
Background dependency property unfortunately is not inherited, so your background will remain as is.
Your application-wide properties will not work on controls more complex than TextBlocks - like Buttons, since the default style of Buttons and other controls defines the style of TextBlocks explicitly using appropriate system styles.
I would say you should create your own resource dictionaries with styles of your controls and apply these to your controls manually, otherwise - you would need to write some code to automatically replace these properties at run time.

WPF Grid.Resources Style breaks ResourceDictionary Style. How to make them coexist?

In a WPF app I have a ResourceDictionary with Style defined for the TargetType MyCustomControl:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cc="clr-namespace:MyControlLibrary;assembly=MyControlLibrary" >
<Style TargetType="{x:Type cc:MyCustomControl}">
<Setter Property="Prop1" Value="1" />
<Setter Property="Prop2" Value="2" />
...
The problem is that I need to define a context menu for MyCustomControl in the page XAML like following:
<Grid>
<Grid.Resources>
<ContextMenu x:Key="MyControlContextMenu">
<MenuItem Name="Name1"
Header="Header1"
Click="Cm1_Click"
.../>
....
</ContextMenu>
<Style TargetType="{x:Type ScNamespace:MyCustomControl}">
<Setter Property="ContextMenu" Value="{StaticResource MyControlContextMenu}"/>
</Style>
</Grid.Resources>
...
In this case, though I only assign one Property in the Style definition inside my Grid, the ResourceDictionary Style values are not applied at all. They get overridden by page resource style and ignored.
How to solve this issue? Maybe there is a way to make a reference to ResourceDictionary in the Grid.Resources section to enforce looking up the ResourceDictionary Style?
Base your new style on your default style:
<Style TargetType="{x:Type ScNamespace:MyCustomControl}" BasedOn="{StaticResource {x:Type ScNamespace:MyCustomControl}}">
<Setter Property="ContextMenu" Value="{StaticResource MyControlContextMenu}"/>
</Style>
Not sure if it is what you're looking for, but a Style can inherit from another. With the BasedOn-property you can define the base style of a Style, so that the new style inherits all settings from this style.
However I never tried if it works also if the BasedOn references to the same key (type). Maybe it works:
<Style TargetType="{x:Type ScNamespace:MyCustomControl}"
BasedOn="{x:Type ScNamespace:MyCustomControl}">
If this works not, maybe you can separate the Style, define it globaly with a key and then reference to the globaly defined Style via the BasedOn-property.
In general, Controls should have their default Styles defined in the Themes folder in a theme specific file (see here for more info).
When an application looks for a
resource, it looks at three levels in
the following order:
1) The element level.
The system starts with the element
that references the resource and then
searches resources of the logical
parent and so forth until the root
element is reached.
2) The application level.
Resources defined by the Application
object.
3) The theme level.
Theme-level dictionaries are stored in
a subfolder named Themes. The files in
the Themes folder correspond to
themes. For example, you might have
Aero.NormalColor.xaml,
Luna.NormalColor.xaml,
Royale.NormalColor.xaml, and so on.
You can also have a file named
generic.xaml. When the system looks
for a resource at the themes level, it
first looks for it in the
theme-specific file and then looks for
it in generic.xaml.
In your case, you have two implicit Styles, so HCL and Kent's answers should work. Since only one implicit Style can be applied at a time. Same goes for setting the Style properly directly. In that case, no implicit Styles will be applied.
If you have your first Style setup as a default Style at the theme level, then it would be applied in addition to your second implicit Style (or any explicitly defined Style).

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