简体   繁体   English

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

[英]What's the correct way to create a custom control

Edit (as commented: XY-Problem) - Problem: 编辑(如评论:XY问题) - 问题:

I want to create my own control which has predefined styles and positions for special elements (Button,...), but in general everything should be able to be placed inside my custom control. 我想创建我自己的控件,它具有预定义的样式和特殊元素的位置(Button,...),但一般来说一切都应该能够放在我的自定义控件中。 The custom control in my case is just a "menubar" which should be able to be used anywhere in the "GUI code" - but there is no need it has to be there. 在我的情况下,自定义控件只是一个“菜单栏”,应该能够在“GUI代码”中的任何地方使用 - 但是没有必要在那里。 But when it is used it should be the same style and behavior everywhere. 但是它被使用 ,它应该是相同的风格和行为。 A style is - I think - not enough, because there are also predefined elements in this menubar (eg Help is already in menubar) 一种风格 - 我认为 - 还不够,因为此菜单栏中还有预定义的元素(例如,帮助已经在菜单栏中)

Edit end. 编辑结束。

I want to build a custom control (just a special stackpanel) in WPF with the following requirements: can be used as any other control within a xaml has defined styles for controls within the custom control 我想在WPF中构建一个自定义控件(只是一个特殊的堆栈面板),具有以下要求:可以用作xaml中的任何其他控件,为自定义控件中的控件定义样式

First I simply tried to create a UserControl containing a stackpanel with defined styles (in the xaml) for containing elements (eg Button). 首先,我只是尝试创建一个UserControl,其中包含一个带有已定义样式(在xaml中)的stackpanel,用于包含元素(例如Button)。 This UserControl contained the 这个UserControl包含了

<ContentPresenter />

in the xaml. 在xaml。 With this method it is not possible to name the containing elements. 使用此方法,无法命名包含元素。 Eg: 例如:

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

Next try was to create a "real" custom control. 接下来尝试创建一个“真正的”自定义控件。 This custom control is just a class without the xaml. 这个自定义控件只是一个没有xaml的类。 Code is very simple. 代码很简单。 Class inherits from UserControl and just contains: 类继承自UserControl并且只包含:

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

Woooohoooo, now it's possible to name the containing elements. Woooohoooo,现在可以命名包含元素。 But still a big problem: How to define the styles? 但仍然是一个大问题:如何定义样式?

I could define the style for my very own custom control in a ResourceDictionary. 我可以在ResourceDictionary中为我自己的自定义控件定义样式。 But i have to add the ResourceDictionary to the global (App.xaml) Resources. 但我必须将ResourceDictionary添加到全局(App.xaml)资源中。 And then I can define styles only for my custom control - not for the containing elements? 然后我只能为我的自定义控件定义样式 - 而不是包含元素? - But anyway... doing it like this just feels wrong! - 但无论如何......这样做只是感觉不对劲!

So the main question is: WHAT is the "correct" way of creating a custom control which can be used in xaml like any other control? 所以主要的问题是:创建自定义控件的“正确”方法是什么,可以像任何其他控件一样在xaml中使用? If the second way is the correct way - how is it possible to set the style like I do it in a xaml (eg every Button in this element has a special style) and has it to be a "global" ResourceDictionary? 如果第二种方式是正确的方式 - 如何设置样式就像我在xaml中那样(例如,这个元素中的每个Button都有一个特殊的样式)并且它是一个“全局”的ResourceDictionary?

How is it implemented in third-party stuff? 它是如何在第三方的东西中实现的?

Ok I made an example for you, which involves Custom Controls (as Opposed to UserControl s) 好的我为你做了一个例子,它涉及Custom Controls (与UserControl相反)

Step 1: 第1步:

Create a new class (code only, no XAML) derived from ContentControl (or whatever UI element that has a behavior similar to what you need) 创建一个从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); }
        }
    }

See how I'm defining the Button property as a DependencyProperty here. 看看我如何在这里将Button属性定义为DependencyProperty。 You can add more DPs for whatever "content placeholders" that you need in your custom control. 您可以为自定义控件中所需的“内容占位符”添加更多DP。

Step 2: 第2步:

Have your predefined Styles for the UI elements inside the container in a separate ResourceDictionary : 在单独的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>

Step 3: in app.xaml , define an application-wide style for the ReusableContainer , which defines it's template: 第3步:app.xaml ,为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>

See how I'm using the TemplateBinding expression to define that the ContentPresenter 's content is going to be defined by the Button property in the ReusableContainer . 了解我如何使用TemplateBinding表达式来定义ContentPresenter的内容将由ReusableContainerButton属性定义。

Also notice how I'm Adding the Resources in CustomStyles.xaml to the ControlTemplate.Resources collection. 另请注意我是如何将CustomStyles.xaml的资源添加到ControlTemplate.Resources集合中的。 This makes these resources available to all UI elements inside the Template. 这使得这些资源可用于模板内的所有UI元素。

Step 4: 第4步:

Place your ReusableContainer in a Window: 将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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM