Changing background of TabControl - c#

I would like to change the background color of a WPF TabControl:
Changing the background color of the TabControl does not work, because the Grid element (direct child of the TabControl) doesn't inherit the backround of its parent:
The code below works, but it changes the background color of all subsequent grids:
<TabControl>
<TabControl.Resources>
<Style TargetType="Grid">
<Setter Property="Background" Value="Green" />
</Style>
</TabControl.Resources>
<!-- ... -->
</TabControl>
Is there a more appropriate solution?

While writing answer, nkoniishvt has already given right idea in comments, but I anyway will finish posting complete example.
Add xmlns:s="clr-namespace:System;assembly=mscorlib" namespace in your control.
Add this ControlTemplate in your ResourceDictionary in xaml:
<ControlTemplate x:Key="CustomTabControlTemplate" TargetType="TabControl" >
<Grid ClipToBounds="True" SnapsToDevicePixels="True" KeyboardNavigation.TabNavigation="Local" >
<Grid.ColumnDefinitions>
<ColumnDefinition Name="ColumnDefinition0" />
<ColumnDefinition Width="0" Name="ColumnDefinition1" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" Name="RowDefinition0" />
<RowDefinition Height="*" Name="RowDefinition1" />
</Grid.RowDefinitions>
<TabPanel IsItemsHost="True" Name="HeaderPanel" Margin="2,2,2,0" Panel.ZIndex="1" KeyboardNavigation.TabIndex="1" Grid.Column="0" Grid.Row="0" Background="Aqua" />
<Border BorderThickness="{TemplateBinding Border.BorderThickness}" BorderBrush="{TemplateBinding Border.BorderBrush}" Background="{TemplateBinding Panel.Background}" Name="ContentPanel" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local" KeyboardNavigation.DirectionalNavigation="Contained" Grid.Column="0" Grid.Row="1">
<ContentPresenter Content="{TemplateBinding TabControl.SelectedContent}" ContentTemplate="{TemplateBinding TabControl.SelectedContentTemplate}" ContentStringFormat="{TemplateBinding TabControl.SelectedContentStringFormat}" ContentSource="SelectedContent" Name="PART_SelectedContentHost" Margin="{TemplateBinding Control.Padding}" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="TabControl.TabStripPlacement">
<Setter Property="Grid.Row" TargetName="HeaderPanel">
<Setter.Value>
<s:Int32>1</s:Int32>
</Setter.Value>
</Setter>
<Setter Property="Grid.Row" TargetName="ContentPanel">
<Setter.Value>
<s:Int32>0</s:Int32>
</Setter.Value>
</Setter>
<Setter Property="RowDefinition.Height" TargetName="RowDefinition0">
<Setter.Value>
<GridLength>*</GridLength>
</Setter.Value>
</Setter>
<Setter Property="RowDefinition.Height" TargetName="RowDefinition1">
<Setter.Value>
<GridLength>Auto</GridLength>
</Setter.Value>
</Setter>
<Setter Property="FrameworkElement.Margin" TargetName="HeaderPanel">
<Setter.Value>
<Thickness>2,0,2,2</Thickness>
</Setter.Value>
</Setter>
<Trigger.Value>
<x:Static Member="Dock.Bottom" />
</Trigger.Value>
</Trigger>
<Trigger Property="TabControl.TabStripPlacement">
<Setter Property="Grid.Row" TargetName="HeaderPanel">
<Setter.Value>
<s:Int32>0</s:Int32>
</Setter.Value>
</Setter>
<Setter Property="Grid.Row" TargetName="ContentPanel">
<Setter.Value>
<s:Int32>0</s:Int32>
</Setter.Value>
</Setter>
<Setter Property="Grid.Column" TargetName="HeaderPanel">
<Setter.Value>
<s:Int32>0</s:Int32>
</Setter.Value>
</Setter>
<Setter Property="Grid.Column" TargetName="ContentPanel">
<Setter.Value>
<s:Int32>1</s:Int32>
</Setter.Value>
</Setter>
<Setter Property="ColumnDefinition.Width" TargetName="ColumnDefinition0">
<Setter.Value>
<GridLength>Auto</GridLength>
</Setter.Value>
</Setter>
<Setter Property="ColumnDefinition.Width" TargetName="ColumnDefinition1">
<Setter.Value>
<GridLength>*</GridLength>
</Setter.Value>
</Setter>
<Setter Property="RowDefinition.Height" TargetName="RowDefinition0">
<Setter.Value>
<GridLength>*</GridLength>
</Setter.Value>
</Setter>
<Setter Property="RowDefinition.Height" TargetName="RowDefinition1">
<Setter.Value>
<GridLength>0</GridLength>
</Setter.Value>
</Setter>
<Setter Property="FrameworkElement.Margin" TargetName="HeaderPanel">
<Setter.Value>
<Thickness>2,2,0,2</Thickness>
</Setter.Value>
</Setter>
<Trigger.Value>
<x:Static Member="Dock.Left" />
</Trigger.Value>
</Trigger>
<Trigger Property="TabControl.TabStripPlacement">
<Setter Property="Grid.Row" TargetName="HeaderPanel">
<Setter.Value>
<s:Int32>0</s:Int32>
</Setter.Value>
</Setter>
<Setter Property="Grid.Row" TargetName="ContentPanel">
<Setter.Value>
<s:Int32>0</s:Int32>
</Setter.Value>
</Setter>
<Setter Property="Grid.Column" TargetName="HeaderPanel">
<Setter.Value>
<s:Int32>1</s:Int32>
</Setter.Value>
</Setter>
<Setter Property="Grid.Column" TargetName="ContentPanel">
<Setter.Value>
<s:Int32>0</s:Int32>
</Setter.Value>
</Setter>
<Setter Property="ColumnDefinition.Width" TargetName="ColumnDefinition0">
<Setter.Value>
<GridLength>*</GridLength>
</Setter.Value>
</Setter>
<Setter Property="ColumnDefinition.Width" TargetName="ColumnDefinition1">
<Setter.Value>
<GridLength>Auto</GridLength>
</Setter.Value>
</Setter>
<Setter Property="RowDefinition.Height" TargetName="RowDefinition0">
<Setter.Value>
<GridLength>*</GridLength>
</Setter.Value>
</Setter>
<Setter Property="RowDefinition.Height" TargetName="RowDefinition1">
<Setter.Value>
<GridLength>0</GridLength>
</Setter.Value>
</Setter>
<Setter Property="FrameworkElement.Margin" TargetName="HeaderPanel">
<Setter.Value>
<Thickness>0,2,2,2</Thickness>
</Setter.Value>
</Setter>
<Trigger.Value>
<x:Static Member="Dock.Right" />
</Trigger.Value>
</Trigger>
<Trigger Property="UIElement.IsEnabled">
<Setter Property="TextElement.Foreground">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.GrayTextBrushKey}" />
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>False</s:Boolean>
</Trigger.Value>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
For example I set Background="Aqua" for TabPanel element inside root Grid.
Assign this ControlTemplate to the Template property of TabControl:
<TabControl Template="{StaticResource CustomTabControlTemplate}">
...
</TabControl>

