Заменить часть шаблона по умолчанию в WPF
есть ли способ "лучшей практики" заменить часть шаблона по умолчанию. Текущий вариант использования - древовидная структура. По умолчанию древовидная структура имеет такие маленькие треугольные фигуры, которые расширяются и сжимаются.
Я знаю, как их заменить, если я заменю весь шаблон управления, как показано в приведенном ниже коде. Я не уверен, есть ли способ "сохранить все умолчания, просто измените XY". Это не стиль, мне в основном нужно заменить часть существующего шаблона управления.
Чтобы проиллюстрировать это, взгляните на следующий XAML. Первый меньший блок - это соответствующий XAML, который я хочу адаптировать.
Большая вторая и третья части - это в основном копия шаблонов по умолчанию, только для администрирования "измененной" части с самого начала.
Есть ли лучший способ сделать это, сохраняя длинный и запутывающий XAML во второй половине?
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<Style x:Key="ExpandCollapseToggleStyle" TargetType="ToggleButton">
<Setter Property="Focusable" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid
Width="15"
Height="13"
Background="Transparent">
<Path x:Name="ExpandPath"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Margin="1,1,1,1"
Fill="Black"
Data="M 4 0 L 8 4 L 4 8 Z"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked"
Value="True">
<Setter Property="Data"
TargetName="ExpandPath"
Value="M 0 4 L 8 4 L 4 8 Z"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TreeViewItem}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="19"
Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<ToggleButton x:Name="Expander"
Style="{StaticResource ExpandCollapseToggleStyle}"
IsChecked="{Binding Path=IsExpanded,
RelativeSource={RelativeSource TemplatedParent}}"
ClickMode="Press"/>
<Border Name="Bd"
Grid.Column="1"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}">
<ContentPresenter x:Name="PART_Header"
ContentSource="Header"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>
</Border>
<ItemsPresenter x:Name="ItemsHost"
Grid.Row="1"
Grid.Column="1"
Grid.ColumnSpan="2"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded"
Value="false">
<Setter TargetName="ItemsHost"
Property="Visibility"
Value="Collapsed"/>
</Trigger>
<Trigger Property="HasItems"
Value="false">
<Setter TargetName="Expander"
Property="Visibility"
Value="Hidden"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="HasHeader"
Value="false"/>
<Condition Property="Width"
Value="Auto"/>
</MultiTrigger.Conditions>
<Setter TargetName="PART_Header"
Property="MinWidth"
Value="75"/>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="HasHeader"
Value="false"/>
<Condition Property="Height"
Value="Auto"/>
</MultiTrigger.Conditions>
<Setter TargetName="PART_Header"
Property="MinHeight"
Value="19"/>
</MultiTrigger>
<Trigger Property="IsSelected"
Value="true">
<Setter TargetName="Bd"
Property="Background"
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 TargetName="Bd"
Property="Background"
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>
Ответы
Ответ 1
К сожалению, я думаю, вам нужно заменить весь шаблон:
Из MSDN: http://msdn.microsoft.com/en-us/library/aa970773.aspx
Элементы управления в представлении Windows Фонд (WPF) имеет ControlTemplate, который содержит визуальное дерево этого контроля. Ты можешь изменить структуру и внешний вид контроль путем изменения ControlTemplate этого элемента управления. Там не может заменить только часть визуальное дерево элемента управления; изменить визуальное дерево элемента управления, которое вы должны установите свойство Template контроль за его новым и полным ControlTemplate.
Ответ 2
На самом деле есть способ (вроде). Вы можете создать свой собственный элемент управления и переопределить функцию OnApplyTemplate, чтобы динамически изменять стиль.
Например, создайте собственный пользовательский элемент управления (я делаю это в silverlight, но все равно полагаю):
namespace SilverlightClassLibrary1
{
public class MyButton: Button
{
public string BackgroundColor { get; set; }
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
if (BackgroundColor != null)
{
Rectangle r = this.GetTemplateChild("BackgroundGradient") as Rectangle;
if (r != null)
{
r.Fill = new SolidColorBrush(Color.FromArgb(255,
Convert.ToByte(BackgroundColor.Substring(1,2),16),
Convert.ToByte(BackgroundColor.Substring(3,2),16),
Convert.ToByte(BackgroundColor.Substring(5,2),16)));
}
}
}
}
}
Интересной частью является метод GetTemplateChild, который ищет элемент управления Rectangle с именем "BackgroundGradient". (BTW, проще, если вы определяете настраиваемые элементы управления в отдельном проекте, поэтому создайте новый проект библиотеки Silverlight, если вы еще этого не сделали и не поместили его в этот проект.)
Затем добавьте новый файл словаря ресурсов и переопределите шаблон управления и убедитесь, что у вас есть прямоугольник с именем "BackgroundGradient". В этом случае мы используем стандартный шаблон управления кнопками, который я немного сократил:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:custom="clr-namespace:SilverlightClassLibrary1;assembly=SilverlightClassLibrary1">
<Style TargetType="custom:MyButton">
<Setter Property="Background" Value="#FF1F3B53"/>
<Setter Property="Foreground" Value="#FF000000"/>
<Setter Property="Padding" Value="3"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFA3AEB9" Offset="0"/>
<GradientStop Color="#FF8399A9" Offset="0.375"/>
<GradientStop Color="#FF718597" Offset="0.375"/>
<GradientStop Color="#FF617584" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<Border x:Name="Background" CornerRadius="3" Background="White" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}">
<Grid Background="{TemplateBinding Background}" Margin="1">
<Border Opacity="0" x:Name="BackgroundAnimation" Background="#FF448DCA" />
<Rectangle x:Name="BackgroundGradient" Fill="White" >
</Rectangle>
</Grid>
</Border>
<ContentPresenter
x:Name="contentPresenter"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"/>
<Rectangle x:Name="DisabledVisualElement" RadiusX="3" RadiusY="3" Fill="#FFFFFFFF" Opacity="0" IsHitTestVisible="false" />
<Rectangle x:Name="FocusVisualElement" RadiusX="2" RadiusY="2" Margin="1" Stroke="#FF6DBDD1" StrokeThickness="1" Opacity="0" IsHitTestVisible="false" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Итак, теперь вы можете объявить элемент управления кнопкой и переопределить стиль, если хотите:
<UserControl x:Class="SilverlightApplication1.MainPage"
...
xmlns:custom="clr-namespace:SilverlightClassLibrary1;assembly=SilverlightClassLibrary1">
<custom:MyButton>Normal Button 1</custom:MyButton>
<custom:MyButton>Normal Button 2</custom:MyButton>
<custom:MyButton BackgroundColor="#8888cc">Customized Background</custom:MyButton>
Я предполагаю, что вы можете стать еще более умным и пройти через имя ресурса или имя стиля и загрузить его динамически.
Затем вам необходимо включить свой файл ресурсов как часть вашего приложения:
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SilverlightApplication1.App"
>
<Application.Resources>
<ResourceDictionary >
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary1.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
и вы увидите изменения пользовательского свойства в своем дизайне XAML.
Ответ 3
Я бы пересмотрел ваш шаблон как пользовательский элемент управления, используя ContentPresenters в качестве заполнителей для элементов, которые будут меняться.
Чтобы использовать эти заполнители, вы должны связать их с зависимыми свойствами.
Отметьте это сообщение, чтобы узнать, как это делается.
http://www.codeproject.com/Articles/82464/How-to-Embed-Arbitrary-Content-in-a-WPF-Control
"Использование пользовательского контроля" объясняет мой подход