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

Получить компонентную родительскую форму

У меня есть невизуальный компонент, который управляет другими визуальными средствами управления.

Мне нужно иметь ссылку на форму, над которой работает компонент, но я не знаю, как ее получить.

Я не уверен в добавлении конструктора с родителем, указанным в качестве элемента управления, так как я хочу, чтобы компонент работал, просто будучи упавшим в конструктор.

Другая мысль, которую я имел, заключалась в том, чтобы иметь свойство parent в качестве элемента управления со значением по умолчанию как "Me"

любые предложения были бы замечательными

Edit:

Чтобы уточнить, это компонент, а не элемент управления, см. здесь: ComponentModel.Component

4b9b3361

Ответ 1

[Важно понимать, что техника ISite ниже работает только во время разработки. Поскольку ContainerControl является общедоступным и получает назначенное значение, VisualStudio будет писать код инициализации, который устанавливает его во время выполнения. Сайт установлен во время выполнения, но вы не можете получить ContainerControl от него]

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

В принципе вам нужно добавить свойство ContainerControl к вашему компоненту:

public ContainerControl ContainerControl
{
  get { return _containerControl; }
  set { _containerControl = value; }
}
private ContainerControl _containerControl = null;

и переопределить свойство Site:

public override ISite Site
{
  get { return base.Site; }
  set
  {
    base.Site = value;
    if (value == null)
    {
      return;
    }

    IDesignerHost host = value.GetService(
        typeof(IDesignerHost)) as IDesignerHost;
    if (host != null)
    {
        IComponent componentHost = host.RootComponent;
        if (componentHost is ContainerControl)
        {
            ContainerControl = componentHost as ContainerControl;
        }
    }
  }
}

Если вы это сделаете, ContainerControl будет инициализирован для ссылки на содержащую форму конструктор. Связанная статья объясняет это более подробно.

Хороший способ увидеть, как это сделать, - это посмотреть на реализацию типов в .NET Framework, которые имеют поведение, подобное тому, что вы хотите с помощью такого инструмента, как Lutz Reflector. В этом случае System.Windows.Forms.ErrorProvider является хорошим примером для просмотра: Компонент, который должен знать его содержащую форму.

Ответ 2

Я использую рекурсивный вызов для перехода по цепочке управления. Добавьте это под свой контроль.

public Form ParentForm
{
    get { return GetParentForm( this.Parent ); }
}

private Form GetParentForm( Control parent )
{
    Form form = parent as Form;
    if ( form != null )
    {
        return form;
    }
    if ( parent != null )
    {
        // Walk up the control hierarchy
        return GetParentForm( parent.Parent );
    }
    return null; // Control is not on a Form
}

Изменить: Я вижу, что вы изменили свой вопрос, когда я печатал его. Если это компонент, конструктор этого компонента должен воспринимать его как родительский как параметр, и родитель должен передать его при построении. Несколько других компонентов делают это, например, таймер.

Сохраните родительский элемент управления в качестве члена, а затем используйте его в свойстве ParentForm, которое я дал вам выше, вместо этого.

Ответ 3

Если componentenet управляет другими визуальными элементами управления, то вы должны иметь возможность добраться до родителя через них.

Ответ 4

Вам нужно установить родительский контейнер каким-то образом. Ваш компонент - это просто класс, который находится в памяти так же, как и все остальное. У него нет истинного контекста того, что его создало, если что-то не говорит вам об этом. Создайте свойство управления родителем и установите его.

Или просто вывести из управления и использовать FindForm(). Не все элементы управления должны иметь видимый компонент

Ответ 5

Я думаю, вы хотите использовать свойство Site для IComponent. Это более или менее эквивалентно родительскому свойству.

Ответ 6

Спасибо, Роб, я использовал ваше решение в программе VB.Net, выглядит так:

''' <summary>
''' Returns the parent System.Windows.form of the control
''' </summary>
''' <param name="parent"></param>
''' <returns>First parent form or null if no parent found</returns>
''' <remarks></remarks>
Public Shared Function GetParentForm(ByVal parent As Control) As Form
    Dim form As Form = TryCast(parent, Form)
    If form IsNot Nothing Then
        Return form
    End If

    If parent IsNot Nothing Then
        ' Walk up the control hierarchy
        Return GetParentForm(parent.Parent)
    End If

    ' Control is not on a Form
    Return Nothing
End Function

Ссылка на него в моем блоге: http://www.dailycode.info/Blog/post/2012/07/03/How-to-get-a-user-controls-parent-form-(Windows-forms).aspx

Ответ 7

Я нашел это решение, которое не требует ввода. Для С# я реализовал его следующим образом:

public partial class RegistryManager : Component, ISupportInitialize
{

    private Form _parentForm;
    public Form ParentForm
    {
        get { return _parentForm;  }
        set { _parentForm = value; }
    }

    // Etc....

    #region ISupportInitialize
    public void BeginInit() {  }
    public void EndInit()
    {
        setUpParentForm();
    }
    private void setUpParentForm()
    {
        if (_parentForm != null) return; // do nothing if it is set
        IDesignerHost host;
        if (Site != null)
        {
            host = Site.GetService(typeof(IDesignerHost)) as IDesignerHost;
            if (host != null)
            {
                if (host.RootComponent is Form)
                {
                    _parentForm = (Form)host.RootComponent;
                }
            }
        }
    }
    #endregion
}

Этот способ позволяет установить ParentForm пользователем, но он устанавливается родительской формой как Default.

Надеюсь, это поможет вам.

Ответ 8

Попробуйте это....

private Form GetParentForm(Control parent)
{
    if (parent is Form)
        return parent as Form;

    return parent.FindForm();
}

Вызвать GetParentForm(this.Parent) из компонента

Ответ 9

Если связанный с компонентом Form является активным Form, вы можете получить его Form.ActiveForm.

Ответ 10

Улучшение выше:

public static Form ParentForm(this Control ctrl) => ctrl as Form ?? ctrl.FindForm();