Related

Background does not change of button C# WPF

I am trying to change style on mouseover.
My Code is:
<Button Name="register" Content="Register" Margin="15,410,20,0" Padding="6" FontSize="18" VerticalAlignment="Top" Background="#FF0090D6" BorderBrush="#FF0090D6" Foreground="White">
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Red"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
But the Background is the same default thing. But when i change property to BorderThickness then it works.
What am i doing wrong?
In the default template of button, there is trigger in ControlTemplate which set Background of button to #FFBEE6FD and since control template triggers have higher precedence compared to Style triggers that's why your trigger never works.
For that to achieve you have to override default template of button and remove that trigger from it so that your style trigger gets applied.
Here is the default template with that specific trigger commented out. In case you want to override BorderBrush as well, get rid of it as well from the template.
<ControlTemplate x:Key="DefaultTemplateOfButton" TargetType="ButtonBase">
<Border BorderThickness="{TemplateBinding Border.BorderThickness}"
BorderBrush="{TemplateBinding Border.BorderBrush}"
Background="{TemplateBinding Panel.Background}"
Name="border"
SnapsToDevicePixels="True">
<ContentPresenter RecognizesAccessKey="True"
Content="{TemplateBinding ContentControl.Content}"
ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}"
ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}"
Name="contentPresenter"
Margin="{TemplateBinding Control.Padding}"
HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}"
Focusable="False" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="Button.IsDefaulted" Value="True">
<Setter Property="Border.BorderBrush" TargetName="border">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.HighlightBrushKey}" />
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="UIElement.IsMouseOver" Value="True">
<!--<Setter Property="Panel.Background" TargetName="border">
<Setter.Value>
<SolidColorBrush>#FFBEE6FD</SolidColorBrush>
</Setter.Value>
</Setter>-->
<Setter Property="Border.BorderBrush" TargetName="border">
<Setter.Value>
<SolidColorBrush>#FF3C7FB1</SolidColorBrush>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="ButtonBase.IsPressed" Value="True">
<Setter Property="Panel.Background" TargetName="border">
<Setter.Value>
<SolidColorBrush>#FFC4E5F6</SolidColorBrush>
</Setter.Value>
</Setter>
<Setter Property="Border.BorderBrush" TargetName="border">
<Setter.Value>
<SolidColorBrush>#FF2C628B</SolidColorBrush>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="ToggleButton.IsChecked" Value="True">
<Setter Property="Panel.Background" TargetName="border">
<Setter.Value>
<SolidColorBrush>#FFBCDDEE</SolidColorBrush>
</Setter.Value>
</Setter>
<Setter Property="Border.BorderBrush" TargetName="border">
<Setter.Value>
<SolidColorBrush>#FF245A83</SolidColorBrush>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="UIElement.IsEnabled" Value="False">
<Setter Property="Panel.Background" TargetName="border">
<Setter.Value>
<SolidColorBrush>#FFF4F4F4</SolidColorBrush>
</Setter.Value>
</Setter>
<Setter Property="Border.BorderBrush" TargetName="border">
<Setter.Value>
<SolidColorBrush>#FFADB2B5</SolidColorBrush>
</Setter.Value>
</Setter>
<Setter Property="TextElement.Foreground" TargetName="contentPresenter">
<Setter.Value>
<SolidColorBrush>#FF838383</SolidColorBrush>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
How to set the control template to button?
Define the template somewhere under resource section of parent panel or UserControl and can be applied via StaticResource:
<Grid>
<Grid.Resources>
<ControlTemplate x:Key="MyTemplate"
TargetType="ButtonBase">
.......
</Grid.Resources>
<Button Name="register" Template="{StaticResource MyTemplate}"...>
</Grid>
Edit: As Rohit pointed out in the comments,
This won't work on Windows 8 because of some changes in PresentationFramework where default template of button is declared. ... In Windows 7 default template of button doesn't have that ControlTemplate trigger. That's why your posted code works fine on Windows7 but it won't work on Windows 8 and higher.
Rohit's answer about DependencyProperty Precedence being the cause is correct, but there's a much simpler way of fixing it than overwriting the Button's Template.
If you review the DependencyProperty Precedence List, you'll notice that properties set in the <Tag> have a higher precedence than Triggered properties, which is why your button will always use the background you have defined in your <Button> tag.
If you move the Background property to the <Style> itself, then triggered property will work since Triggered properties take precedence over properties defined in a Style.
<Button Name="register" Content="Register" ...>
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="#FF0090D6" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
You have to override the default template for achieve this.
<Button Content="Button" HorizontalAlignment="Left" VerticalAlignment="Bottom" Width="50" Height="50" HorizontalContentAlignment="Left" BorderBrush="{x:Null}" Foreground="{x:Null}" Margin="50,0,0,0">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Green"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="DarkGoldenrod"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
Hope this helps.
<Button Content="Button" HorizontalAlignment="Left" VerticalAlignment="Bottom" Width="50" Height="50" HorizontalContentAlignment="Left" BorderBrush="{x:Null}" Foreground="{x:Null}" Margin="50,0,0,0">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Green"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="DarkGoldenrod"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
Above code perfectly works,
Even with this user can change the background color of button in runtime/codebehind

