Using a converter for more than one binding? - c#

I would like to do something like this:
<Style TargetType="{x:Type Binding}">
<Setter Property="Converter" Value="{StaticResource converter1}"/>
</Style>
That doesn't work though. So how do I tell more than one binding which converter to use without writing it explicitly for every single one?

I'm sorry to say, but there are actually two reasons you cannot do this.
<Style TargetType="{x:Type Binding}">
<Setter Property="Converter" Value="{StaticResource converter1}"/>
</Style>
Firstly, you cannot create a style for System.Windows.Data.Binding because it does not meet the requirements for styling. The TargetType must derive from either FrameworkElement or FrameworkContentElement. Alas, Binding inherits from BindingBase, then MarkupExtension, then Object and so it cannot be styled.
Secondly, Setter.Property is of type DependencyProperty. Binding.Converter is not a dependency property, so it simply cannot have a value bound to it.
So, you will have to repeat the Converer={StaticResource converter1} within the braces of each XAML {Binding} markup extension.

Related

WPF Override Style Value

I'm using MaterialDesignInXaml for WPF which provides 3rd party controls and styles. I need to edit one of these styles by changing one property.
I am using an Expander control which has a template creating a bunch of child controls. I've discovered the child 'Border' control (4 layers deep) has the property (padding) which I need to set to zero.
See this output from Snoop showing the property I need to change:
Link to image
My question is how can I do this? I've tried extending the style used by the control as follows, but it isn't changing anything so I assume I'm doing something wrong?
<Style TargetType="{x:Type Expander}"
x:Key="MaterialDesignExpanderHeadless"
BasedOn="{StaticResource MaterialDesignExpander}">
<Style.Resources>
<Style TargetType="{x:Type Border}">
<Setter Property="Padding" Value="0"></Setter>
</Style>
</Style.Resources>
</Style>
I am able to use the style like this. And I know this is working for sure:
<Expander Header="Header Content" Style="{StaticResource MaterialDesignExpanderHeadless}">
Some Content
</Expander>
You're right, this method should work. Something else is setting the border's padding.
Snoop is telling you the padding is defined by the parent template, which could be the HeaderSite (ToggleButton).
You could try to extend the ToggleButton style (BasedOn) or redefine it locally.

The member "Height" is not recognized or is not accessible

I want to set the Height property in a setter of a style but it shows the error at design time. It will work without problem at runtine.
The type inherits from control, which inherits for framework element, that has a Height property.
Can someone explain why and how I can fix it or get rid of the message?
<Style TargetType="{x:Type materialDesign:PackIcon}"
BasedOn="{StaticResource {x:Type materialDesign:PackIcon}}">
<Setter Property="Height"
Value="30" />
</Style>
I think it has nothing to do with the class itself, but here is the code anyway:
Apparently it has to do with the class itself:
materialDesign:PackIcon
Edit1:
After prefixing with FrameworkElement I get the error messagages:
PackIconExtension' type must derive from FrameworkElement or FrameworkContentElement.
and
The resource "materialDesign:PackIcon" could not be resolved.
Seemingly it is an extension - but this surpasses my wpf knowledge.
<Setter Property="FrameworkElement.Height"
Value="30" />
Edit2:
Here is the code of the extension: materialDesign:PackIconExtension

MenuItem Style seems to be overwritten

It seems that the menuitem style that I am attempting to use gets totally overwritten when I use ItemContainerStyle.
Here's an example of what happens when I use it:
However, when I don't use it, this is what I get:
I much prefer the look of the second menu, but it doesn't support dynamic menu creation due to not using ItemContainerStyle. What could possibly be overwriting the style? I'm using Mahapps Dark base and VS colors/styles.
Base your custom Style on the MetroMenuItem style that comes with MahApps:
<Style TargetType="MenuItem" BasedOn="{StaticResource MetroMenuItem}">
<Setter Property="Background" Value="Yellow" />
</Style>
you should use BaseOn property in the ItemContainerStyle.
<ItemContainerStyle x:Key="MyContainerStyle" BaseOn="{DynamicResource MenuItemStyle}">Style here</ItemContainerStyle>

Ignore global style for specific control and it's children

