How can I base a style on a default control's style? - wpf

We're writing a custom subclass of TextBox where we need to change only some basic parts of the style. Now we know when you subclass Control, normally you're supposed to change the metadata like this...
public class EnhancedTextBox : TextBox {
static EnhancedTextBox() {
// Commenting this line out lets this use the default TextBox style.
DefaultStyleKeyProperty.OverrideMetadata(
typeof(EnhancedTextBox),
new FrameworkPropertyMetadata(typeof(EnhancedTextBox)));
}
}
This changes the key used for that subclass type to be the type itself, which means it no longer gets the default TextBox style. No biggie... we just comment that line out and it again works since the key is still set to the value used by TextBox directly.
However, we're wondering if we did want to change a few things in the style, but not the entire style, we could simply create a new style and set its BasedOn property... but what do we set there? We don't want to have to pull out the XAML manually and create a new style, give it a key, then use a StaticResource, but we haven't found out what we could set there to say 'This is based on the TextBox style.
I'm hoping its something simple but again, we haven't found it. Can anyone help?

And just like that... I found it. Man, kicking myself that it was this obvious and I missed it!
<Style TargetType="{x:Type local:EnhancedTextBox}"
BasedOn="{StaticResource {x:Type TextBox}}">
....
</Style>
Found it here... WPF style basedon current

Related

When overriding DefaultStyleKey is necessary?

I have just spent like 2 hours trying to figure out why after moving a control from solution A to solution B (along with its style), the control stops showing up (control template was not applied). Turned out I forgot to override default style key. Here is the question: why did it work for solution A?
In DesignerView.cs:
public class DesignerView : Control {
// No DefaultStyleKeyProperty.OverrideMetadata here
}
In Generic.xaml:
<Style TargetType="{x:Type controls:DesignerView}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:DesignerView}">
<TextBlock Text="Hello" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Of course, my style is a little bit more complicated than that, but anyhow: exactly the same control (class+style, no proper DefaultStyleKeyProperty set) did show up in solution A, but didn't in solution B.
I guess you are talking about this:
static MyControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyControl),
new FrameworkPropertyMetadata(typeof(MyControl)));
}
Every control needs theme style which define its default template. (Most often for custom controls its defined under Themes\Generic.xaml).
DefaultStyleKeyProperty defines the key used to find the theme style of the control. If you comment out this line, it will pick default template of base class which generally is of type Control. (But since Control does not have any default template defined for it, your control is not shown when you comment out this line)
So, defaultStyleKeyProperty metadata needs to be overriden in static constructor to indicate that its default style is declared under Themes\Generic.xaml.
If you change base class to say Button and you comment out this line, you will see it pick default template of Button class.
So, for your question if your custom control is deriving from
Control, you need to override it to provide default template of control. In case deriving from control
whose default template is already defined then you can avoid
overriding it. It will pick base control style.
That being said for your question
why did it work for solution A?
I suspect you have defined an explicit style somewhere in your
solution A which is missing from Solution B. And Solution B doesn't
have theme style set as well because of no override of metadata.

Setting FontFamily of TextBox applicationwide