Handling Events In Style Tag in Xaml

i m using EventSetter inside Style tag in xaml and Handling MouseEnter event.
But the problem is that the mouse enter event is only visible for a moment and get disappeard after that...why is it so??why it is not persisting??
this is my xaml file in which i have define style
<Style x:Key="MouseOverHighlightStyle">
<EventSetter Event="Button.MouseEnter" Handler="element_MouseEnter" />
<Setter Property="Button.Padding" Value="5"/>
</Style>
and this is my .cs file where i m handling events
namespace testing2
{
partial class stt
{
private void element_MouseEnter(object sender, MouseEventArgs e)
{
((Button)sender).Background =
new SolidColorBrush(Colors.LightGoldenrodYellow);
}
}
The behaviour you seeing is because in default template of button, there is a trigger on IsMouseOver property where explicit color is set to value #FFBEE6FD.
Specifically the trigger is this:
<Trigger Property="UIElement.IsMouseOver" Value="True">
<Setter Property="Panel.Background" TargetName="border">
<Setter.Value>
<SolidColorBrush>#FFBEE6FD</SolidColorBrush>
</Setter.Value>
</Setter>
<Setter Property="Border.BorderBrush" TargetName="border">
<Setter.Value>
<SolidColorBrush>#FF3C7FB1</SolidColorBrush>
</Setter.Value>
</Setter>
</Trigger>
But unfortunately if you have to change the value in that trigger you have to override entire ControlTemplate of button.
For your case it will be like this (with color LightGoldenrodYellow):
<Button>
<Button.Template>
<ControlTemplate TargetType="ButtonBase">
<Border BorderThickness="{TemplateBinding Border.BorderThickness}"
BorderBrush="{TemplateBinding Border.BorderBrush}"
Background="{TemplateBinding Panel.Background}"
Name="border"
SnapsToDevicePixels="True">
<ContentPresenter RecognizesAccessKey="True"
Content="{TemplateBinding ContentControl.Content}"
ContentTemplate="{TemplateBinding
ContentControl.ContentTemplate}"
ContentStringFormat="{TemplateBinding
ContentControl.ContentStringFormat}"
Name="contentPresenter"
Margin="{TemplateBinding Control.Padding}"
HorizontalAlignment="{TemplateBinding
Control.HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding
Control.VerticalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding
UIElement.SnapsToDevicePixels}"
Focusable="False" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="Button.IsDefaulted" Value="True">
<Setter Property="Border.BorderBrush" TargetName="border">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.HighlightBrushKey}"/>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="UIElement.IsMouseOver" Value="True">
<Setter Property="Panel.Background" TargetName="border">
<Setter.Value>
<SolidColorBrush Color="LightGoldenrodYellow"/>
</Setter.Value>
</Setter>
<Setter Property="Border.BorderBrush" TargetName="border">
<Setter.Value>
<SolidColorBrush>#FF3C7FB1</SolidColorBrush>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="ButtonBase.IsPressed" Value="True">
<Setter Property="Panel.Background" TargetName="border">
<Setter.Value>
<SolidColorBrush>#FFC4E5F6</SolidColorBrush>
</Setter.Value>
</Setter>
<Setter Property="Border.BorderBrush" TargetName="border">
<Setter.Value>
<SolidColorBrush>#FF2C628B</SolidColorBrush>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="ToggleButton.IsChecked" Value="True">
<Setter Property="Panel.Background" TargetName="border">
<Setter.Value>
<SolidColorBrush>#FFBCDDEE</SolidColorBrush>
</Setter.Value>
</Setter>
<Setter Property="Border.BorderBrush" TargetName="border">
<Setter.Value>
<SolidColorBrush>#FF245A83</SolidColorBrush>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="UIElement.IsEnabled" Value="False">
<Setter Property="Panel.Background" TargetName="border">
<Setter.Value>
<SolidColorBrush>#FFF4F4F4</SolidColorBrush>
</Setter.Value>
</Setter>
<Setter Property="Border.BorderBrush" TargetName="border">
<Setter.Value>
<SolidColorBrush>#FFADB2B5</SolidColorBrush>
</Setter.Value>
</Setter>
<Setter Property="TextElement.Foreground"
TargetName="contentPresenter">
<Setter.Value>
<SolidColorBrush>#FF838383</SolidColorBrush>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>

