Заменить часть шаблона по умолчанию в WPF - PullRequest
29 голосов
/ 08 февраля 2010

Есть ли какой-либо "лучший метод", способ заменить часть шаблона по умолчанию. Текущий вариант использования - это древовидная структура. По умолчанию древовидная структура имеет этот маленький треугольник для расширения и свертывания.

Я знаю, как заменить их, если я заменю весь шаблон элемента управления, как показано в коде ниже. Я не уверен, есть ли способ «сохранить все настройки по умолчанию, просто измените 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>

Ответы [ 3 ]

23 голосов
/ 08 марта 2010

К сожалению, я думаю, вы должны заменить весь шаблон:

Из MSDN: http://msdn.microsoft.com/en-us/library/aa970773.aspx

Элементы управления в презентации Windows Фонд (WPF) имеет ControlTemplate, который содержит визуальное дерево этого элемента управления. Вы можете изменить структуру и внешний вид контроль путем изменения ControlTemplate этого элемента управления. Там нет способа заменить только часть визуальное дерево элемента управления; изменить визуальное дерево элемента управления вы должны установить свойство шаблона контроль до нового и полного ControlTemplate.

10 голосов
/ 14 октября 2013

На самом деле есть способ (вроде). Вы можете создать свой собственный пользовательский элемент управления и переопределить функцию 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". (Кстати, проще определить пользовательские элементы управления в отдельном проекте, поэтому создайте новый проект «Библиотека классов 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 голосов
/ 27 ноября 2014

Я бы изменил ваш шаблон на пользовательский элемент управления, используя ContentPresenters в качестве заполнителей для изменяемых элементов.

Чтобы использовать эти заполнители, вы должны связать их со свойствами зависимостей.

Проверьте это сообщение, чтобы увидеть, как это делается

http://www.codeproject.com/Articles/82464/How-to-Embed-Arbitrary-Content-in-a-WPF-Control

«Использование пользовательского контроля» объясняет мой подход

...