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

标签 c# wpf xaml

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

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

编辑结束。

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

首先,我只是尝试创建一个包含堆栈面板的 UserControl,该堆栈面板具有用于包含元素(例如 Button)的已定义样式(在 xaml 中)。此用户控件包含

<ContentPresenter />

在 xaml 中。使用此方法无法命名包含的元素。例如:

<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);

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

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

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

它是如何在第三方的东西中实现的?

最佳答案

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

第 1 步:

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

    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>

第 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>

看看我如何使用 TemplateBinding 表达式来定义 ContentPresenter 的内容将由 Button 属性定义在 ReusableContainer 中。

另请注意我是如何将 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>

关于c# - 创建自定义控件的正确方法是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20333657/

相关文章:

c# - 异步调用后丢失变量

silverlight - WP7 ScrollViewer - 将查看器留在滚动到的位置

wpf - 将 WPF 日期选择器的默认日期设置为当前日期

.net - 绑定(bind)到数组元素

c# - 焦点标签显示虚线作为边框

c# - 如何在 Silverlight 中为事物制作可重复的背景?

c# - 制作C#项目安装包

c# - 本地实现的 Azure 功能无法在云端运行

c# - Azure .NET MVC 核心应用程序 : User not being redirected upon form submission

wpf - ListBoxItem.Parent 不返回任何内容,也无法通过 VisualTreeHelper.GetParent 获取它