Stretch Width of WPF RichTextBox within a TreeView

My objective is simply to have a RichTextBox consume the entire row width inside a TreeView. The XAML below will produce a TreeView with a RichTextBox element, but the width is only 1 character wide.
I have encountered the posts below concerning width Bugs in RichTextBox. These issues may have been fixed since a standalone RichTextBox has the expected width. Despite this I still tried creating Grids, setting Alignments to Stretch, and binding the FlowDocument PageWidth to parent without success.
[NEW]
I am adding a description of my application in case some would like to propose RTB alternatives. I have a TreeView that contains between 10-1000 RTB nodes. TextBox and TextBlock are not practical because I need full formatting and user editing.
WPF RichTextBox with no width set
A WPF RichTextBox + Button in a StackPanel => what a mess?
<TreeView>
<RichTextBox>
<FlowDocument>
<Paragraph>
<Run>
Hello
</Run>
</Paragraph>
</FlowDocument>
</RichTextBox>
</TreeView>
Thanks,
As you stated this is a known issue
The workaround provided is:
<TreeView Name="RTBContainer" >
<RichTextBox Width="{Binding Path=ActualWidth, ElementName=RTBContainer, Mode=OneWay}">
<FlowDocument >
<Paragraph>
<Run>
Hello
</Run>
</Paragraph>
</FlowDocument>
</RichTextBox>
</TreeView>
Your problem stems from the TreeViewItem default template. A TreeViewItem element wraps any content placed in a TreeView. The TreeViewItem's template is Grid containing three columns with the width of the first two set as Auto while width of the third is set as *. The element holding the Header content is in the second column and its content alignment set to Left.
I've extracted the template for the TreeViewItem and modified it so that the content container for the header spans the second and third columns and has its content alignment set to stretch.
(This is a modified clone of the WPF template so it's a bit lengthly)
<TreeView>
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<!-- set the headers content to stretch -->
<Setter Property="Control.HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TreeViewItem" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="19" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<ToggleButton IsChecked="False" ClickMode="Press" Name="Expander">
<ToggleButton.Style>
<Style TargetType="ToggleButton">
<Style.Resources>
<ResourceDictionary />
</Style.Resources>
<Setter Property="UIElement.Focusable">
<Setter.Value>
<s:Boolean>False</s:Boolean>
</Setter.Value>
</Setter>
<Setter Property="FrameworkElement.Width">
<Setter.Value>
<s:Double>16</s:Double>
</Setter.Value>
</Setter>
<Setter Property="FrameworkElement.Height">
<Setter.Value>
<s:Double>16</s:Double>
</Setter.Value>
</Setter>
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border Padding="5,5,5,5" Background="#00FFFFFF" Width="16" Height="16">
<Path Fill="#00FFFFFF" Stroke="#FF989898" Name="ExpandPath">
<Path.Data>
<PathGeometry Figures="M0,0L0,6L6,0z" />
</Path.Data>
<Path.RenderTransform>
<RotateTransform Angle="135" CenterX="3" CenterY="3" />
</Path.RenderTransform>
</Path>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="UIElement.IsMouseOver">
<Setter Property="Shape.Stroke" TargetName="ExpandPath">
<Setter.Value>
<SolidColorBrush>#FF1BBBFA</SolidColorBrush>
</Setter.Value>
</Setter>
<Setter Property="Shape.Fill" TargetName="ExpandPath">
<Setter.Value>
<SolidColorBrush>#00FFFFFF</SolidColorBrush>
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>True</s:Boolean>
</Trigger.Value>
</Trigger>
<Trigger Property="ToggleButton.IsChecked">
<Setter Property="UIElement.RenderTransform" TargetName="ExpandPath">
<Setter.Value>
<RotateTransform Angle="180" CenterX="3" CenterY="3" />
</Setter.Value>
</Setter>
<Setter Property="Shape.Fill" TargetName="ExpandPath">
<Setter.Value>
<SolidColorBrush>#FF595959</SolidColorBrush>
</Setter.Value>
</Setter>
<Setter Property="Shape.Stroke" TargetName="ExpandPath">
<Setter.Value>
<SolidColorBrush>#FF262626</SolidColorBrush>
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>True</s:Boolean>
</Trigger.Value>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ToggleButton.Style>
</ToggleButton>
<!-- other problem was here set the Borders ColumnSpan to 2 -->
<Border BorderThickness="{TemplateBinding Border.BorderThickness}" Padding="{TemplateBinding Control.Padding}" BorderBrush="{TemplateBinding Border.BorderBrush}" Background="{TemplateBinding Panel.Background}" Name="Bd" SnapsToDevicePixels="True" Grid.Column="1" HorizontalAlignment="Stretch" Grid.ColumnSpan="2" >
<ContentPresenter Content="{TemplateBinding HeaderedContentControl.Header}" ContentTemplate="{TemplateBinding HeaderedContentControl.HeaderTemplate}" ContentStringFormat="{TemplateBinding HeaderedItemsControl.HeaderStringFormat}" ContentSource="Header" Name="PART_Header" HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</Border>
<ItemsPresenter Name="ItemsHost" Grid.Column="1" Grid.Row="1" Grid.ColumnSpan="2" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="TreeViewItem.IsExpanded">
<Setter Property="UIElement.Visibility" TargetName="ItemsHost">
<Setter.Value>
<x:Static Member="Visibility.Collapsed" />
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>False</s:Boolean>
</Trigger.Value>
</Trigger>
<Trigger Property="ItemsControl.HasItems">
<Setter Property="UIElement.Visibility" TargetName="Expander">
<Setter.Value>
<x:Static Member="Visibility.Hidden" />
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>False</s:Boolean>
</Trigger.Value>
</Trigger>
<Trigger Property="TreeViewItem.IsSelected">
<Setter Property="Panel.Background" TargetName="Bd">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.HighlightBrushKey}" />
</Setter.Value>
</Setter>
<Setter Property="TextElement.Foreground">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.HighlightTextBrushKey}" />
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>True</s:Boolean>
</Trigger.Value>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="TreeViewItem.IsSelected">
<Condition.Value>
<s:Boolean>True</s:Boolean>
</Condition.Value>
</Condition>
<Condition Property="Selector.IsSelectionActive">
<Condition.Value>
<s:Boolean>False</s:Boolean>
</Condition.Value>
</Condition>
</MultiTrigger.Conditions>
<Setter Property="Panel.Background" TargetName="Bd">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.ControlBrushKey}" />
</Setter.Value>
</Setter>
<Setter Property="TextElement.Foreground">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.ControlTextBrushKey}" />
</Setter.Value>
</Setter>
</MultiTrigger>
<Trigger Property="UIElement.IsEnabled">
<Setter Property="TextElement.Foreground">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.GrayTextBrushKey}" />
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>False</s:Boolean>
</Trigger.Value>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.ItemContainerStyle>
<RichTextBox HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch">
<FlowDocument>
<Paragraph>
<Run>
Hello
</Run>
</Paragraph>
</FlowDocument>
</RichTextBox>
</TreeView>