I've done my best to ensure this isn't an exact duplicate of other questions and have tried quite a few possible solutions. Maybe I'm just not doing the right searches.
The problem
I have a resource dictionary with a bunch of default styles. For example, most control types have a default height of 26 to provide some consistency in my layout.
So for example, I have the following style for TextBlock
<Style TargetType="TextBlock">
<Setter Property="Height" Value="26"/>
</Style>
The problem I have is that the Telerik RadGridView uses TextBlock controls to display the column header text and these controls are adopting the default style and end up with a height of 26.
I would like to get the RadGridView, and all of it's child controls, to ignore the styles in my resource dictionary.
I tried this but it didn't work
I found quite a few suggestions to set the style to Null for controls that you want to ignore global styles. I tried the following but it didn't work as it doesn't seem to apply to the child controls inside of the RadGridView.
<telerik:RadGridView Style="{x:Null}">
...
</telerik:RadGridView>
This works but may not be the best solution
I found the following question which had a solution I was able modify and use
Setting style based on existence of an ancestor type
Using the answers in that question I created a converter to check if a control has an ancestor of a specific type. The code is pretty much the same as in the above question so to keep this question from getting too long I won't paste it here.
I modified my style to this
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger
Binding="{Binding RelativeSource={RelativeSource Self},
Converter={StaticResource HasAncestorTypeConverter},
ConverterParameter={x:Type telerik:RadGridView}}"
Value="False">
<Setter Property="Height" Value="26"/>
</DataTrigger>
</Style.Triggers>
</Style>
Although this works, I was concerned about performance as my application grows and there's more and more controls. I have similar triggers for many control types that could be used in the RadGridView.
Every control is going to be recursively checking if it has a RadGridView as an ancestor. Most won't, so they need to search all the way up to their base container before knowing they don't have a RadGridView as an ancestor.
My question
So after that the lead up, my questions is whether there's a better way to do this? Is there something I can wrap the RadGridView with that will tell it, and it's child elements, to ignore the styles in my resource dictionary?
Yes there is better way to do this: define empty style either in Resources of RadGridView itself, or if you want to apply that to all RadGridViews - define it in resources of RadGridView style itself, like this:
<Style TargetType="telerik:RadGridView">
<Style.Resources>
<Style TargetType="TextBlock" />
</Style.Resources>
</Style>
That will prevent all children of RadGridView to inherit global TextBlock style (instead they will use "default" TextBlock style)

How to add a trigger to a WPF custom control without overriding the existing style?

I am creating a simple custom control extending from toggle button that allows the user to specify checked and unchecked content directly in XAML. It works well but it is based on a trigger, and I don't know how to define the trigger except in a style. If I define the style, then I lose anything set outside of the custom control.
What I would like to be able to do is just append this trigger to any existing style set elsewhere on the control.
Here's the XAML for the style/trigger.
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource {x:Type ToggleButton}}">
<Setter Property="Content" Value="{Binding RelativeSource={RelativeSource Self}, Path=UncheckedContent}" />
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content"
Value="{Binding RelativeSource={RelativeSource Self}, Path=CheckedContent}" />
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
I tried inheriting the style via the BasedOn with a default type but it won't work if the custom control has an explicit style set by its parent. I also considered EventTriggers but I do not believe there would be an event to initialize the control.
Thanks for any help anyone can offer. :)
Just to clear things up on the terminology here: A user control is a control that derives from the UserControl class. If I understood you right you derived from ToggleButton to add the UncheckedContent and CheckedContent properties. In that case you have created a custom control. It's always easier to follow if we agree on common terminology :)
As far as I know you can not do such a generic style inheritance in XAML. You always have to specify explicitly what style a another style is based upon. Your style can either be based on the default style for ToggleButton or on a specific other style. If you can't build a style inheritance chain that respects that, this approach won't work.
But since you have a custom control, couldn't you write a default style for it that is based on the default toggle button style like this?
<Style TargetType="{x:Type CustomToggleButton}"
BasedOn="{StaticResource {x:Type ToggleButton}}">
Then whenever you apply an explicit style to a toggle button you would specify that it is based on the default toggle button style.
Also you could write a (default) control template for your new toggle button in Themes\Generic.xaml that contains the above triggers. In blend you can get a copy of the default template for toggle button ("Edit Template"->"Edit a Copy") so you can make sure that your toggle button looks exactly like the normal toggle button. Then incorporate the triggers above into that template.
BTW: you do not have to create a new control just to add new properties. You can add new properties to an existing control using attached properties. They can be used from XAML just like normal properties.

Categories

Resources