【问题标题】:Get Component's Parent Form获取组件的父窗体
【发布时间】:2010-09-27 03:41:14
【问题描述】:

我有一个管理其他可视控件的非可视组件。

我需要对组件操作的表单有一个引用,但我不知道如何获取它。

我不确定添加一个将父级指定为控件的构造函数,因为我希望组件只需放入设计器即可工作。

我的另一个想法是拥有一个父属性作为控件,默认值为“我”

任何建议都会很棒

编辑:

澄清一下,这是一个组件,而不是控件,请看这里:ComponentModel.Component

【问题讨论】:

    标签: c# vb.net winforms components


    【解决方案1】:

    我使用递归调用来遍历控制链。将此添加到您的控件中。

    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
    }
    

    编辑:我看到您在我输入此内容时修改了您的问题。如果它是一个组件,该组件的构造函数应该将它的父级作为参数,并且父级应该在构造时传入 this。其他几个组件会执行此操作,例如计时器。

    将父控件保存为成员,然后在我上面给你的 ParentForm 属性中使用它而不是这个。

    【讨论】:

    • 也可以使用 Control.FindForm() 来实现。
    【解决方案2】:

    我认为您想使用 IComponent 的 Site 属性。它或多或少等同于 Parent 属性。

    【讨论】:

    • 你能不能说得更具体一点?我在调试时查看了站点属性,似乎没有任何引用父表单的内容。
    【解决方案3】:

    如果组件正在管理其他可视控件,那么您应该能够通过它们访问父级。

    【讨论】:

    • 我想到了这个,虽然它有效,但它看起来确实有点“hacky”
    • 我不同意你的观点,但是如果这个组件总是与它所在表单的控件相关联,那么你就没有什么可失去的了。
    【解决方案4】:

    您必须以某种方式设置父容器。你的组件只是一个类,它和其他所有东西一样驻留在内存中。它没有创建它的真正背景,除非有东西告诉你它确实如此。创建一个父控件属性并设置它。

    或者简单地从控件派生并使用 FindForm()。并非所有控件都必须具有可见组件

    【讨论】:

      【解决方案5】:

      [了解以下 ISite 技术仅在设计时有效,这一点很重要。因为 ContainerControl 是公共的并且被分配了一个值,VisualStudio 将编写初始化代码,在运行时设置它。站点是在运行时设置的,但无法从中获取 ContainerControl]

      Here's an article 描述了如何为非可视组件执行此操作。

      基本上你需要为你的组件添加一个属性 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 是一个很好的例子:一个需要知道其包含表单的组件。

      【讨论】:

      • 谢谢,经过一些小的调整(添加了一些 != 空检查),这一切正常。
      • 服务到底是什么,它不是组件的任何成员。
      • 我认为 service 实际上应该是 host - 我换了它,到目前为止它对我有用。
      • 这在运行时是如何工作的。据我所知,提供 IDesignerHost 实现的是设计器,因此它只能在设计模式下工作。
      • 我很抱歉。该代码在将组件拖放到 from 后正常工作,设计器为 ContainerControl 属性生成初始化代码!因此,要使用该解决方案,您应该将组件重新放置到 from。
      【解决方案6】:

      感谢 Rob,我在 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】:

        我找到了不需要输入的this solution。对于 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,但它是由父表单设置为默认的。

        希望对你有帮助。

        【讨论】:

        • 这对你真的有用吗?对我来说,host 始终设置为 null
        【解决方案8】:

        试试这个....

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

        从组件调用GetParentForm(this.Parent)

        【讨论】:

          【解决方案9】:

          上面的一个改进是:

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

          【讨论】:

            【解决方案10】:

            如果与Form相关的组件是活动的Form,你可以通过Form.ActiveForm得到它。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-02-25
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-10-03
              • 1970-01-01
              • 2017-11-08
              • 1970-01-01
              相关资源
              最近更新 更多