WPF TreeView style template resetting IsExpanded on style switch - wpf

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

Related

DoubleClick not handled on ListViewItem when clicking between Labels which comprises the ListViewItem

I implemented a ListView with some ListViewItems. A ListViewItem is comprised of two labels in a grid. In order to not having an underscore eat a letter, I've implemented a fix, setting RecognizesAccessKey to false.
<Grid.Resources>
<Style x:Key="{x:Type Label}" BasedOn="{StaticResource {x:Type Label}}" TargetType="{x:Type Label}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Label}">
<Border>
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
Margin="5"
RecognizesAccessKey="False" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
I'd like to handle a double-click on a ListViewItem. Adding it to the InputBindings of the ListView doesn't work. There's another question here on StackOverflow discussing this issue.
The answer to that other question suggests to move it to the InputBindings of the ListViewItem itself. This does generally work, but when clicking between the Labels, the double-click is not handled.
This is caused by the code shown above. Removing the Margin and having both Labels next to each other would be a 'solution' but I'd like to have them to close to each other. Of course, removing the code above altogether fixes the issue, too.
But with this margin, there is some space between both Labels that do not handle the DoubleClick. This wouldn't change, if the Margin is set on the Labels directly.
A completely different solution, suggested on yet another question, is to implement an attached behavior to the ListView. And yes, then it doesn't matter where I click, the DoubleClick is handled. However, it's even handled when not clicking on an item but somewhere in the ListView. The ListView usually has some empty space below the last item and when clicking there, the DoubleClick is still handled. I would like to handle it only when an item is hovered.
I don't have any strong preference regarding where the DoubleClick is implemented (i.e. both ListView and ListViewItem is fine), but I'm not sure how to get either working fine. Both implementations have that one downside and I haven't figured out how to get around it.
Does anyone have an idea on how to get one of the two approaches above working.
It turned out that the Border has a BackgroundColor of Null by default. When setting it to Transparent, the double-click is handled.
<Border Background="Transparent">
Links:
Mouse event on transparent background
{x:Null} vs. Transparent?
Hit Testing in the Visual Layer

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>

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.

WPF: Why are nested styles not always working?

I'm trying to apply a nested WPF style to a Toolbar. I'd like to have all children of the Toolbar (MenuItems, Buttons, ToggleButtons etc.) to have the specified style.
The problem is, that the nested style definition is applied correctly to some controls like MenuItems, but not to Buttons.
What am I doing wrong?
The MenuItem is correctly placed at the bottom of the Toolbar, but the ToggleButton is in the middle:
<Window.Resources>
<Style x:Key="MyToolbarStyle" TargetType="ToolBar">
<!-- Setters for Toolbar properties -->
<Setter Property="Height" Value="80" />
<!-- Nested setters for children of the Toolbar -->
<Style.Resources>
<Style TargetType="MenuItem">
<Setter Property="VerticalAlignment" Value="Bottom" />
</Style>
<Style TargetType="ToggleButton">
<Setter Property="VerticalAlignment" Value="Bottom" />
</Style>
</Style.Resources>
</Style>
</Window.Resources>
<Grid >
<ToolBar VerticalAlignment="Top" Style="{StaticResource MyToolbarStyle}">
<MenuItem Header="MyMenuItem" /> <!-- Appears on the bottom like defined in the style-->
<ToggleButton Content="MyToggleButton" /> <!-- Nested style does not seem to be applied-->
</ToolBar>
</Grid>
The WPF ToolBar is a special type of control that defines some custom styles for some WPF controls like Button, ToggleButton... full list here, you can identify them by ElementName + StyleKey property name. If you'd like to change a default style for a specific control you will have to modify one of these styles.
Try replacing your style for the ToggleButton with the following:
<Style x:Key="{x:Static ToolBar.ToggleButtonStyleKey}" TargetType="ToggleButton">
<Setter Property="VerticalAlignment" Value="Bottom" />
</Style>
What you are doing wrong is thinking that WPF Styles are like CSS styles. In WPF, Styles are just not used that way. Sure, if we could, we'd probably save a few lines of XAML, but we can't. The best that we can do is what you have done... I'm assuming that you've created a Style for a top level element like Control. As you have seen, not all controls will extend the Control class, so the Style won't be applied to all of them.
Instead, Styles in WPF are more like the .class styles in CSS... one Style per type and then we can apply a further Style per UI element. There are lots of situations like this in WPF where we wish we could write less code, but it is how it is and the sooner that everybody realises it, the better.
UPDATE >>>
In response to your first comment, you seem to be mistaken. Just to clarify, if what you are calling nested Styles are the Styles that you defined in the outer Style.Resources section, then there is nothing wrong with that... no problem what-so-ever. Just take those inner Styles out of the Resources section and you will see the same UI.
Now you're probably thinking of changing your question title to something like 'Why isn't my default ToggleButton Style being applied inside a ToolBar control?'. While I can't say for sure, I can only assume that this behaviour is caused by a Style that has been defined within the ToolBar ControlTemplate.
I'm thinking that because of the following points:
A custom implicit Style (no x:Key) will not work inside the ToolBar control.
A custom explicit Style (named) will work as expected inside the ToolBar control.
A Style property set on the element will work as expected inside the ToolBar control.

WPF: add to margin without overriding existing value

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.

Resources