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.
Related
I have a WPF application using MahApps Metro for it's UI theming. I also need to use style triggers so I can appropriately determine whether a control is visible based on a property. The triggers work, but have the side effect of removing the theme. So now it looks like a default WPF unthemed CheckBox. Is there any way to preserve the MahApps Metro theme on the CheckBox?
When you assign a style, you overwrite the default style or any style applied before. If you want to extend a style, you have specify the base style using the BasedOn property.
Styles can be based on other styles through this property. When you use this property, the new style will inherit the values of the original style that are not explicitly redefined in the new style.
Specify the control type to base your style on the implicit style of the control.
<Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource {x:Type CheckBox}}">
<!-- ...your setters and triggers. -->
</Style>
Specify the key of the style that you want to base your style on.
<Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource MyCheckBoxBaseStyle}">
<!-- ...your setters and triggers. -->
</Style>
The named styles for CheckBox in MahApps can be found here on GitHub.
Please be aware that although your Visibility triggers should work, other triggers that are already defined in the control template of the CheckBox styles take precedence and you will not be able to redefine them in your own style. If you ever hit that case, you have to copy the corresponding style from GitHub into your project and adapt it to your requirements.
My custom control is derived from ContentControl and has an additional dependency property 'AdditionalContent' of type FrameworkElement.
This property is bound to a ContentPresenter in style that has custom style resources:
<ContentPresenter ContentSource="AdditionalContent">
<ContentPresenter.Resources>
<Style TargetType="{x:Type Button}">
... some setters ...
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
As I learned from other questions here, I have to add this object as logical child of my control by calling AddLogicalChild(AdditionalContent) and overriding LogicalChildren property.
Now, if I use my control like this
<MyControl>
<MyControl.AdditionalContent>
<Button .../>
</MyControl.AdditionalContent>
</MyControl>
The style for Button is not applied. And that's the correct behaviour, because of style inheritance (see this answer). So I have to apply the style in the place where I define the AdditionalContent. So far so good.
But strange behaviour: when I leave out adding the object as logical child, the styles are applied.
Why does this happen? And is there a proper way to provide styles for all contents inside AdditionalContent similar to define Toolbar styles?
It's hard to tell since you have left out much of the button definition, but try setting the style of the button to a dynamic resource with the button type as the resource key.
<Button Style="{DynamicResource {x:Type Button}}"/>
When adding a default style with no resource key like you have done, the implicit key is the data type.
By setting the style to a dynamic resource you are indicating that the resource could change during runtime, which is the case when you are inserting it into the tree at runtime like you are doing.
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.
In my case, based on configuration settings grid lines should appear in different colors.
I have defined a simple style with TargetType of CellValuePresenter and I noticed that the style is applied to all columns except the ones which also have a style with target type of CellValuePresenter and have their own ControlTemplate. And I have lots of styles with ControlTemplates for CellValuePresenter across the solution, and it is not possible to change all of them to be BasedOn this new style I created.
What are my options so that the styles with ControlTemplates pickup my changes without modifying each one of them.
(Un)fortunately, styles don't apply like they do in CSS, so there's no ambiguity of what you will end up with at the end, where styles build up on each other.
If you create a style for a type, it is applied across all types in the scope of your style. This means if you include it at the top in your app.xaml, everything is affected, but if you include it only for a user control or window.xaml, it only applies to that.
If you create a style and apply it on a specific control, the local style set will override the global type based one. Unless you use BasedOn, which you specifically say you cannot do.
Unfortunately, I think you will be forced to refactor how you handle your styles to get the look you are trying to achieve, and BasedOn will be the way to go.
You can make a style BasedOn the default style for that element so that it includes all setters from the implicit style as well.
For example,
<Style TargetType="{x:Type CellValuePresenter}">
<!-- Generic Style Setters -->
</Style>
<!-- This Style will include the setters from the implicit style above -->
<Style x:Key="CustomCellStyle"
TargetType="{x:Type CellValuePresenter}"
BasedOn="{StaticResource {x:Type CellValuePresenter}}">
<Setter Property="ControlTemplate" ... />
</Style>
I've create a style for ListItems that I want to use across all ListBoxes in my application. I can set these manually like so:
<ListBox ItemContainerStyle="">
But I'm having trouble getting the style to apply to every single ListBox in my application without touching each one and adding the above attribute.
In addition, and more importantly, I want to apply the style to list boxes used within custom templated controls. Right now I have to modify the Generic.xaml theme in the control library... not something i think I should have to do.
Fairly certain this has something to do with themes, btu having a heck of a time figuring it out.
You can do this with implicit styles in Silverlight 4.
Define your style in the regular way:
<Style x:Key="DefaultListBoxStyle" TargetType="ListBox">
....
<Style>
then create the implicit style:
<Style TargetType="ListBox"
BasedOn="{StaticResource DefaultListBoxStyle}" />
you could use implicit styles.
http://www.silverlightshow.net/items/Implicit-Styles-in-Silverlight-4.aspx
You define one global style for a type (in your case ListBoxItem) and then this style is the new default style for your app.
If you need any further information, just leave a comment.
BR,
TJ