Set TextDecoration in Trigger error

Originally i tried to change color of pen in TextDecoration by trigger, but when i set x:Name property for pen i have got an error that target not found, so i had changed my template to following:
<ControlTemplate x:Key="TabButton" TargetType="{x:Type Button}">
<Border x:Name="border" Padding="10,5" CornerRadius="5,5,0,0" Background="#62A9FF">
<TextBlock x:Name="text" Text="{TemplateBinding Content}"
Cursor="Hand" Foreground="#F9FCFF">
<TextBlock.TextDecorations>
<TextDecoration Location="Underline"
PenThicknessUnit="FontRecommended">
<TextDecoration.Pen>
<Pen Brush="White" Thickness="1">
<Pen.DashStyle>
<DashStyle Dashes="5"/>
</Pen.DashStyle>
</Pen>
</TextDecoration.Pen>
</TextDecoration>
</TextBlock.TextDecorations>
</TextBlock>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="local:MainWindow.TabActive" Value="False">
<Setter TargetName="border" Property="Background" Value="Transparent"/>
<Setter TargetName="text" Property="Foreground" Value="Black"/>
<Setter TargetName="text" Property="TextDecorations">
<Setter.Value>
<TextDecorationCollection>
<TextDecoration Location="Underline">
<TextDecoration.Pen>
<Pen Brush="Gray" Thickness="1">
<Pen.DashStyle>
<DashStyle Dashes="5"/>
</Pen.DashStyle>
</Pen>
</TextDecoration.Pen>
</TextDecoration>
</TextDecorationCollection>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
Now application builds without error but when i run it i get error:
Cannot add content of type 'System.Windows.TextDecoration' to an object of type System.Windows.TextDecorationCollection
What is wrong? Or may be there is another way?
Cannot reproduce an error like that. Note that your triggers as they are would not work even if there was no error since you directly set the values on the target objects which take precedence over the trigger-setters.
Here is an example of variable TextDecorations which works, changes on mouse-over:
<ContentControl Content="Test">
<ContentControl.Template>
<ControlTemplate TargetType="{x:Type ContentControl}">
<TextBlock Name="tb" Text="{TemplateBinding Content}">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="TextDecorations">
<Setter.Value>
<TextDecorationCollection>
<TextDecoration>
<TextDecoration.Pen>
<Pen Brush="Blue" />
</TextDecoration.Pen>
</TextDecoration>
</TextDecorationCollection>
</Setter.Value>
</Setter>
</Style>
</TextBlock.Style>
</TextBlock>
<ControlTemplate.Triggers>
<Trigger Property="ContentControl.IsMouseOver" Value="True">
<Setter TargetName="tb" Property="TextDecorations">
<Setter.Value>
<TextDecorationCollection>
<TextDecoration>
<TextDecoration.Pen>
<Pen Brush="Red" />
</TextDecoration.Pen>
</TextDecoration>
</TextDecorationCollection>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ContentControl.Template>
</ContentControl>
Mine is a similar approach but without the templated control.
<TextBlock Text="5000.00" FontSize="20" >
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<Trigger Property ="IsMouseOver" Value="True">
<Setter Property="TextDecorations">
<Setter.Value>
<TextDecorationCollection>
<TextDecoration Location="Underline">
<TextDecoration.Pen>
<Pen Brush="Red"/>
</TextDecoration.Pen>
</TextDecoration>
</TextDecorationCollection>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property ="IsMouseOver" Value="False">
<Setter Property="TextDecorations">
<Setter.Value>
<TextDecorationCollection>
<TextDecoration Location="Underline">
<TextDecoration.Pen>
<Pen Brush="LimeGreen"/>
</TextDecoration.Pen>
</TextDecoration>
</TextDecorationCollection>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>

