WPF: add to margin without overriding existing value - wpf

I have two simple margin styles defined, one based off the other.
<Style x:Key="marginStyle" TargetType="FrameworkElement">
<Setter Property="Margin" Value="0,10,20,10"/>
</Style>
<!-- based on marginStyle -->
<Style x:Key="marginIndentStyle" TargetType="FrameworkElement" BasedOn="{StaticResource marginStyle}">
<Setter Property="Margin" Value="10,0,0,0"/>
</Style>
In the derived 'marginIndentStyle' style, I want adjust the margin's Left prop to be 10 more than the Left prop in the base 'marginStyle' style, that is 10 more than what it is currently set at. Using a like above overrides the values completely. I just want to add to it such that the resultant margin for the derived 'marginIndentStyle' style is "10,10,20,10".
Note, I dont want to strictly set its value to 10,10,20,10 b/c I want any changes in the 'marginStyle' style to be reflected in the derived 'marginIndentStyle' style.
Is this possible?

AFAIK, this is not possible without a sizable amount of code.
An easier way will be to have two styles with static margins that are applied to two different panels\decorators.
Something like:
<Border Style="{StaticResource marginIndentStyle}">
<Border Style="{StaticResource marginStyle}">
.....
</Border>
</Border>
This, effectively, will compound the margins. So what ever is in the second border will have the margin as combination of the first and the second margins.

Related

How do you expand an element to fill an Expanders Header?

I'm trying to expand an element to fill the horizontal space of an Expander.Header. I asked a similar question earlier, though I have since realized that the premises of the question was incorrect. Any use of Grids, or DockingPanels seems to have no effect on the ability for an element to fill the horizontal space of a Expander.Header.
Some more digging revealed that the ContentPresenter for the header is automatically set to HorizontalAlignment.Left. How do I go about changing this?
The only way to do that is finding the source xaml for the expander and modify it the way you want, creating your own expander style.
What you're looking for is a ControlTemplate. See here. You have to override the default template for the Expander.
You can declare a template which will affect all Expander controls using the following:
<ControlTemplate TargetType="Expander">
...
</ControlTemplate>
Or, you can set the Template property in a Style.
<Style TargetType="Expander">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Expander">
...
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

WPF TreeView style template resetting IsExpanded on style switch

I have a basic TreeView on a window that has a style applied from a resource in a dll. The style dll is capable of switching between two styles. When I don't have a style for the TreeView in the dll I am able to expand the TreeViewItems, switch styles (of other controls), and the TreeViewItems remain expanded. However, as soon as I add a style for the TreeView, the TreeViewItems that have been expanded collapse as soon as the style is switched.
All fancy animations and TreeViewItem styling has been removed in order to track down the problem. The remaining style is simply:
<Style x:Key="{x:Type TreeView}" TargetType="{x:Type TreeView}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TreeView">
<Border Name="Border"
Background="Transparent"
BorderThickness="1"
CornerRadius="1">
<ItemsPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Any suggestions would be greatly appreciated. I've ran out of ideas!
When you take away a template or replace by another some dependency properties will reset to their default value. The reason for that is dependency property precedence. Take a look at this here: http://msdn.microsoft.com/library/ms743230
Think of it like this: A dependency property may contain many values which are layered. The value in top most layer is always the current value. If you take a style away, you take layers away too. If you take all layers away, the dependency property will take default value as current value.
When you replace the style of your TreeView, all underneath styles will be updated/reinitalized/changed/resetted...
To fix this try keep same template and only change colors, borders and stuff like that.. or use Binding

Why is my XAML control losing properties when applying a style template to it?

I'm trying to style this button, and I even though I state the height it should be in my XAML, the template in the styling seems to get rid of it.
Note: I am aware I can just have a style with no template, but I need the template because I'm using multiple themes / style files.
Control:
<Button Style="{DynamicResource basicButton}"
Height="50">
<Canvas...>
<Path... />
</Canvas>
</Button>
Styling:
<Style x:Key="basicButton" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{DynamicResource solid_single_mainColor}">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Is this expected behavior? I intent to re-use this button style, so I need to be able to give it a height in the XAML. What am I missing? How can I give each new button I create a different height?
The problem is likely coming from the Canvas that you are placing inside the Button. In many cases a Canvas will have unbounded size unless you explicitly clip it. The Height of the Button itself isn't affected by its template as layout measurement will use the explicit value you have set but you may not be able to tell visually what size the Button itself is.

Setting ALL colors on WPF ComboBox using styles?

