How to separate tabs into multiple rows in tab control (WPF) - c#

I have a tab control which I add tab items to programatically using C# and WPF. Everything works ok and I have tabs that look like this:
tab1 tab2 tab3
..tabs wrap around..
tab12 tab13
However, what I want to do is have two distinct rows of tabs like follows
tab4 tab5 tab6
...separator line...
tab1 tab2 tab3
..tabs wrap around..
tab12 tab13
Any idea how to accomplish this? My current tab control style looks like this
<Style x:Key="TabControlStyle1" TargetType="{x:Type TabControl}">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="Padding" Value="4,4,4,4"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="Background" Value="#F9F9F9"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="ColumnDefinition0"/>
<ColumnDefinition x:Name="ColumnDefinition1" Width="0"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition x:Name="RowDefinition0" Height="Auto"/>
<RowDefinition x:Name="RowDefinition1" Height="*"/>
</Grid.RowDefinitions>
<WrapPanel x:Name="HeaderPanel" Grid.Column="0" IsItemsHost="true" Margin="2,2,2,0" Grid.Row="0" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1"/>
<Border x:Name="ContentPanel" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="0" KeyboardNavigation.DirectionalNavigation="Contained" Grid.Row="1" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local">
<ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="TabStripPlacement" Value="Left">
<Setter Property="Grid.Row" TargetName="HeaderPanel" Value="0"/>
<Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="HeaderPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="ContentPanel" Value="1"/>
<Setter Property="Width" TargetName="ColumnDefinition0" Value="Auto"/>
<Setter Property="Width" TargetName="ColumnDefinition1" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
<Setter Property="Margin" TargetName="HeaderPanel" Value="2,2,0,2"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
so I figured I would add a second wrap panel to put the other tabs into. However, how do I specify which tabs would go into it?

What about specifying the MaxWidth for the only column of the grid, where the WrapPanel is defined ?
As for the second question, regarding to multiple WrapPanels, that's a good option as well. You can check the ActualWidth of the first WrapPanel in code and if its more than the width of the window, you can then target new tabs into the second panel.

Related

WPF DataGridRow BorderThickness increase row's width

I want to display my data in DataGrid.
I wrote my style for it and here it is
<Style TargetType="DataGridColumnHeader">
<Setter Property="FontSize" Value="20"/>
<Setter Property="Background" Value="DarkGreen" />
<Setter Property="Foreground" Value="White"/>
<Setter Property="BorderThickness" Value="0,0,0,1"/>
<Setter Property="BorderBrush" Value="ForestGreen"/>
<Setter Property="Height" Value="80"/>
<Setter Property="Padding" Value="5,0,0,0"/>
</Style>
<Style TargetType="DataGridRow">
<Setter Property="FontSize" Value="18"/>
<Setter Property="Background" Value="White"/>
<Setter Property="Margin" Value="0,6,0,0"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="LightGreen"/>
<Setter Property="Foreground" Value="DarkGreen"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="LightGreen"/>
<Setter Property="Foreground" Value="DarkGreen"/>
<Setter Property="BorderBrush" Value="ForestGreen"/>
<Setter Property="BorderThickness" Value="1"/>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="DataGridCell">
<Setter Property="Height" Value="80"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Focusable" Value="False"/>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="LightGreen"/>
<Setter Property="Foreground" Value="DarkGreen"/>
<Setter Property="BorderThickness" Value="0"/>
</Trigger>
</Style.Triggers>
</Style>
When i select the row the border show's up but the width of the row becomes larger than the width of the DataGrid -> I don't see right part of the border and horizontal scrollbar show's up.
So here is the question: how can i increase border thickness of the row, but do not increase row's width and height?
UPD
Before selection:
After selection:
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="5*"/>
<ColumnDefinition Width="5*"/>
1st Column is Fixed Width 50 while the other 2 are of same width. This makes your window have narrow left margin but Grid Sized margin on the right. Change Column 3 Width = 50. If that is not how you want it, make both col 2 *& 3 width = * as that is same as being 5*.
Next, Your Grid Columns each have been assigned a Width as a proportion. When you resize the window then only you last column text gets chopped. Otherwise it appears nice & fine.
Change DataGridRow style to following:
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridRow}">
<Border x:Name="DGR_Border"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="True">
<SelectiveScrollingGrid>
<SelectiveScrollingGrid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</SelectiveScrollingGrid.ColumnDefinitions>
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<DataGridCellsPresenter ItemsPanel="{TemplateBinding ItemsPanel}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
<DataGridDetailsPresenter Margin="4"
Grid.Row="1"
SelectiveScrollingGrid.SelectiveScrollingOrientation="{Binding AreRowDetailsFrozen, ConverterParameter={x:Static SelectiveScrollingOrientation.Vertical}, Converter={x:Static DataGrid.RowDetailsScrollingConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
Visibility="{TemplateBinding DetailsVisibility}"/>
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Grid.RowSpan="2"/>
</Grid>
<DataGridRowHeader SelectiveScrollingGrid.SelectiveScrollingOrientation="Vertical"
Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.Row}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
</SelectiveScrollingGrid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="DetailsVisibility" Value="Visible">
<Setter Property="BorderThickness" Value="4,1,4,4"/>
<Setter Property="BorderBrush" Value="#FF3886B9"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="LightGreen"/>
<Setter Property="Foreground" Value="DarkGreen"/>
<Setter Property="BorderBrush" Value="ForestGreen"/>
<Setter Property="BorderThickness" Value="1"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
Hope this will resolve your problem...

