Получить родительскую форму компонента - PullRequest
25 голосов
/ 16 декабря 2008

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

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

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

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

любые предложения будут великолепны

Edit:

Для пояснения, это компонент , а не элемент управления , см. Здесь: ComponentModel.Component

Ответы [ 10 ]

26 голосов
/ 16 декабря 2008

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

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

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

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

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

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 является хорошим примером для рассмотрения: Компонент, которому необходимо знать содержащую его форму.

9 голосов
/ 16 декабря 2008

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

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 голосов
/ 16 декабря 2008

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

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

2 голосов
/ 19 сентября 2012

Я нашел это решение , которое не требует ввода. Для C # я реализовал это так:

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 пользователем, но он устанавливается родительской формой по умолчанию.

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

2 голосов
/ 16 декабря 2008

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

1 голос
/ 25 сентября 2014

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

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

    return parent.FindForm();
}

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

1 голос
/ 03 июля 2012

Спасибо, Роб, я использовал ваше решение в программе 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

1 голос
/ 16 декабря 2008

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

0 голосов
/ 17 декабря 2016

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

0 голосов
/ 22 мая 2016

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

public static Form ParentForm(this Control ctrl) => ctrl as Form ?? ctrl.FindForm();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...