简体   繁体   English

如何强制某些UserControl设计

[英]How to force a certain UserControl design

I am writing a Base UserControl, that will be inherited by a bunch of other UserControls. 我正在编写一个基本的UserControl,它将被一堆其他UserControl继承。 I need to enforce a certain design for all these descendant controls (eg a couple of buttons must be on the top along with a label or two). 我需要为所有这些后代控件强制执行某种设计(例如,几个按钮必须在顶部以及一个或两个标签)。

The rest of the descendant UserControl area is free to have whatever on it. 子孙UserControl区域的其余部分可以自由放置任何内容。

Initially, I thought that I could just plop a Panel onto the Base UserControl, set the Dock=Fill and the designer of the descendant control would be forced to add all the UI into this said panel. 最初,我认为我可以将面板放到基本UserControl上,设置Dock = Fill,后代控件的设计者将被迫将所有UI添加到该面板中。 Then, I could resize the panel to my content. 然后,我可以将面板调整为适合我的内容的大小。

But that is not the case - when you drop a control (say a GridView) onto the descendant UserControl, it adds it to the .Controls collection of the descendant user control, not the Panel I added. 事实并非如此-将控件(例如GridView)放到后代UserControl上时,它将它添加到后代用户控件的.Controls集合中,而不是我添加的Panel中。

Is there a way to force a certain layout from the Base user control? 有没有办法从基本用户控件中强制某种布局?

The short answer is "Yes"... However to get this behavior delves into the ugly world of writing your own designers which you have to associate with the each control which will need to inherit the special placement into the content panels.. 简短的答案是“是”。但是,要使这种行为深入研究编写自己的设计器的丑陋世界,您必须将其与每个控件相关联,这需要将特殊位置继承到内容面板中。

The following link should be a good starting point as it gives an overview of what needs to be done as well as provides sample code. 以下链接应该是一个很好的起点,因为它概述了需要完成的工作并提供了示例代码。

http://support.microsoft.com/?id=813808 http://support.microsoft.com/?id=813808

Be warned, however, this is not a trivial task. 被警告,但是,这不是一件容易的事。 And there is a lot of code (30+ files) to sift through in order to understand how to implement a designer. 并且有很多代码(30多个文件)可供筛选,以了解如何实现设计器。 It's been about 2 years since I have tried this. 自从我尝试过大约两年了。

On the other hand, have you considered changing your design to have a single parent control which has the labels and buttons, and which populates the content area with the appropriate child control(s)? 另一方面,您是否考虑过将设计更改为具有一个带有标签和按钮的单个父控件,并使用适当的子控件填充内容区域? Perhaps even having your child controls for the content area implement a specific interface to guarantee a contract so that the parent can interact with them without having to know a specific class name? 也许甚至让您的孩子对内容区域进行控制都实现了一个特定的接口来保证合同,以便家长可以与他们进行交互而不必知道特定的类名?

AngryHacker - AngryHacker-

I went off thinking this was to be very easy, and found myself embarking on an interesting journey into WinForm design-time land. 我以为这很容易,然后发现自己踏上了进入WinForm设计时领域的有趣旅程。 This is definitely not as easy as it was in VB6 :-) . 这绝对不像在VB6中那么容易:-)。

Anyhow, after a bit of research, I found a number of references to a method called EnableDesignMode() . 无论如何,经过一番研究,我发现了许多对名为EnableDesignMode()的方法的引用。 However, this is not directly accessible from a WinForm component. 但是,这不能从WinForm组件直接访问。 This has to be called from a class that subclasses ParentControlDesigner , which is injected into the UserControl via a Designer attribute. 这必须从ParentControlDesigner子类的类中调用,该类通过Designer属性注入到UserControl中。 In this project, I have called the subclass ButtonBarDesigner , and have overridden the Initialize() method, which allows me to tell the designer that the component ButtonBar has a child component fillPanel which can be accessed via the public property "FillPanel". 在这个项目中,我调用了子类ButtonBarDesigner ,并且重写了Initialize()方法,该方法使我可以告诉设计器ButtonBar组件具有子组件fillPanel ,可以通过公共属性“ FillPanel”对其进行访问。

At this point, it seemed to be working. 在这一点上,它似乎正在工作。 I managed to drop a control onto the ButtonBar and it was appearing in the fill panel. 我设法将一个控件放到ButtonBar上,它出现在填充面板中。 However, if you saved the form, and then reloaded it, it turned out that the control was instantiated, but not placed in the ButtonBar control. 但是,如果您保存了表单,然后重新加载了表单,事实证明该控件已实例化,但未放置在ButtonBar控件中。 It seems that there was one sneaky last bit which the documentation for EnableDesignMode() conveniently leaves out. 似乎有一点偷偷摸摸的地方, EnableDesignMode()的文档方便地省略了这一点。 You need to have the DesignerSerializationVisibility attribute on the FillPanel property. 您需要在FillPanel属性上具有DesignerSerializationVisibility属性。 Adding this attribute makes this work. 添加此属性即可完成这项工作。

You need a reference to System.Design in your project for the design time stuff to work. 您需要在项目中引用System.Design才能使设计时工作正常。

The following code is for the putative base class, ButtonBar: 以下代码用于假定的基类ButtonBar:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using System.Threading;

namespace ForceUserControl
{
    [Designer(typeof(ButtonBarDesigner))]
    public partial class ButtonBar : UserControl
    {
        public ButtonBar()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Returns inner panel.
        /// </summary>
        /// <remarks>Should allow persistence.</remarks>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public Panel FillPanel
        {
            get { return fillPanel; }
        }

    }

    private class ButtonBarDesigner : ParentControlDesigner
    {
        public override void Initialize(IComponent component)
        {
        base.Initialize(component);

            Panel fillPanel = ((ButtonBar)component).FillPanel;

            // The name should be the same as the public property used to return the inner panel control.
            base.EnableDesignMode(fillPanel, "FillPanel");
        }
    }
}

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

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