Получить компонентную родительскую форму
У меня есть невизуальный компонент, который управляет другими визуальными средствами управления.
Мне нужно иметь ссылку на форму, над которой работает компонент, но я не знаю, как ее получить.
Я не уверен в добавлении конструктора с родителем, указанным в качестве элемента управления, так как я хочу, чтобы компонент работал, просто будучи упавшим в конструктор.
Другая мысль, которую я имел, заключалась в том, чтобы иметь свойство parent в качестве элемента управления со значением по умолчанию как "Me"
любые предложения были бы замечательными
Edit:
Чтобы уточнить, это компонент, а не элемент управления, см. здесь: ComponentModel.Component
Ответы
Ответ 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();