创建自定义控件的正确方法是什么

时间:2013-12-02 16:57:55

标签: c# wpf xaml

编辑(如评论:XY问题) - 问题:

我想创建自己的控件,它具有预定义的特殊元素的样式和位置(Button,...),但一般来说,所有内容都应该放在我的自定义控件中。在我的情况下,自定义控件只是一个“菜单栏”,应该能够在“GUI代码”中的任何地方使用 - 但是没有必要在那里。但使用时,它应该是相同的风格和行为。一种风格 - 我认为 - 还不够,因为此菜单栏中还有预定义的元素(例如,帮助已经在菜单栏中)

编辑结束。

我想在WPF中构建一个自定义控件(只是一个特殊的堆栈面板),具有以下要求: 可以用作xaml中的任何其他控件 已为自定义控件

中的控件定义样式

首先,我只是尝试创建一个UserControl,其中包含一个带有已定义样式(在xaml中)的stackpanel,用于包含元素(例如Button)。

包含此UserControl
<ContentPresenter />

在xaml中。使用此方法,无法命名包含元素。 E.g:

<mynamespace:MyStackPanel>
  <Button Name="w00t">This does not work!</Button>
</mynamespace:MyStackPanel>

接下来尝试创建一个“真正的”自定义控件。这个自定义控件只是一个没有xaml的类。代码很简单。类继承自UserControl并且只包含:

StackPanel sp = new StackPanel();
sp.Children.Add(new ContentPresenter());
this.AddChild(sp);

Woooohoooo,现在可以命名包含元素。但仍然是一个大问题:如何定义样式?

我可以在ResourceDictionary中为我自己的自定义控件定义样式。但我必须将ResourceDictionary添加到全局(App.xaml)资源中。然后我只能为我的自定义控件定义样式 - 而不是包含元素? - 但无论如何......这样做只是感觉不对劲!

所以主要的问题是:创建自定义控件的“正确”方法是什么,可以像任何其他控件一样在xaml中使用?如果第二种方式是正确的方法 - 如何设置样式就像我在xaml中那样(例如,这个元素中的每个Button都有一个特殊的样式)并且它是一个“全局”的ResourceDictionary?

如何在第三方内容中实施?

1 个答案:

答案 0 :(得分:2)

好的,我为你做了一个例子,涉及Custom Controls(与UserControl s相反)

第1步:

创建一个从ContentControl派生的新类(仅代码,没有XAML)(或任何具有类似于您需要的行为的UI元素)

    public class ReusableContainer : ContentControl
    {
        public static readonly DependencyProperty ButtonProperty = DependencyProperty.Register("Button", typeof(Button), typeof(ReusableContainer), new PropertyMetadata(default(Button)));

        public Button Button
        {
            get { return (Button)GetValue(ButtonProperty); }
            set { SetValue(ButtonProperty, value); }
        }
    }

在这里看看我如何将Button属性定义为DependencyProperty。您可以为自定义控件中需要的“内容占位符”添加更多DP。

第2步:

在单独的ResourceDictionary

中为容器内的UI元素预定义样式

CustomStyles.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Style TargetType="Button">
        <Setter Property="Background" Value="Green"/>
    </Style>
</ResourceDictionary>
app.xaml中的

第3步:,为ReusableContainer定义应用程序范围的样式,该样式定义了它的模板:

<Application x:Class="WpfApplication14.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:WpfApplication14"
             StartupUri="MainWindow.xaml">
    <Application.Resources>

        <Style TargetType="{x:Type local:ReusableContainer}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type local:ReusableContainer}">
                        <ControlTemplate.Resources>
                            <ResourceDictionary Source="CustomStyles.xaml"/>
                        </ControlTemplate.Resources>

                        <ContentPresenter Content="{TemplateBinding Button}"/>

                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Application.Resources>
</Application>

了解我如何使用TemplateBinding表达式来定义ContentPresenter的内容将由Button中的ReusableContainer属性定义。< / p>

另请注意我如何将CustomStyles.xaml中的资源添加到ControlTemplate.Resources集合中。这使得这些资源可用于模板中的所有UI元素。

第4步:

将ReusableContainer放在窗口中:

<Window x:Class="WpfApplication14.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication14"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <local:ReusableContainer>
            <local:ReusableContainer.Button>
                <Button x:Name="Button1" Content="Hello! Button 1"/>
            </local:ReusableContainer.Button>
        </local:ReusableContainer>

        <local:ReusableContainer>
            <local:ReusableContainer.Button>
                <Button x:Name="Button2" Content="Hello! Button 2"/>
            </local:ReusableContainer.Button>
        </local:ReusableContainer>

        <local:ReusableContainer>
            <local:ReusableContainer.Button>
                <Button x:Name="Button3" Content="Hello! Button 3"/>
            </local:ReusableContainer.Button>
        </local:ReusableContainer>
    </StackPanel>
</Window>