I asked this question a few days ago and got some answers, non of which really helped me with the problem, so I am trying a fresh approach.
I want to be able to set the colors (foreground, background, and border) of the textbox used by a comboBox so that it can have a number of different values, based on a trigger. With a textbox, this is easy, just use setters on those properties and you are done.
So given that I have a trigger as follows:
<Trigger Property="someProperty" Value="true">
<!-- Insert Setters Here -->
<Setter Property="Foreground"
Value="Red" />
</Trigger>
What Setters would I insert into the above to change the 3 aforementioned colors of the textbox used by the combobox? For each trigger, assume that every color will change. It appears that Foreground works except for disabled.
I am under the impression that changing the colors based on an "IsEnabled" trigger (when false) can be tricky, but not sure why. But I need to support that and a number of other triggers based on custom attached properties or validations.
For the background, I have tried a whole bunch of options including ComboBox.Background, TextElement.Background, Panel.Background, etc., but all I get is a plain white background.
One other thing occurred to me is that if those should work, there may be some resource library in the calling tree that may be setting the background color in a way that won't allow me to change it, but, if so, how would I be able to find out?
Thank you!
As I told you in your last (now duplicated) question, you will need to define a new ControlTemplate to achieve your goal.
For future reference:
Asking duplicate questions on StackOverflow is not approved by the community, especially if you are asking a duplicate of your own question. If you do not understand your answer(s) or do not feel that they answer your question adequately, you should ask the answer author(s) to explain it further in that question.
Now I'll get off my soap box and get you further on your way to achieving your goal. As I said, you will need to define a new ControlTemplate... there is no way around this. The reason for this is simple - you want to add Triggers to affect the XAML controls that are defined inside the default ControlTemplate, but you have no other way to do this from XAML.
So, how do we define a new ControlTemplate? It's quite simple really: we just define some XAML in the Template property that describes the way that we want the control to look and behave. Please refer to the link that I provided you with for help with this in your last post. Additionally, here is a very simplified example:
<Style TargetType="{x:Type ComboBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Border Name="Border" CornerRadius="2" Padding="2">
<ScrollViewer Margin="0" HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto">
<ItemsPresenter />
</ScrollViewer>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Border" Property="Background" Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Apply this Style to a ComboBox with the IsEnabled property set to False and you will see that it is red. Now you're probably thinking 'that doesn't look like a ComboBox' and you'd be right. That's because I just replaced all of the XAML from the default ComboBox ControlTemplate with a little bit that slightly resembles just the drop down section for simplicity.
Your job now is to define your own ControlTemplate that replicates the default XAML and adds the relevant Triggers that I have shown you in this and your last post. In the example, notice how the Trigger.TargetName is set to Border, which is the name of the internal Border control used. You will need to do this for each element that you want to colour.
Here is a link to the default ControlTemplate for the ComboBox control. When you see how large it is, you will understand why I didn't use it in the example.
ComboBox Styles and Templates

Toolbar button styles get ignored?

I have buttons on a toolbar in WPF.
When I do the XAML:
<ToolBar.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Width" Value="21"></Setter>
<Setter Property="Height" Value="21"></Setter>
</Style>
</ToolBar.Resources>
None of the buttons on the toolbar set their sizes accordingly.
I have to go to each button and manually set their widths and heights to the desired values.
Any idea why the Style on the toolbar does not work?
This occurs because ToolBar applies the style identified by ToolBar.ButtonStyleKey to buttons, instead of leaving them with the default style. (That's why buttons in Toolbars are flat even though the default style is raised.) Reference.
You need to "hijack" this style, instead of the default style:
<ToolBar.Resources>
<Style x:Key="{x:Static ToolBar.ButtonStyleKey}" TargetType="Button">
<Setter Property="Width" Value="100" />
</Style>
</ToolBar.Resources>
Note the x:Key in the Style declaration.
If you are adding hardcoded buttons to your toolbar, you can set ToolBar.ItemContainerStyle to a custom style to get the effect you want.
<ToolBar.ItemContainerStyle>
<Style
TargetType="Button">
<Setter
Property="Width"
Value="21" />
<Setter
Property="Height"
Value="21" />
</Style>
</ToolBar.ItemContainerStyle>
If you are using ToolBar.ItemsSource you can instead use ToolBar.ItemTemplate to define a template for your toolbar data.
<ToolBar.ItemTemplate>
<DataTemplate>
<Button
Width="21"
Height="21"
Content="{Binding}" />
</DataTemplate>
</ToolBar.ItemTemplate>
Note that in some cases, both of these can be used at the same time for additional flexibility.
This applies not only to toolbar, but to all derivatives of ItemsControl.
Best of luck,
As noted in the other answer the Toolbar will automatically apply its own styles to many/most typical controls added to it.
As an alternative to hijacking its style keys or applying your own styles to the controls manually, you can instead override its method which sets its internal styles in the first place. Simple example:
public class LessIsMoreToolbar : ToolBar
{
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
// Nada
}
}
and then use <local:LessIsMoreToolbar> in your XAML instead of <Toolbar>.
Note that here PrepareContainerForItemOverride() specifically does NOT call base.PrepareContainerForItemOverride()`. This is what eliminates the setting of styles. You can view the base's version of this method yourself to verify this doesn't eliminate anything you need.
One caveat is that PrepareContainerForItemOverride is defined by ItemsControl, which is like a great-grandparent of Toolbar. Its version of this method kicks off some other Prepare... cases which you also should be careful won't break anything. You can't (or perhaps shouldn't) just call that version of the method directly.
But in the end if it works for you then this is a nice simple approach.

Resources