Changing the selected tab color WPF c#

I am trying to make the tabs the same color, regardless of whether it's selected or not, I have triggered and set the color, but it doesnt seem to be working:
<Window.Resources>
<SolidColorBrush x:Key="TabItem.Selected.Background" Color="#424E5A"/>
<SolidColorBrush x:Key="TabItem.Selected.Border" Color="#424E5A"/>
<Style x:Key="TabControlStyle1" TargetType="{x:Type TabControl}">
<Setter Property="Padding" Value="2"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Background" Value="{StaticResource TabItem.Selected.Background}"/>
<Setter Property="BorderBrush" Value="{StaticResource TabItem.Selected.Border}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid x:Name="templateRoot" ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="ColumnDefinition0"/>
<ColumnDefinition x:Name="ColumnDefinition1" Width="0"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition x:Name="RowDefinition0" Height="Auto"/>
<RowDefinition x:Name="RowDefinition1" Height="*"/>
</Grid.RowDefinitions>
<TabPanel x:Name="headerPanel" Background="#424E5A" Grid.Column="0" IsItemsHost="true" Margin="2,2,2,0" Grid.Row="0" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1"/>
<Border x:Name="contentPanel" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="0" KeyboardNavigation.DirectionalNavigation="Contained" Grid.Row="1" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local">
<ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="TabStripPlacement" Value="Bottom">
<Setter Property="Grid.Row" TargetName="headerPanel" Value="1"/>
<Setter Property="Grid.Row" TargetName="contentPanel" Value="0"/>
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition1" Value="Auto"/>
<Setter Property="Margin" TargetName="headerPanel" Value="2,0,2,2"/>
</Trigger>
<Trigger Property="TabStripPlacement" Value="Left">
<Setter Property="Grid.Row" TargetName="headerPanel" Value="0"/>
<Setter Property="Grid.Row" TargetName="contentPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="headerPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="contentPanel" Value="1"/>
<Setter Property="Width" TargetName="ColumnDefinition0" Value="Auto"/>
<Setter Property="Width" TargetName="ColumnDefinition1" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
<Setter Property="Margin" TargetName="headerPanel" Value="2,2,0,2"/>
</Trigger>
<Trigger Property="TabStripPlacement" Value="Right">
<Setter Property="Grid.Row" TargetName="headerPanel" Value="0"/>
<Setter Property="Grid.Row" TargetName="contentPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="headerPanel" Value="1"/>
<Setter Property="Grid.Column" TargetName="contentPanel" Value="0"/>
<Setter Property="Width" TargetName="ColumnDefinition0" Value="*"/>
<Setter Property="Width" TargetName="ColumnDefinition1" Value="Auto"/>
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
<Setter Property="Margin" TargetName="headerPanel" Value="0,2,2,2"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="TextElement.Foreground" TargetName="templateRoot" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="templateRoot" Property="Background" Value="#424E5A" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
But as you can see the color is white rather than the blueygrey the rest of my tab sidebar is:
image
How can I fix it so the color is always #424E5A
I think you are close, you are just missing that the header is defined in a TabItem, not in TabControl.
Thus you are looking for another style to add, in addition with the one you have already. Something like:
<Style x:Key="TabItemStyle1" TargetType="{x:Type TabItem}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<Border x:Name="grid" Background="{StaticResource TabItem.Selected.Background}">
<ContentPresenter>
<ContentPresenter.Content>
<TextBlock Margin="4" FontSize="15" Text="{TemplateBinding Content}"/>
</ContentPresenter.Content>
</ContentPresenter>
</Border>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type TabItem}},Path=IsSelected}" Value="True">
<Setter TargetName="grid" Property="Background" Value="{StaticResource TabItem.Selected.Background}"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</Setter.Value>
</Setter>
Hope it helps.