Dragging and dropping TreeViewItems in non-clickable area of TreeView [WPF]

A question about dragging and dropping tree view items in WPF.
My original question is a little complex. So I simplified it, and here is the code:
XAML
<Window x:Class="WpfApplication2.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<TreeView>
<TreeView.ItemContainerStyle>
<Style>
<Setter Property="TreeViewItem.IsExpanded" Value="True"/>
<Setter Property="TreeViewItem.Background" Value="LightBlue"/>
<Setter Property="TreeViewItem.AllowDrop" Value="True"/>
<EventSetter Event="TreeViewItem.MouseMove" Handler="TreeNode_MouseMove"/>
<EventSetter Event="TreeViewItem.Drop" Handler="TreeNode_Drop"/>
</Style>
</TreeView.ItemContainerStyle>
<TreeViewItem Header="first node in the tree"/>
<TreeViewItem Header="second node in the tree"></TreeViewItem>
<TreeViewItem Header="third node in the tree"></TreeViewItem>
</TreeView>
</Grid>
And code-behind:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void TreeNode_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
DragDrop.DoDragDrop(this, DateTime.Now.ToString(), DragDropEffects.Move);
}
}
private void TreeNode_Drop(object sender, DragEventArgs e)
{
string str = (string)e.Data.GetData(typeof(string));
MessageBox.Show(str);
}
}
So what I want to do is very simple, just pop up a message box when one tree view item is dragged and dropped on another tree view item.
When I drop it right on another item, it works fine, like this:
But if I drag it slightly off the boundary of the item, it does not work, like this:
The mouse cursor is displayed as a “forbidden sign”, sorry I can’t get it in the screen shot.
So now my question is: how to make the second condition work? How to make the Drop event still fire up when the dropping location is slightly off the boundary of the item?
Thanks in advance.
Take the default ControlTemplate of TreeViewItem and make the Border (the border which contains the ContentPresenter) to have a colspan of 2, e.g.:
<Border
BorderThickness="{TemplateBinding Border.BorderThickness}"
Padding="{TemplateBinding Control.Padding}"
BorderBrush="{TemplateBinding Border.BorderBrush}"
Background="{TemplateBinding Panel.Background}"
Name="Bd"
SnapsToDevicePixels="True"
Grid.Column="1" Grid.ColumnSpan="2">
Note that the whole area in TreeViewItem next to the TextBlock would become clickable. You may want to play around with the template to fit it to your needs.
Below is the ControlTemplate of TreeViewItem extracted using Dump Control Template Utility.
<?xml version="1.0" encoding="utf-16"?>
<ControlTemplate
TargetType="TreeViewItem" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition
Width="Auto"
MinWidth="19" />
<ColumnDefinition
Width="Auto" />
<ColumnDefinition
Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition
Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<ToggleButton
IsChecked="False"
ClickMode="Press"
Name="Expander">
<ToggleButton.Style>
<Style
TargetType="ToggleButton">
<Style.Resources>
<ResourceDictionary />
</Style.Resources>
<Setter
Property="UIElement.Focusable">
<Setter.Value>
<s:Boolean>False</s:Boolean>
</Setter.Value>
</Setter>
<Setter
Property="FrameworkElement.Width">
<Setter.Value>
<s:Double>19</s:Double>
</Setter.Value>
</Setter>
<Setter
Property="FrameworkElement.Height">
<Setter.Value>
<s:Double>13</s:Double>
</Setter.Value>
</Setter>
<Setter
Property="Control.Template">
<Setter.Value>
<ControlTemplate
TargetType="ToggleButton">
<Border
Background="#00FFFFFF"
Width="19"
Height="13">
<Border
BorderThickness="1,1,1,1"
CornerRadius="1,1,1,1"
BorderBrush="#FF7898B5"
Width="9"
Height="9"
SnapsToDevicePixels="True">
<Border.Background>
<LinearGradientBrush
StartPoint="0,0"
EndPoint="1,1">
<LinearGradientBrush.GradientStops>
<GradientStop
Color="#FFFFFFFF"
Offset="0.2" />
<GradientStop
Color="#FFC0B7A6"
Offset="1" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Border.Background>
<Path
Data="M0,2L0,3 2,3 2,5 3,5 3,3 5,3 5,2 3,2 3,0 2,0 2,2z"
Fill="#FF000000"
Name="ExpandPath"
Margin="1,1,1,1" />
</Border>
</Border>
<ControlTemplate.Triggers>
<Trigger
Property="ToggleButton.IsChecked">
<Setter
Property="Path.Data"
TargetName="ExpandPath">
<Setter.Value>
<StreamGeometry>M0,2L0,3 5,3 5,2z</StreamGeometry>
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>True</s:Boolean>
</Trigger.Value>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ToggleButton.Style>
</ToggleButton>
<Border
BorderThickness="{TemplateBinding Border.BorderThickness}"
Padding="{TemplateBinding Control.Padding}"
BorderBrush="{TemplateBinding Border.BorderBrush}"
Background="{TemplateBinding Panel.Background}"
Name="Bd"
SnapsToDevicePixels="True"
Grid.Column="1">
<ContentPresenter
Content="{TemplateBinding HeaderedContentControl.Header}"
ContentTemplate="{TemplateBinding HeaderedContentControl.HeaderTemplate}"
ContentStringFormat="{TemplateBinding HeaderedItemsControl.HeaderStringFormat}"
ContentSource="Header"
Name="PART_Header"
HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</Border>
<ItemsPresenter
Name="ItemsHost"
Grid.Column="1"
Grid.Row="1"
Grid.ColumnSpan="2" />
</Grid>
<ControlTemplate.Triggers>
<Trigger
Property="TreeViewItem.IsExpanded">
<Setter
Property="UIElement.Visibility"
TargetName="ItemsHost">
<Setter.Value>
<x:Static
Member="Visibility.Collapsed" />
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>False</s:Boolean>
</Trigger.Value>
</Trigger>
<Trigger
Property="ItemsControl.HasItems">
<Setter
Property="UIElement.Visibility"
TargetName="Expander">
<Setter.Value>
<x:Static
Member="Visibility.Hidden" />
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>False</s:Boolean>
</Trigger.Value>
</Trigger>
<Trigger
Property="TreeViewItem.IsSelected">
<Setter
Property="Panel.Background"
TargetName="Bd">
<Setter.Value>
<DynamicResource
ResourceKey="{x:Static SystemColors.HighlightBrushKey}" />
</Setter.Value>
</Setter>
<Setter
Property="TextElement.Foreground">
<Setter.Value>
<DynamicResource
ResourceKey="{x:Static SystemColors.HighlightTextBrushKey}" />
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>True</s:Boolean>
</Trigger.Value>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition
Property="TreeViewItem.IsSelected">
<Condition.Value>
<s:Boolean>True</s:Boolean>
</Condition.Value>
</Condition>
<Condition
Property="Selector.IsSelectionActive">
<Condition.Value>
<s:Boolean>False</s:Boolean>
</Condition.Value>
</Condition>
</MultiTrigger.Conditions>
<Setter
Property="Panel.Background"
TargetName="Bd">
<Setter.Value>
<DynamicResource
ResourceKey="{x:Static SystemColors.ControlBrushKey}" />
</Setter.Value>
</Setter>
<Setter
Property="TextElement.Foreground">
<Setter.Value>
<DynamicResource
ResourceKey="{x:Static SystemColors.ControlTextBrushKey}" />
</Setter.Value>
</Setter>
</MultiTrigger>
<Trigger
Property="UIElement.IsEnabled">
<Setter
Property="TextElement.Foreground">
<Setter.Value>
<DynamicResource
ResourceKey="{x:Static SystemColors.GrayTextBrushKey}" />
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>False</s:Boolean>
</Trigger.Value>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
use AllowDrop property and Drop event for TreeView itself.
this is from msdn: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/4b8bafe5-ae3e-439d-953a-f534a60dbb2d/

Categories