I have a big project at hand which involves a large amount of views and usercontrols. Additionaly, I want to set the FontFamily of every element to a certain font.
This works with most of the usercontrols like textBlocks, buttons and labels. Sadly this does not hold for textBoxes. They remain unchanged.
Before I create the whole GUI, I am overriding most of the metadata for elements containing text:
TextElement.FontFamilyProperty.OverrideMetadata(typeof(TextElement),
new FrameworkPropertyMetadata(new FontFamily("Calibri")));
TextBlock.FontFamilyProperty.OverrideMetadata(typeof(TextBlock),
new FrameworkPropertyMetadata(new FontFamily("Calibri")));
After a bit of searching, I found this article using the same method: http://blog.davidpadbury.com/
It clearly states at the end:
"In the above image you’ll see that we’ve successfully change the font on the text blocks, labels and buttons. Unfortunately the font inside the TextBox remains unchanged, this is due to it receiving it’s FontFamily property from it’s base class Control. Control adds itself as an Owner of the TextElement FontFamilyProperty but specifies it’s own metadata which we are then unable to override."
It also suggests to create a control template, which then sets the fontFamily. Is there another way? I want to set the fontFamily programmatically at the start without using XAML or creating a controlTemplate and using it as a base template for every textBox.
Thanks in advance.
You can declare a Style without the x:Key property and it will apply to all controls of that type:
<Style TargetType="{x:Type Control}">
<Setter Property="FontFamily" Value="Calibri" />
</Style>
Alternatively, you can simply set this on the MainWindow definition which will affect most elements:
<Window TextElement.FontFamily="Calibri" ...>
...
</Window>
Ahhh... I've just noticed your condition of not using xaml... sorry, I should have looked closer the first time.
UPDATE >>>
After a little research, it seems that you can do this in code like this:
Style style = new Style(typeof(TextBlock));
Setter setter = new Setter();
setter.Property = TextElement.FontFamilyProperty;
setter.Value = new FontFamily("Calibri");
style.Setters.Add(setter);
Resources.Add(typeof(TextBlock), style);
Unfortunately, you'd have to do other Styles for other types of controls too.
UPDATE 2 >>>
I just thought of something... that previous example just set the Style into the local Resources section which would be out of scope for your other modules. You could try setting the Style to the Application.Resources section which has global scope. Try replacing the last line of the code example above to this:
App.Current.Resources.Add(typeof(TextBlock), style);

Derive from Control and then allow others to apply a style

I have derived a new control from Control base class and set the DefaultStyleKeyProperty in the static constructor so that the appropriate style from Generic.xaml is used to defined the ControlTemplate. This all works fine and I get the expected appearance of several buttons etc.
Now I want to add some Style instances that customize the settings of my new control, such as the font and foreground color. But when I assign the style to the custom controls Style property it seems to remove the original default style and so it no longer has any appearance.
This doesn't seem quite right. The TabControl has a default style but you can still assign a Style to the TabControl.Style property that only modifies the Foreground color and it will not remove the rest of the TabControl appearance in the process.
Any ideas what I am doing wrong?
Declare your new style based on the default:
<Style TargetType={x:Type MyControl} BasedOn={StaticResource {x:Type MyControl}>

inherit a style or find the style programmatically

I have a third party control that I assume gets a style from somewhere.
I have an subclass of that control, where I add an event handler. but now when I replace the old control in xaml with my overrided control, the style gets lost. I assume that its distinguishing between the superclass and subclass when it applies the style. How do I tell it that subclasses, like MyButton:ThirdPartyButton, should have the same style as ThirdPartyButton.
Or is there a programmatic way to see the source of the style like
ThirdPartyButton.GetDefaultStyleLocation();
Define a style in the resources which is implicitly applied:
<Style TargetType="{x:Type local:MySubclass}"
BasedOn="{StaticResource {x:Type thirdParty:Control}}"/>
This is necessary since styles are sadly not inherited.

WPF: Create a custom control without rewriting the ControlTemplate

Hey, I am creating a Custom Control i WPF inheriting from the ListView. However, I want it to look exactly as the already existing ListView.
Is there a way To use the default ListView Template in a Custom Control without rewriting it in xaml? I do have a Generic.xaml file with the new control added, but I should no need to rewrite the template code.
Thanks
EDIT: I also want to keep it as DRY as possible without repeating (making a mess) the code.
If you subclass the ListView, them your subclassed control will use the ListView Template. That's it! You do not have to do anything!
The Template used by a control is defined by its DefaultStyleKey dependency property. If you want to change the template of your control, set this property as follows:
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyControl),
new FrameworkPropertyMetadata(typeof(MyControl)));
However, if you do not set this property, it will use the value set by the superclass.
I think the problem is that you have used "Add New Item" => "Custom Control" to create you control then changed the class it extends. Instead of doing this, just add a new C# class and extend ListView.
<Style TargetType="{x:Type local:MyControl}" BasedOn={StaticResource {x:Type ListView}}" />

Resources