[英]Control template triggers cannot set value when used with StaticResource or x:Static
我遇到的奇怪問題。
當嘗試將StaticResource
或x:Static
與來自ControlTemplate.Trigger
的轉換器一起使用時,轉換器value
始終為NULL
。
在下面的示例中,顯示了不同的用法,沒有任何問題:
<StackPanel Orientation="Horizontal">
<ContentControl Content="{DynamicResource Plus}"/>
<ContentControl Content="{DynamicResource Minus}"/>
<ContentControl Content="{Binding Source={StaticResource Plus}}"/>
<ContentControl Content="{Binding Source={StaticResource Minus}}"/>
<ContentControl Content="{Binding Source={StaticResource Plus}, Converter={StaticResource ToRed}}"/>
<ContentControl Content="{Binding Source={StaticResource Minus}, Converter={StaticResource ToRed}}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<ContentControl Content="{x:Static icon:Icons.Plus}"/>
<ContentControl Content="{x:Static icon:Icons.Minus}"/>
<ContentControl Content="{Binding Source={x:Static icon:Icons.Plus}}"/>
<ContentControl Content="{Binding Source={x:Static icon:Icons.Minus}}"/>
<ContentControl Content="{Binding Source={x:Static icon:Icons.Plus}, Converter={StaticResource ToRed}}"/>
<ContentControl Content="{Binding Source={x:Static icon:Icons.Minus}, Converter={StaticResource ToRed}}"/>
</StackPanel>
上面的代碼導致:
到目前為止一切都很好, StaticResouce
和x:Static
都可以正常工作,但是在ControlTemplate.Triggers
中使用相同的示例,然后轉換器將NULL
作為VALUE
這在 VS 16.11.15 (2019) 中的 .NET 4.5、4.7.2 和 4.8 中進行了測試
重現:
我的資源.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Viewbox x:Key="Minus" x:Shared="False" Stretch="Uniform">
<Canvas Width="32" Height="32" Clip="F1 M 0,0L 32,0L 32,32L 0,32L 0,0">
<Rectangle Width="19" Height="19" Canvas.Left="6.49999" Canvas.Top="6.5" Stretch="Fill" StrokeMiterLimit="2.75" Stroke="#FF575756"/>
<Rectangle Width="9" Height="2" Canvas.Left="11.5" Canvas.Top="15" Stretch="Fill" Fill="#FF1E5AA0"/>
</Canvas>
</Viewbox>
<Viewbox x:Key="Plus" x:Shared="False" Stretch="Uniform">
<Canvas Width="32" Height="32" Clip="F1 M 0,0L 32,0L 32,32L 0,32L 0,0">
<Rectangle Width="19" Height="19" Canvas.Left="6.49999" Canvas.Top="6.5" Stretch="Fill" StrokeMiterLimit="2.75" Stroke="#FF575756"/>
<Path Width="9" Height="9" Canvas.Left="11.5" Canvas.Top="11.5" Stretch="Fill" Fill="#FF1E5AA0" Data="F1 M 20.5,15L 17,15L 17,11.5L 15,11.5L 15,15L 11.5,15L 11.5,17L 15,17L 15,20.5L 17,20.5L 17,17L 20.5,17L 20.5,15 Z "/>
</Canvas>
</Viewbox>
</ResourceDictionary>
靜態類
//STATIC CLASS TO GET ICONS via x:Static
public static class Icons
{
public static UIElement Minus => GetIconByName("Minus");
public static UIElement Plus => GetIconByName("Plus");
private static UIElement GetIconByName(string name)
{
try
{
return Application.Current.FindResource(name) as UIElement;
}
catch
{
return null;
}
}
}
//STATIC CLASS TO WRITE TO THE CONSOLE TEXTBOX
public static class Console
{
public static void WriteLine(string message)
{
var console = ((MainWindow) Application.Current.MainWindow).Console;
if (console == null)
{
Debug.WriteLine(message);
return;
}
console.Text = $"{message}\n{console.Text}";
}
}
//STATIC EXTENSION CLASS FOR CHANGING COLORS
public static class Extensions
{
public static UIElement ToRed(this UIElement element)
{
if (element == null) return null;
var result = (UIElement)System.Windows.Markup.XamlReader.Parse(System.Windows.Markup.XamlWriter.Save(element));
result.ReColorAll(new SolidColorBrush(Colors.Red));
return result;
}
private static void ReColorAll(this DependencyObject element, Brush newColor)
{
if (element is null) return;
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
{
// Retrieve child visual at specified index value.
var childVisual = VisualTreeHelper.GetChild(element, i);
switch (childVisual)
{
case Shape shape:
{
if (shape.Fill != null) shape.Fill = newColor;
if (shape.Stroke != null) shape.Stroke = newColor;
break;
}
case GeometryDrawing drawing:
{
if (drawing.Brush != null) drawing.Brush = newColor;
break;
}
}
childVisual.ReColorAll(newColor);
}
}
}
轉換器類
//CONVERTER CLASS TO CONVERTER ICONS TO RED
public class ToRedConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Console.WriteLine($"PARAMETER: {parameter} - VALUE: {value}");
var result = !(value is UIElement element) ? value : element.ToRed();
return result;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
主窗口.xaml
<Window x:Class="WpfAllPurposesTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:icon="clr-namespace:WpfAllPurposesTest"
Title="InfragisticsWindow" Width="700" Height="800">
<Window.Resources>
<icon:ToRedConverter x:Key="ToRed"/>
<!--STYLE/TEMPLATE FOR TOGGLE BUTTON-->
<Style x:Key="TreeToggleButtonStyle" TargetType="ToggleButton" x:Shared="False">
<Setter Property="Focusable" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid Width="20" Height="20" Background="{TemplateBinding Background}">
<ContentControl x:Name="ExpandPath" Content="{Binding Path=Content, RelativeSource={RelativeSource TemplatedParent}}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--STYLE/TEMPLATE FOR TREEVIEWITEM-->
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TreeViewItem}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition x:Name="RowToHide" Height="20"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Border Name="BrdBackground" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" BorderBrush="Gray" BorderThickness="0,0,0,0"/>
<!--VERTICAL LINE-->
<Border Name="VerticalLine" Grid.Row="0" Grid.RowSpan="2" Grid.Column="0">
<Path Data="M 5 1 L 5 9" StrokeThickness="0.5" Stroke="Black" Stretch="Fill" VerticalAlignment="Stretch" HorizontalAlignment="Center"/>
</Border>
<!--HORIZONTAL LINE-->
<Border Grid.Row="0" Grid.Column="0" Width="25">
<Path Data="M 12 12 L 25 12" StrokeThickness="0.5" Stroke="Black" Stretch="None"/>
</Border>
<!--EXPANDER / PLUS / MINUS ICON-->
<ToggleButton x:Name="Expander" Grid.Column="0" Grid.Row="0" Background="White" IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
ClickMode="Press" Content="{Binding Source={StaticResource Plus}}" Style="{DynamicResource TreeToggleButtonStyle}" Visibility="Visible" Margin="0,0,2,0"/>
<!--TREE VIEW ITEM-->
<ContentPresenter x:Name="PART_Header" Grid.Column="1" Grid.Row="0" ContentSource="Header" HorizontalAlignment="Left"/>
<!--TREE VIEW ITEM CHILDREN HOST-->
<ItemsPresenter x:Name="ItemsHost" Grid.Column="1" Grid.Row="1" Grid.ColumnSpan="2" />
<!--DUMMY BORDER TO MAKE ITEM AVAILABLE FOR MOUSE OVER AND SELECTION-->
<Border x:Name="TopBorder" Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" BorderThickness="0" Background="Transparent"/>
</Grid>
<!--TRIGGERS-->
<ControlTemplate.Triggers>
<Trigger Property="HasItems" Value="false">
<Setter TargetName="Expander" Property="Visibility" Value="Collapsed"/>
</Trigger>
<Trigger Property="IsExpanded" Value="false">
<Setter TargetName="ItemsHost" Property="Visibility" Value="Collapsed"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition SourceName="TopBorder" Property="IsMouseOver" Value="true"/>
<Condition Property="IsSelected" Value="false"/>
<Condition Property="IsExpanded" Value="false"/>
</MultiTrigger.Conditions>
<Setter TargetName="Expander" Property="Content" Value="{Binding Source={StaticResource Plus}, Converter={StaticResource ToRed}, ConverterParameter=CONVERTtview1}"/>
<Setter TargetName="Expander" Property="Background" Value="LightSkyBlue"/>
<Setter TargetName="BrdBackground" Property="Background" Value="LightSkyBlue"/>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition SourceName="TopBorder" Property="IsMouseOver" Value="true"/>
<Condition Property="IsSelected" Value="false"/>
<Condition Property="IsExpanded" Value="true"/>
</MultiTrigger.Conditions>
<Setter TargetName="Expander" Property="Content" Value="{Binding Source={StaticResource Minus}, Converter={StaticResource ToRed}, ConverterParameter=CONVERTtview2}"/>
<Setter TargetName="Expander" Property="Background" Value="LightSkyBlue"/>
<Setter TargetName="BrdBackground" Property="Background" Value="LightSkyBlue"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--STYLE/TEMPLATE FOR BUTTON-->
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<StackPanel>
<ContentControl Name="Temp_Content" Width="50" Height="50" Content="{StaticResource Plus}"/>
<ContentPresenter />
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Temp_Content" Property="Content" Value="{Binding Source={StaticResource Minus}, Converter={StaticResource ToRed}, ConverterParameter=CONVERTbtn}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Orientation="Horizontal">
<ContentControl Content="{DynamicResource Plus}" Width="50" Height="50" Margin="10"/>
<ContentControl Content="{DynamicResource Minus}" Width="50" Height="50" Margin="10"/>
<ContentControl Content="{Binding Source={StaticResource Plus}}" Width="50" Height="50" Margin="10"/>
<ContentControl Content="{Binding Source={StaticResource Minus}}" Width="50" Height="50" Margin="10"/>
<ContentControl Content="{Binding Source={StaticResource Plus}, Converter={StaticResource ToRed}}" Width="50" Height="50" Margin="10"/>
<ContentControl Content="{Binding Source={StaticResource Minus}, Converter={StaticResource ToRed}}" Width="50" Height="50" Margin="10"/>
</StackPanel>
<StackPanel Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Orientation="Horizontal">
<ContentControl Content="{x:Static icon:Icons.Plus}" Width="50" Height="50" Margin="10"/>
<ContentControl Content="{x:Static icon:Icons.Minus}" Width="50" Height="50" Margin="10"/>
<ContentControl Content="{Binding Source={x:Static icon:Icons.Plus}}" Width="50" Height="50" Margin="10"/>
<ContentControl Content="{Binding Source={x:Static icon:Icons.Minus}}" Width="50" Height="50" Margin="10"/>
<ContentControl Content="{Binding Source={x:Static icon:Icons.Plus}, Converter={StaticResource ToRed}}" Width="50" Height="50" Margin="10"/>
<ContentControl Content="{Binding Source={x:Static icon:Icons.Minus}, Converter={StaticResource ToRed}}" Width="50" Height="50" Margin="10"/>
</StackPanel>
<TreeView Grid.Row="2" Grid.Column="0" Width="200">
<TreeViewItem Header="Parent 1">
<TreeViewItem Header="Child 1"/>
<TreeViewItem Header="Child 2"/>
<TreeViewItem Header="Child 3"/>
<TreeViewItem Header="Child 4"/>
</TreeViewItem>
<TreeViewItem Header="Parent 2">
<TreeViewItem Header="Child 1"/>
<TreeViewItem Header="Child 2"/>
<TreeViewItem Header="Child 3"/>
<TreeViewItem Header="Child 4"/>
</TreeViewItem>
<TreeViewItem Header="Parent 3">
<TreeViewItem Header="Child 1"/>
<TreeViewItem Header="Child 2"/>
<TreeViewItem Header="Child 3"/>
<TreeViewItem Header="Child 4"/>
</TreeViewItem>
<TreeViewItem Header="Parent 4">
<TreeViewItem Header="Child 1"/>
<TreeViewItem Header="Child 2"/>
<TreeViewItem Header="Child 3"/>
<TreeViewItem Header="Child 4"/>
</TreeViewItem>
<TreeViewItem Header="Parent 5">
<TreeViewItem Header="Child 1"/>
<TreeViewItem Header="Child 2"/>
<TreeViewItem Header="Child 3"/>
<TreeViewItem Header="Child 4"/>
</TreeViewItem>
</TreeView>
<StackPanel Grid.Row="2" Grid.Column="1" HorizontalAlignment="Center">
<Button Content="Test"/>
<Button Content="Test 1"/>
</StackPanel>
<TextBox x:Name="Console" Grid.Row="2" Grid.Column="2" IsReadOnly="True"/>
</Grid>
</Window>
主窗口.xaml.cs
public partial class MainWindow
{
public MainWindow()
{
Application.Current.Resources.MergedDictionaries.Add(
Application.LoadComponent(new Uri("WpfAllPurposesTest;component/MyResources.xaml", UriKind.Relative)
) as ResourceDictionary);
InitializeComponent();
}
}
更新:當我寫這個問題時,我意識到這個問題在某種程度上是時間相關的?!?
如果我立即以某種方式使用觸發器,它們會起作用,但等待幾秒鍾它們不會
在下面的示例中,我等待了幾秒鍾(查找錄制的快捷方式):
當指向TreeViewItem
並且Background
變為藍色時,圖標消失。 中間的按鈕也沒有觸發器的圖標。
右側是來自轉換器的消息,顯示觸發了正確的觸發器,但轉換器沒有得到值。
在下面的示例中,我使用錄制快捷方式稍微快了一點:
在此示例中,父樹視圖項目正確顯示並且圖標也在更改,來自轉換器的消息也顯示該值不為空。
但是對於稍后觸發的第二個觸發器和按鈕它不起作用。
有誰知道為什么會發生這種情況或如何解決?
更新
消除所有不必要的焦點和混亂。
這個問題是關於部分的:
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter ... Value="{Binding Source={StaticResource PlusRed}}"/>
</Trigger>
</ControlTemplate.Triggers>
在ControlTemplate.Trigger
中使用帶有{Binding Source={StaticResource...
的Setter
時,如果您等待幾秒鍾,它只會在編譯后短暫讀取StaticResource
。 它不會讀取它。
我刪除了所有轉換器,問題仍然存在...
結論:
經過一些評論, @BionicCode的以下評論消除了混亂。
您所指的綁定是靜態的。 綁定旨在綁定到可以更改的值。 綁定將更新源襲擊者的目標一個 PropertyChanged 事件。 綁定並不意味着設置對對象的引用。 您為此目的使用 StaticResource(請參閱我的回答)
為了使用 Converter,我創建了一個到 StaticResource 的綁定,這當然不是本意。
在性能方面,你做的完全錯誤而且太貴了。 此外,您的樣式包含冗余元素,例如TreeViewItem
模板中的"TopBorder"
和錯誤的觸發邏輯。
正確的方法是在 XAML ResourceDictionary
中定義所有資源並使用StaticResource
標記來引用它們。 不要在這種情況下使用x:Static
。
您使元素變為紅色或更改其顏色的算法通常效率很低。 例如,您不應該遍歷圖標的可視化樹來更改每個元素的Background
——即使基於元素類型(這需要實現異味類型切換)。 您當前的算法甚至需要 XAML 元素反序列化/序列化。 換句話說,整體性能很差,這在這一點上是完全沒有必要的。
您可以在轉換器旁邊替換此邏輯,並通過正確使用數據綁定來簡化它。 這也將提高性能。
我假設TreeViewItem
擴展器的期望行為是
LightSkyBlue
Red
實現觸發器時,您必須為模板化元素提供默認狀態。
由於布爾變量的默認值以及擴展器的ToggleButton.IsChecked
屬性為false
,因此您應該根據折疊狀態設計模板。 然后定義觸發器以在狀態更改為展開時更改元素的外觀。 這減少了觸發器的數量並提高了可讀性。
定義您的圖標以允許動態着色,即填充和描邊。 這樣我們就可以通過數據綁定來設置這些屬性。
以下示例期望繪圖托管在ContentControl
(或派生類型,如Button
)中。 它使用ContentControl.Background
為圖標的背景(在本例中為Canvas.Background
)着色,並使用ContentControl.Foreground
為實際圖標繪圖的筆划着色。
為了實現這種行為,我們使用Bindig.RelativeSource
綁定到ContentControl
(稍后將在不同范圍內添加的父級):
<Viewbox x:Key="MinusIcon"
x:Shared="False"
Stretch="Uniform">
<Canvas Background="{Binding RelativeSource={RelativeSource AncestorType=ContentControl}, Path=Background}"
Width="32"
Height="32"
Clip="F1 M 0,0L 32,0L 32,32L 0,32L 0,0">
<Rectangle Width="19"
Height="19"
Canvas.Left="6.49999"
Canvas.Top="6.5"
Stretch="Fill"
StrokeMiterLimit="2.75"
Stroke="#FF575756" /> <!-- Static border color (gray) -->
<Rectangle Fill="{Binding RelativeSource={RelativeSource AncestorType=ContentControl}, Path=Foreground}"
Width="9"
Height="2"
Canvas.Left="11.5"
Canvas.Top="15"
Stretch="Fill" />
</Canvas>
</Viewbox>
<Viewbox x:Key="PlusIcon"
x:Shared="False"
Stretch="Uniform">
<Canvas Background="{Binding RelativeSource={RelativeSource AncestorType=ContentControl}, Path=Background}"
Width="32"
Height="32"
Clip="F1 M 0,0L 32,0L 32,32L 0,32L 0,0">
<Rectangle Width="19"
Height="19"
Canvas.Left="6.49999"
Canvas.Top="6.5"
Stretch="Fill"
StrokeMiterLimit="2.75"
Stroke="#FF575756" /> <!-- Static border color (gray) -->
<Path Fill="{Binding RelativeSource={RelativeSource AncestorType=ContentControl}, Path=Foreground}"
Width="9"
Height="9"
Canvas.Left="11.5"
Canvas.Top="11.5"
Stretch="Fill"
Data="F1 M 20.5,15L 17,15L 17,11.5L 15,11.5L 15,15L 11.5,15L 11.5,17L 15,17L 15,20.5L 17,20.5L 17,17L 20.5,17L 20.5,15 Z " />
</Canvas>
</Viewbox>
當您想使用動態圖標時,您可以將它們托管在任何ContentControl
中。 您使用StaticResource
標記來引用圖標資源。 你直接引用它(沒有Binding
到資源)。 例如
<Button Content="{StaticResource PlusIcon}" />
同樣,您定義默認狀態(如果是未單擊按鈕)並定義在狀態更改時修改元素的觸發器。 強烈建議使用VisualStateManager
而不是觸發器。
為了使答案在技術上盡可能簡單,以下示例使用觸發器。 它們會更改圖標的顏色和圖標本身(根據您的要求):
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<StackPanel>
<ContentControl x:Name="IconHost"
Foreground="LightSkyBlue"
Background="Transparent"
Content="{StaticResource PlusIcon}"
Width="50"
Height="50" />
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment" />
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="IconHost"
Property="Content"
Value="{StaticResource MinusIcon}" />
<Setter TargetName="IconHost"
Property="Foreground"
Value="Red" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
TreeViewItem
的ToggleButton
中使用動態圖標您可以使用第 2 步中的圖標,將它們托管在ContentControl
中。
以下片段顯示了如何將圖標與擴展器ToggleButton
一起使用。 您可以將ToggleButton.Content
的設置移動到Style
:
<ToggleButton x:Name="Expander"
Grid.Column="0"
Grid.Row="0"
Content="{StaticResource PlusIcon}"
Background="{TemplateBinding Background}"
Foreground="LightSkyBlue"
IsChecked="{TemplateBinding IsExpanded}"
ClickMode="Press"
Style="{DynamicResource TreeToggleButtonStyle}"
Visibility="Visible"
Margin="0,0,2,0" /> <!-- Consider to use {StaticResource TreeToggleButtonStyle} when possible -->
以下示例是TreeViewItem
樣式的改進版本。 它修復了不正確的觸發邏輯並突出顯示行為。
完整的邏輯完全在 XAML 中實現。 它使用Step 1
中定義的動態圖標和數據綁定來使綁定轉換器和擴展方法過時。
改進了布局,例如刪除了多余的"TopBorder"
,所有元素都綁定到模板化父級的TreeViewItem.Background
屬性以獲取當前背景突出顯示顏色(以減少觸發器設置器)。
然后完整的模板現在基於默認狀態,即折疊的樹節點。 Visibility
和Background
等所有屬性都進行了相應配置。
完整的TreeViewItem
樣式如下所示:
<Window>
<Window.Resources>
<!-- Minus icon -->
<Viewbox x:Key="MinusIcon"
x:Shared="False"
Stretch="Uniform">
<Canvas Width="32"
Height="32"
Clip="F1 M 0,0L 32,0L 32,32L 0,32L 0,0"
Background="{Binding RelativeSource={RelativeSource AncestorType=ContentControl}, Path=Background}">
<Rectangle Width="19"
Height="19"
Canvas.Left="6.49999"
Canvas.Top="6.5"
Stretch="Fill"
StrokeMiterLimit="2.75"
Stroke="#FF575756" />
<Rectangle Width="9"
Height="2"
Canvas.Left="11.5"
Canvas.Top="15"
Stretch="Fill"
Fill="{Binding RelativeSource={RelativeSource AncestorType=ContentControl}, Path=Foreground}" />
</Canvas>
</Viewbox>
<!-- Plus icon -->
<Viewbox x:Key="PlusIcon"
x:Shared="False"
Stretch="Uniform">
<Canvas Width="32"
Height="32"
Clip="F1 M 0,0L 32,0L 32,32L 0,32L 0,0"
Background="{Binding RelativeSource={RelativeSource AncestorType=ContentControl}, Path=Background}">
<Rectangle Width="19"
Height="19"
Canvas.Left="6.49999"
Canvas.Top="6.5"
Stretch="Fill"
StrokeMiterLimit="2.75"
Stroke="#FF575756" />
<Path Width="9"
Height="9"
Canvas.Left="11.5"
Canvas.Top="11.5"
Stretch="Fill"
Fill="{Binding RelativeSource={RelativeSource AncestorType=ContentControl}, Path=Foreground}"
Data="F1 M 20.5,15L 17,15L 17,11.5L 15,11.5L 15,15L 11.5,15L 11.5,17L 15,17L 15,20.5L 17,20.5L 17,17L 20.5,17L 20.5,15 Z " />
</Canvas>
</Viewbox>
<!-- Button style -->
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<StackPanel>
<ContentControl x:Name="IconHost"
Width="50"
Height="50"
Foreground="LightSkyBlue"
Background="Transparent"
Content="{StaticResource Plus}" />
<ContentPresenter />
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="IconHost"
Property="Content"
Value="{StaticResource Minus}" />
<Setter TargetName="IconHost"
Property="Foreground"
Value="Red" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<TreeView>
<!-- TreeViewItem style -->
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="FocusVisualStyle"
Value="{x:Null}" />
<Setter Property="Background"
Value="White" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TreeViewItem">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition x:Name="RowToHide"
Height="20" />
<RowDefinition />
</Grid.RowDefinitions>
<Border Name="BrdBackground"
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="3"
Background="{TemplateBinding Background}"
BorderBrush="Gray"
BorderThickness="0,0,0,0" />
<!--VERTICAL LINE-->
<Border Name="VerticalLine"
Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="0">
<Path Data="M 5 1 L 5 9"
StrokeThickness="0.5"
Stroke="Black"
Stretch="Fill"
VerticalAlignment="Stretch"
HorizontalAlignment="Center" />
</Border>
<!--HORIZONTAL LINE-->
<Border Grid.Row="0"
Grid.Column="0"
Width="25">
<Path Data="M 12 12 L 25 12"
StrokeThickness="0.5"
Stroke="Black"
Stretch="None" />
</Border>
<!--EXPANDER / PLUS / MINUS ICON-->
<ToggleButton x:Name="Expander"
Grid.Column="0"
Grid.Row="0"
Content="{StaticResource PlusIcon}"
Background="{TemplateBinding Background}"
Foreground="LightSkyBlue"
IsChecked="{TemplateBinding IsExpanded}"
ClickMode="Press"
Style="{DynamicResource TreeToggleButtonStyle}"
Visibility="Visible"
Margin="0,0,2,0" /> <!-- Consider to use {StaticResource TreeToggleButtonStyle} when possible (to improve performance) -->
<!--TREE VIEW ITEM HEADER -->
<ContentPresenter x:Name="PART_Header"
Grid.Column="1"
Grid.Row="0"
ContentSource="Header"
HorizontalAlignment="Left" />
<!--TREE VIEW ITEM CHILDREN HOST-->
<ItemsPresenter x:Name="ItemsHost"
Grid.Row="1"
Grid.Column="1"
Grid.ColumnSpan="2"
Visibility="Collapsed" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="HasItems"
Value="false">
<Setter TargetName="Expander"
Property="Visibility"
Value="Collapsed" />
</Trigger>
<Trigger Property="IsExpanded"
Value="True">
<Setter TargetName="ItemsHost"
Property="Visibility"
Value="Visible" />
<Setter TargetName="Expander"
Property="Content"
Value="{StaticResource MinusIcon}" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Setter Property="Background"
Value="LightSkyBlue" />
<Setter TargetName="Expander"
Property="Foreground"
Value="Red" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
</Window>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.