【问题标题】:How to restyle a control nested in a custom control?如何重新设置嵌套在自定义控件中的控件?
【发布时间】:2009-02-24 10:48:52
【问题描述】:

假设您正在 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

如果在自定义控件定义中,两个按钮具有相同的样式,引用自定义控件中定义的样式,并且您想重新设置它们的样式,那么解决此问题的最佳方法是什么?

提前感谢您的所有帮助

【问题讨论】:

    标签: wpf custom-controls styling


    【解决方案1】:

    您可以在自定义控件中定义 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); }
        }
      }
    }
    

    最好将这两个属性实现为依赖属性,因为这将使它们符合标准 WPF 控件中的其他 Style 属性。

    现在您可以像在任何 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>
    

    或者,您可以让 2 个按钮通过在您绑定到两个内部控件的 Style 属性的自定义控件中公开单个属性来共享相同的样式。

    更新

    您不必将 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));
          }
        }
      }
    }
    

    【讨论】:

    • Ciao Enrico,谢谢您的回答。您的解决方案肯定会运作良好,但我想知道即使没有将样式定义为依赖属性,是否也能达到我的目标。我想在 XAML 中将两种样式定义为静态资源 (x:Key=...) 并在应用程序中扩展
    • 谢谢恩里科。即使没有在自定义控件中定义任何专用属性,您是否知道这是否可能会覆盖样式。我的意思是只在默认 xaml 中创建两个样式作为静态资源?
    猜你喜欢
    • 2019-04-11
    • 1970-01-01
    • 2011-03-17
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-24
    相关资源
    最近更新 更多