How can I shorten a BasedOn style

I'm currently making a "base style" for our application. I started by making a "base style" for our buttons, which will be a nice double-gradient (I created a template with 2 rows, and both rows have a two-point gradient).
So, the base button works fine, now I want to create other buttons based on that style.
This is the code for the base button:
<Style x:Key="BaseButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Height" Value="24"/>
<Setter Property="Width" Value="150" />
<Setter Property="Foreground" Value="{DynamicResource OffWhiteBrush}"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="OuterBorder" BorderBrush="{DynamicResource GrayBorderBrush}" BorderThickness="2" CornerRadius="5">
<Grid x:Name="LayoutGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border x:Name="TopBorder" BorderBrush="{x:Null}" BorderThickness="0" CornerRadius="4,4,0,0" Background="{DynamicResource TopGrayGradientBrush}"/>
<Border x:Name="BottomBorder" BorderBrush="{x:Null}" BorderThickness="0" Grid.Row="1" CornerRadius="0,0,4,4" Background="{DynamicResource BottomGrayGradientBrush}"/>
<ContentPresenter x:Name="contentPresenter" Grid.RowSpan="2" HorizontalAlignment="Center" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Control.Foreground" TargetName="contentPresenter" Value="{DynamicResource DisabledBrush}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Margin" TargetName="OuterBorder" Value="1"/>
<Setter Property="Background" TargetName="TopBorder" Value="{DynamicResource TopGrayGradientBrush}"/>
<Setter Property="Background" TargetName="BottomBorder" Value="{DynamicResource BottomGrayGradientBrush}"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" TargetName="TopBorder" Value="{DynamicResource TopBlueGradientBrush}"/>
<Setter Property="Background" TargetName="BottomBorder" Value="{DynamicResource BottomBlueGradientBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
When I create a second button I can do it "BasedOn" the other style:
<Style x:Key="RedButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource BaseButtonStyle}">
...
Inside the grid I've named my gradients: topborder and bottomborder. The problem is that I need to duplicate the code in order to be able to set any code, because the redbuttonStyle doesn't "know" topborder or bottomborder:
<Style x:Key="RedButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource BaseButtonStyle}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="OuterBorder" BorderBrush="{DynamicResource GrayBorderBrush}" BorderThickness="2" CornerRadius="5">
<Grid x:Name="LayoutGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border x:Name="TopBorder" BorderBrush="{x:Null}" BorderThickness="0" CornerRadius="4,4,0,0" Background="{DynamicResource TopGrayGradientBrush}"/>
<Border x:Name="BottomBorder" BorderBrush="{x:Null}" BorderThickness="0" Grid.Row="1" CornerRadius="0,0,4,4" Background="{DynamicResource BottomGrayGradientBrush}"/>
<ContentPresenter x:Name="contentPresenter" Grid.RowSpan="2" HorizontalAlignment="Center" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Control.Foreground" TargetName="contentPresenter" Value="{DynamicResource DisabledBrush}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Margin" TargetName="OuterBorder" Value="1"/>
<Setter Property="Background" TargetName="TopBorder" Value="{DynamicResource TopGrayGradientBrush}"/>
<Setter Property="Background" TargetName="BottomBorder" Value="{DynamicResource BottomGrayGradientBrush}"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" TargetName="TopBorder" Value="{DynamicResource TopRedGradientBrush}"/>
<Setter Property="Background" TargetName="BottomBorder" Value="{DynamicResource BottomRedGradientBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The problem here is that I've pretty much repeated the entire style, whilst I only want to change the two gradients on the IsMouseOver event
How should I handle this?
PS. I've looked at this WPF -- override style colors, best practice, but I can't figure out the TemplateBinding :/
You can use a technique where you define properties specific to your theme in a separate class and then bind to those properties from your templates. Please see my answer to this question.

