Как изменить стиль элемента управления, вложенного в пользовательский элемент управления? - PullRequest
1 голос
/ 24 февраля 2009

Предположим, что вы разрабатываете пользовательский элемент управления в WPF, который внутренне содержит некоторые другие основные элементы управления. Для простоты предположим, что он содержит 2 кнопки .

Теперь вы хотите использовать этот пользовательский элемент управления в своем приложении, но вы хотите рестайлировать немного.

ДЕЛО 1

Если в определении пользовательского элемента управления обе кнопки имеют одинаковый стиль (wpf по умолчанию) и вы хотите изменить стиль обеих, это должно быть легко:

<mc:MyControl>
   <mc:MyControl.Resources>
      <Style x:Key={x:Type Button}, TargetType={x:Type Button}>
         <!-- Insert the new style here -->
      </Style>
   </mc:MyControl.Resources>
<mc:MyControl>

СЛУЧАЙ 2

Если в определении пользовательского элемента управления обе кнопки имеют одинаковый стиль (wpf по умолчанию), но вы хотите изменить их стиль двумя разными стилями , как лучше всего решить эту проблему?

СЛУЧАЙ 3

Если в определении пользовательского элемента управления обе кнопки имеют одинаковый стиль, , который относится к стилю, определенному внутри пользовательского элемента управления , и вы хотите изменить их стиль, как лучше всего решить эту проблему?

Заранее спасибо за помощь

1 Ответ

5 голосов
/ 03 марта 2009

Вы можете определить 2 различных свойства Style в своем пользовательском элементе управления и связать их со свойством Style отдельных кнопок , что позволит клиентам независимо устанавливать стиль для двух элементов управления друг друга.

XAML-файл:

<UserControl x:Class="MyNamespace.MyControl"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Name="MyControl">
  <StackPanel>
    <Button Name="FirstButton"
            Style={Binding ElementName=MyControl, Path=FirstButtonStyle}
            Content="First Button" />
    <Button Name="SecondButton"
            Style={Binding ElementName=MyControl, Path=SecondButtonStyle}
            Content="Second Button" />
  </StackPanel>
</UserControl>

Файл с выделенным кодом:

using System;
using System.Windows;
using System.Windows.Controls;

namespace MyNamespace
{
  [StyleTypedProperty(
  Property = "FirstButtonStyle",
  StyleTargetType = typeof(Button))]
  [StyleTypedProperty(
  Property = "SecondButtonStyle",
  StyleTargetType = typeof(Button))]
  public partial class MyControl : UserControl
  {
    public static readonly DependencyProperty FirstButtonStyleProperty =
      DependencyProperty.Register(
        "FirstButtonStyle",
        typeof(Style),
        typeof(MyControl)
      );

    public Style FirstButtonStyle
    {          
      get { return (Style)GetValue(FirstButtonStyleProperty); }
      set { SetValue(FirstButtonStyleProperty, value); }
    }


    public static readonly DependencyProperty SecondButtonStyleProperty =
      DependencyProperty.Register(
        "SecondButtonStyle",
        typeof(Style),
        typeof(MyControl)
      );

    public Style SecondButtonStyle
    {          
      get { return (Style)GetValue(SecondButtonStyleProperty); }
      set { SetValue(SecondButtonStyleProperty, value); }
    }
  }
}

Рекомендуется реализовать эти 2 свойства как свойства зависимостей, так как они приведут их в соответствие с другими свойствами стиля в стандартных элементах управления WPF.

Теперь вы можете установить стиль кнопок, как в любом элементе управления WPF:

<Window 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:local="clr-namespace:MyNamespace"
  Title="MyControl Sample" 
  Height="300" 
  Width="300">
  <Window.Resources>
    <Style x:Key="GreenButton" TargetType="{x:Type Button}">
      <Setter Property="Background" Value="Green" />
    </Style>
    <Style x:Key="RedButton" TargetType="{x:Type Button}">
      <Setter Property="Background" Value="Red" />
    </Style>
  </Windows.Resources>
  <StackPanel>
    <local:MyControl FirstButtonStyle="{StaticResource GreenButton}"
                     SecondButtonStyle="{StaticResource RedButton}" />
  </StackPanel>
</Window>

В качестве альтернативы вы можете использовать две кнопки для совместного использования одного и того же стиля, предоставив в свой пользовательский элемент управления одно свойство , которое вы связываете со свойством Style обоих внутренних элементов управления.

UPDATE

Вам не нужно определять свойства FirstButtonStyle и SecondButtonStyle в качестве свойств зависимости. Важно то, что внутренние привязки к свойствам кнопок Style обновляются при изменении их значения. Это можно сделать, внедрив интерфейс INotifyPropertyChanged в свой пользовательский элемент управления и вызвав событие OnPropertyChanged в установщиках свойств.

Вы также можете назначить «стиль по умолчанию» для 2 свойств в конструкторе пользовательского элемента управления. Вот пример:

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;

namespace MyNamespace
{
  [StyleTypedProperty(
  Property = "FirstButtonStyle",
  StyleTargetType = typeof(Button))]
  [StyleTypedProperty(
  Property = "SecondButtonStyle",
  StyleTargetType = typeof(Button))]
  public partial class MyControl : UserControl, INotifyPropertyChanged
  {
    private Style firstButtonStyle;
    private Style secondButtonStyle;

    public MyControl()
    {
      Style defaultStyle = new Style();
      // assign property setters to customize the style

      this.FirstButtonStyle = defaultStyle;
      this.SecondButtonStyle = defaultStyle; 
    }

    public Style FirstButtonStyle
    {          
      get { return firstButtonStyle; }
      set
      {
         firstButtonStyle = value;
         OnPropertyChanged("FirstButtonStyle");
      }
    }

    public Style SecondButtonStyle
    {          
      get { return secondButtonStyle; }
      set
      {
         secondButtonStyle = value;
         OnPropertyChanged("SecondButtonStyle");
      }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
      if (PropertyChanged != null)
      {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
      }
    }
  }
}
...