Подтвердить что ты не робот

Контроль пользователя как контейнер во время разработки

Я разрабатываю простой элемент управления расширителя.

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

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

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

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

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

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

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

[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).

4b9b3361

Ответ 1

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

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

Ответ 2

Чтобы предотвратить перемещение/изменение рабочей области в дизайнере, вы должны создать класс для этой рабочей области, который скрывает свойства Location, Height, Width, Size от конструктора:

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

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

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

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