How can I make the background color of a node in a TreeView goes all the way out to the right edge?

How can I make the background color of a node in a TreeView goes all the way out to the right edge?
Background
I have a TreeView where all nodes that have children are gray. Leaf nodes have an icon with descriptive text.
If i understand the problem right you are looking to stretch the treeview items.
If that is the case check Here
It's an easy fix. Unfortunately it'll require pretty much code since you'll have to re-template the TreeViewItem. The TreeViewItem's template looks like this
<ControlTemplate TargetType="{x:Type TreeViewItem}">
<Grid>
<Grid.ColumnDefinitions>
<!-- The Expand/Collapse ToggleButton -->
<ColumnDefinition MinWidth="19" Width="Auto"/>
<!-- The TreeViewItem -->
<ColumnDefinition Width="Auto"/>
<!-- The Children -->
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<ToggleButton x:Name="Expander" ClickMode="Press" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource ExpandCollapseToggleStyle}"/>
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="1" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
<ContentPresenter x:Name="PART_Header" ContentSource="Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
<ItemsPresenter x:Name="ItemsHost" Grid.ColumnSpan="2" Grid.Column="1" Grid.Row="1"/>
</Grid>
As you can see, the TreeViewItem itself is in Column 1 which has Width set to Auto while the children (ItemsPresenter) is in Grid.Column 1 and 2 and the Column 2 has Width set to *. To get the TreeViewItem itself to get the same Width as its children we can remove the middle Column (Column 1) and just use Grid.Column="1" for both.
Here's the default Template for TreeViewItem with this "Horizontal Stretch" fix. You'll have to add a reference to PresentationFramework.Aero
<Style x:Key="TreeViewItemFocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<PathGeometry x:Key="TreeArrow" Figures="M0,0 L0,6 L6,0 z"/>
<Style x:Key="ExpandCollapseToggleStyle" TargetType="{x:Type ToggleButton}">
<Setter Property="Focusable" Value="False"/>
<Setter Property="Width" Value="16"/>
<Setter Property="Height" Value="16"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Background="Transparent" Height="16" Padding="5,5,5,5" Width="16">
<Path x:Name="ExpandPath" Data="{StaticResource TreeArrow}" Fill="Transparent" Stroke="#FF989898">
<Path.RenderTransform>
<RotateTransform Angle="135" CenterY="3" CenterX="3"/>
</Path.RenderTransform>
</Path>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Stroke" TargetName="ExpandPath" Value="#FF1BBBFA"/>
<Setter Property="Fill" TargetName="ExpandPath" Value="Transparent"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter Property="RenderTransform" TargetName="ExpandPath">
<Setter.Value>
<RotateTransform Angle="180" CenterY="3" CenterX="3"/>
</Setter.Value>
</Setter>
<Setter Property="Fill" TargetName="ExpandPath" Value="#FF595959"/>
<Setter Property="Stroke" TargetName="ExpandPath" Value="#FF262626"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="StretchTreeViewItemStyle"
TargetType="{x:Type TreeViewItem}"
xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="Padding" Value="1,0,0,0"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="FocusVisualStyle" Value="{StaticResource TreeViewItemFocusVisual}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TreeViewItem}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="19" Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<ToggleButton x:Name="Expander" ClickMode="Press" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource ExpandCollapseToggleStyle}"/>
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="1" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
<ContentPresenter x:Name="PART_Header" ContentSource="Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
<ItemsPresenter x:Name="ItemsHost" Grid.Column="1" Grid.Row="1"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="false">
<Setter Property="Visibility" TargetName="ItemsHost" Value="Collapsed"/>
</Trigger>
<Trigger Property="HasItems" Value="false">
<Setter Property="Visibility" TargetName="Expander" Value="Hidden"/>
</Trigger>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true"/>
<Condition Property="IsSelectionActive" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
</MultiTrigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="VirtualizingStackPanel.IsVirtualizing" Value="true">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<VirtualizingStackPanel/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
And then you can use it like this
<TreeView ...>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource StretchTreeViewItemStyle}">
<!-- Add your own setters if applicable -->
</Style>
</TreeView.ItemContainerStyle>
</TreeView>

