Пользовательский контроль как контейнер во время разработки - PullRequest
17 голосов
/ 23 апреля 2010

Я проектирую простое управление экспандером.

Я получил от UserControl, нарисовал внутренние элементы управления, построил, запустил; все ок.

Поскольку внутренний элемент управления - это панель, я хотел бы использовать его в качестве контейнера во время разработки. На самом деле я использовал атрибуты:

[Designer(typeof(ExpanderControlDesigner))]
[Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))] 

Отлично, говорю. Но это не так ...

В результате я могу использовать его как контейнер во время разработки, но:

  • Добавленные элементы управления возвращают внутренние элементы управления, уже встроенные в пользовательский элемент управления
  • Даже если я нажму верхний элемент управления, добавленный во время разработки, во время выполнения он снова вернется к элементам управления, встроенным в пользовательский элемент управления
  • Я не могу ограничить область контейнера во время разработки в область Panel

Чего мне не хватает? Вот код для полноты ... почему этот фрагмент кода не работает?

[Designer(typeof(ExpanderControlDesigner))]
[Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))] 
public partial class ExpanderControl : UserControl
{
    public ExpanderControl()
    {
        InitializeComponent();
....

[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")] 
internal class ExpanderControlDesigner : ControlDesigner
{
    private ExpanderControl MyControl;

    public override void Initialize(IComponent component)
    {
        base.Initialize(component);

        MyControl = (ExpanderControl)component;

        // Hook up events
        ISelectionService s = (ISelectionService)GetService(typeof(ISelectionService));
        IComponentChangeService c = (IComponentChangeService)GetService(typeof(IComponentChangeService));

        s.SelectionChanged += new EventHandler(OnSelectionChanged);
        c.ComponentRemoving += new ComponentEventHandler(OnComponentRemoving);
    }

    private void OnSelectionChanged(object sender, System.EventArgs e)
    {

    }

    private void OnComponentRemoving(object sender, ComponentEventArgs e)
    {

    }

    protected override void Dispose(bool disposing)
    {
        ISelectionService s = (ISelectionService)GetService(typeof(ISelectionService));
        IComponentChangeService c = (IComponentChangeService)GetService(typeof(IComponentChangeService));

        // Unhook events
        s.SelectionChanged -= new EventHandler(OnSelectionChanged);
        c.ComponentRemoving -= new ComponentEventHandler(OnComponentRemoving);

        base.Dispose(disposing);
    }

    public override System.ComponentModel.Design.DesignerVerbCollection Verbs
    {
        get
        {
            DesignerVerbCollection v = new DesignerVerbCollection();

            v.Add(new DesignerVerb("&asd", new EventHandler(null)));

            return v;
        }
    }
}

Я нашел много ресурсов ( Взаимодействие , разработан , ограниченная область ), но ничего не было полезным для оперативности ...

На самом деле есть хитрость, поскольку классы System.Windows.Forms могут создаваться (как обычно) и иметь правильное поведение во время выполнения (например, TabControl).

Ответы [ 3 ]

17 голосов
/ 23 апреля 2010

ParentControlDesigner не знает, что вы хотите сделать. Он только знает, что вы хотите, чтобы ваш UserControl был контейнером.

Что вам нужно сделать, так это реализовать собственный дизайнер, который включает режим дизайна на панели:

    using System.ComponentModel;
    using System.Windows.Forms;
    using System.Windows.Forms.Design;

    namespace MyCtrlLib
    {
        // specify my custom designer
        [Designer(typeof(MyCtrlLib.UserControlDesigner))]
        public partial class UserControl1 : UserControl
        {
            public UserControl1()
            {
                InitializeComponent();
            }

            // define a property called "DropZone"
            [Category("Appearance")]
            [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] 
            public Panel DropZone
            {
                get { return panel1; }
            }
        }

        // my designer
        public class UserControlDesigner  : ParentControlDesigner
        {
            public override void Initialize(System.ComponentModel.IComponent component)
            {
                base.Initialize(component);

                if (this.Control is UserControl1)
                {
                    this.EnableDesignMode(
                       (UserControl1)this.Control).DropZone, "DropZone");
                }
            }
        }
    }

Я узнал это от Генри Минута на CodeProject. Смотрите ссылку для некоторых улучшений в технике.

3 голосов
/ 05 марта 2013

Чтобы предотвратить перемещение или изменение размера рабочей области в конструкторе, необходимо создать класс для этой рабочей области, который скрывает свойства «Местоположение», «Высота», «Ширина», «Размер» от дизайнера:

public class WorkingArea : Panel
{
    [Browsable(false)]
    [EditorBrowsable(EditorBrowsableState.Never)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public new Point Location
    {
        get
        {
            return base.Location;
        }
        set
        {
            base.Location = value;
        }
    }
...
}   
3 голосов
/ 15 января 2013

В дополнение к ответу выше. В комментариях упоминается, что пользователь может перетащить рабочую область. Мое исправление для этого состоит в том, чтобы включить панель WorkingArea в другую панель, установив для нее значение Dock.Fill. Чтобы запретить пользователю изменять его обратно, я создал класс ContentPanel, который переопределяет и скрывает свойство Dock:

class ContentPanel : Panel
{
    [Browsable(false)]
    public override DockStyle Dock
    {
        get { return base.Dock; }
        set { base.Dock = DockStyle.Fill; }
    }
}

Для меня это делает его достаточно безопасным. Мы используем элемент управления только для внутреннего использования, поэтому мы в основном хотим предотвратить случайное перетаскивание разработчиков. В любом случае, конечно, есть способы все испортить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...