Blinking button on WPF application

My WPF application has a style manager that I have built on blend.
My problem is this: I've got a login button that blinks occasionally and i can't figure out how to remove this behavior.
Here's the style code for my login box:
<Style x:Key="LoginBoxGrid" TargetType="{x:Type Grid}">
<Setter Property="Background">
<Setter.Value>
<ImageBrush ImageSource="/Client;component/Assets/images/LoginBox.png" Stretch="None" TileMode="Tile"/>
</Setter.Value>
</Setter>
<Setter Property="Opacity" Value="0.765"/>
<Setter Property="Width" Value="411"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Margin" Value="126,150,0,111"/>
</Style>
<Style x:Key="LoginBoxHeader" TargetType="{x:Type Label}">
<Setter Property="Grid.Column" Value="2"/>
<Setter Property="Margin" Value="-16.183,18.347,0,0"/>
<Setter Property="Width" Value="64.994"/>
<Setter Property="FontSize" Value="16"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="FontStyle" Value="Italic"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="FontFamily" Value="/Client;component/Assets/Fonts/#Arial Black"/>
</Style>
<Style x:Key="LoginBtn" TargetType="{x:Type Button}">
<Setter Property="Grid.Column" Value="2"/>
<Setter Property="Margin" Value="16.6,9.022,9.282,8"/>
<Setter Property="Grid.Row" Value="4"/>
<Setter Property="Width" Value="164"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Opacity" Value="0.78"/>
<Setter Property="IsDefault" Value="True"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background">
<Setter.Value>
<ImageBrush ImageSource="/Client;component/Assets/images/LoginBtn.png"/>
</Setter.Value>
</Setter>
</Style>
And here's my code for the window:
<Grid Style="{StaticResource LoginBoxGrid}" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.127*"/>
<ColumnDefinition Width="0.326*"/>
<ColumnDefinition Width="0.462*"/>
<ColumnDefinition Width="0.085*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="0.269*"/>
<RowDefinition Height="0.028*"/>
<RowDefinition Height="0.256*"/>
<RowDefinition Height="0.223*"/>
<RowDefinition Height="0.178*"/>
<RowDefinition Height="0.046*"/>
</Grid.RowDefinitions>
<Label Content="User Name" Grid.Column="1" Margin="43.986,23.1,8,8" Grid.Row="2" Width="82" BorderThickness="0" FontFamily="Arial" FontWeight="Bold" FontStyle="Italic"/>
<Label Content="Password" Grid.Column="1" Margin="43.986,15.873,8,8" Grid.Row="3" Width="82" BorderThickness="0" FontFamily="Arial" FontWeight="Bold" FontStyle="Italic"/>
<PasswordBox Grid.Column="2" Name="PassTb" HorizontalAlignment="Left" Margin="8,18.877,0,8" Grid.Row="3" Width="172.6" d:LayoutOverrides="Height"/>
<TextBox Grid.Column="2" Name="UserTb" HorizontalAlignment="Left" Margin="9.282,23.1,0,11.004" Grid.Row="2" TextWrapping="Wrap" Text="TextBox" Width="172.6" d:LayoutOverrides="Height"/>
<Label Style="{StaticResource LoginBoxHeader}" Content="Login" />
<Button Name="LoginBtn" Style="{StaticResource LoginBtn}" Content="Login" />
</Grid>
The Button I'm talking about is called "LoginBtn", as is its style.
How can I remove that blinking behavior? Thanks in advance.
That flashing is due to the default style that WPF uses for buttons. To be more specific, it's due to the Trigger on the button's control template. To remove this, go into blend, right click on the button and select "Edit Template"->"Edit a copy". Click on the child element of the content presenter (by default, this is the control called "Chrome"). Then, in the triggers tab, inactive RenderDefaulted by pressing "- trigger". That trigger will keep the button from blinking. If you just want the XAML for all of that, here it is wrapped by windows.resource...
<Window.Resources>
<Style x:Key="ButtonFocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<LinearGradientBrush x:Key="ButtonNormalBackground" EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#F3F3F3" Offset="0"/>
<GradientStop Color="#EBEBEB" Offset="0.5"/>
<GradientStop Color="#DDDDDD" Offset="0.5"/>
<GradientStop Color="#CDCDCD" Offset="1"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="ButtonNormalBorder" Color="#FF707070"/>
<Style x:Key="BoringButtonStyle" TargetType="{x:Type Button}">
<Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}"/>
<Setter Property="Background" Value="{StaticResource ButtonNormalBackground}"/>
<Setter Property="BorderBrush" Value="{StaticResource ButtonNormalBorder}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Microsoft_Windows_Themes:ButtonChrome x:Name="Chrome" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}" RenderDefaulted="{TemplateBinding IsDefaulted}" SnapsToDevicePixels="true">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Microsoft_Windows_Themes:ButtonChrome>
<ControlTemplate.Triggers>
<Trigger Property="ToggleButton.IsChecked" Value="true">
<Setter Property="RenderPressed" TargetName="Chrome" Value="true"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="#ADADAD"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
Then, wherever you button is, apply this style...
<Button Style="{DynamicResource BoringButtonStyle}"/>
Update: The default button style has changed over the years. The idea is the same, use Blend for Visual Studio to edit the templete of the element you want to change. For this button, simply remove the IsDefaulted trigger entirly. Here is an updated code snippet.
<Style x:Key="FocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<SolidColorBrush x:Key="Button.Static.Background" Color="#FFDDDDDD"/>
<SolidColorBrush x:Key="Button.Static.Border" Color="#FF707070"/>
<SolidColorBrush x:Key="Button.MouseOver.Background" Color="#FFBEE6FD"/>
<SolidColorBrush x:Key="Button.MouseOver.Border" Color="#FF3C7FB1"/>
<SolidColorBrush x:Key="Button.Pressed.Background" Color="#FFC4E5F6"/>
<SolidColorBrush x:Key="Button.Pressed.Border" Color="#FF2C628B"/>
<SolidColorBrush x:Key="Button.Disabled.Background" Color="#FFF4F4F4"/>
<SolidColorBrush x:Key="Button.Disabled.Border" Color="#FFADB2B5"/>
<SolidColorBrush x:Key="Button.Disabled.Foreground" Color="#FF838383"/>
<Style x:Key="BoringButtonStyle" TargetType="{x:Type Button}">
<Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
<Setter Property="Background" Value="{StaticResource Button.Static.Background}"/>
<Setter Property="BorderBrush" Value="{StaticResource Button.Static.Border}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
<ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
<ControlTemplate.Triggers>
<!-- Delete this trigger
<Trigger Property="IsDefaulted" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
</Trigger>-->
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" TargetName="border" Value="{StaticResource Button.MouseOver.Background}"/>
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter Property="Background" TargetName="border" Value="{StaticResource Button.Pressed.Background}"/>
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Pressed.Border}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" TargetName="border" Value="{StaticResource Button.Disabled.Background}"/>
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Disabled.Border}"/>
<Setter Property="TextElement.Foreground" TargetName="contentPresenter" Value="{StaticResource Button.Disabled.Foreground}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Simple solution: Set button's "Focusable" to False.
A slightly less obtrusive way of removing that blinking would be to set a new ControlTemplate for ButtonBase with the offending bindings removed.
I took this via StyleSnooper from the Button default Style and revamped/simplified it to be a Style for ButtonBase that simply provides a new ControlTemplate*. To do this, add an assembly reference to Presentation.Aero and introduce the Microsoft.Windows.Themes namespace in your ResourceDictionary.
Here, I specifically removed the affected Button's ability to "blink" on its IsDefault property by hardcoding RenderDefaulted to false; you'll probably also want to replace the RenderMouseOver TemplateBinding.
<ResourceDictionary [...]
xmlns:mwt="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero">
<Style TargetType="{x:Type ButtonBase}"
x:Key="NonBlinkingButtonBase">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ButtonBase}">
<mwt:ButtonChrome Background="{TemplateBinding Panel.Background}"
BorderBrush="{TemplateBinding Border.BorderBrush}"
RenderDefaulted="False"
RenderMouseOver="{TemplateBinding UIElement.IsMouseOver}"
RenderPressed="{TemplateBinding ButtonBase.IsPressed}"
Name="Chrome"
SnapsToDevicePixels="True">
<ContentPresenter RecognizesAccessKey="True"
Content="{TemplateBinding ContentControl.Content}"
ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}"
ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}"
Margin="{TemplateBinding Control.Padding}"
HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</mwt:ButtonChrome>
<ControlTemplate.Triggers>
<Trigger Property="UIElement.IsKeyboardFocused" Value="True">
<Setter Property="mwt:ButtonChrome.RenderDefaulted" TargetName="Chrome" Value="True" />
</Trigger>
<Trigger Property="ToggleButton.IsChecked" Value="True">
<Setter Property="mwt:ButtonChrome.RenderPressed" TargetName="Chrome" Value="True" />
</Trigger>
<Trigger Property="UIElement.IsEnabled" Value="False">
<Setter Property="TextElement.Foreground">
<Setter.Value>
<SolidColorBrush>
#FFADADAD</SolidColorBrush>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then use this style as a BasedOn for your Button:
<Style x:Key="LoginBtn"
TargetType="{x:Type Button}"
BasedOn="{StaticResource NonBlinkingButtonBase}">
[...your stuff...]
</Style>
(*) And yes, we should really have the ability to use BasedOn for ControlTemplates as well...
I've since my first answer ran into this problem when attaching images to buttons and I figured out by setting the image and button to stretch and using a size on the border it fixed the problem.
Example code..
<Border Width="45" Height="45">
<Button x:Name="buttonSend"
ToolTip="Send" Command="{Binding Path=SendCommand}" Style="{StaticResource actionButtonStyle}">
<Image Source="..\Images\Email-256.png" Stretch="Fill" />
</Button>

Categories

Resources