当前位置:  开发笔记 > 编程语言 > 正文

一般枚举.Net控件的项目(MenuStrip,ToolStrip,StatusStrip)

如何解决《一般枚举.Net控件的项目(MenuStrip,ToolStrip,StatusStrip)》经验,为你挑选了1个好方法。

我有一些代码,通常会在表单中获取所有控件并将它们放在一个列表中.这是一些代码:

        private List GetControlList(Form parentForm)
        {
            List controlList = new List();
            AddControlsToList(parentForm.Controls, controlList);

            return controlList;
        }

        private void AddControlsToList(Control.ControlCollection rootControls, List controlList)
        {
            foreach (Control c in rootControls)
            {
                controlList.Add(c);
                if (c.HasChildren)
                    AddControlsToList(c.Controls, controlList);
                //
            }
        }

所以我只能使用c.HasChildren检查并查看是否还有来自此根控件的子控件.

menuStrip,toolStrip和statusStrip怎么样?如何获得这些控件中的所有控件?例如:MenuStripItem

我知道我可以尝试测试c.GetType()== typeof(MenuStrip),但我希望不必进行特定的类型测试.

如果我需要提供更多信息,请询问.

谢谢一堆



1> P Daddy..:

我相信VS设计师通过获取控件设计器的实例(参见Designer属性)来实现它,如果设计者是a ComponentDesigner,则获取AssociatedComponents属性.

编辑:

好吧,我猜这有点模糊.但是有一个警告:接下来的内容有点复杂,可能不值得付出努力.

关于命名法的注释:
下面,我将指代Visual Studio中的设计器 - 这是用于引用Visual Studio中的功能的名称,通过它可以直观地编辑表单和控件的布局和内容,以及设计器类 - 这将在下面解释.为了防止在任何给定时间引起混淆,我将始终将Visual Studio中的设计器功能称为"设计器",并且我将始终将设计器类称为"IDesigner",这是接口每个都必须实现.

当Visual Studio设计器加载一个组件(通常是一个控件,还有类似的东西Timer)时,它会在类的类上查找自定义属性DesignerAttribute.(那些不熟悉属性的人可能希望在继续之前阅读它们.)

此属性(如果存在)提供类的名称 - 一个IDesigner - 设计人员可以使用该名称与组件进行交互.实际上,此类控制设计器的某些方面以及组件的设计时行为.你可以用IDesigner做很多事情,但是现在我们只对一件事情感兴趣.

使用自定义的IDesigner使用一个从派生大多数控件ControlDesigner,它本身派生ComponentDesigner.该ComponentDesigner班有一个叫做公共虚拟财产AssociatedComponents,这是指在派生类中重写,以引用的集合返回这一个所有的"孩子"的组件.

更具体地说,ToolStrip控件(以及继承,MenuStrip控件)有一个DesignerAttribute引用一个名为的类ToolStripDesigner.看起来有点像:

/*
 * note that in C#, I can refer to the "DesignerAttribute" class within the [ brackets ]
 * by simply "Designer".  The compiler adds the "Attribute" to the end for us (assuming
 * there's no attribute class named simply "Designer").
 */
[Designer("System.Windows.Forms.Design.ToolStripDesigner, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"), ...(other attributes)]
public class ToolStrip : ScrollableControl, IArrangedElement, ...(other interfaces){
    ...
}

ToolStripDesigner堂课不公开.它是System.Design.dll的内部.但是由于它是由完全限定名称指定的,因此VS设计者Activator.CreateInstance无论如何都可以使用它来创建它的实例.

这个ToolStripDesigner类,因为它从[间接]继承ComponentDesigner了一个AssociatedComponents属性.当你调用它时,你得到一个新的ArrayList,包含对已经添加到的所有项目的引用ToolStrip.

那么你的代码看起来要做同样的事情是什么?相当复杂,但我想我有一个有效的例子:

/*
 * Some controls will require that we set their "Site" property before
 * we associate a IDesigner with them.  This "site" is used by the
 * IDesigner to get services from the designer.  Because we're not
 * implementing a real designer, we'll create a dummy site that
 * provides bare minimum services and which relies on the framework
 * for as much of its functionality as possible.
 */
class DummySite : ISite, IDisposable{
    DesignSurface designSurface;
    IComponent    component;
    string        name;

    public IComponent Component {get{return component;}}
    public IContainer Container {get{return designSurface.ComponentContainer;}}
    public bool       DesignMode{get{return false;}}
    public string     Name      {get{return name;}set{name = value;}}

    public DummySite(IComponent component){
        this.component = component;
        designSurface = new DesignSurface();
    }
    ~DummySite(){Dispose(false);}

    protected virtual void Dispose(bool isDisposing){
        if(isDisposing)
            designSurface.Dispose();
    }

    public void Dispose(){
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    public object GetService(Type serviceType){return designSurface.GetService(serviceType);}
}

static void GetComponents(IComponent component, int level, Action action){
    action(component, level);

    bool visible, enabled;
    Control control = component as Control;
    if(control != null){
        /*
         * Attaching the IDesigner sets the Visible and Enabled properties to true.
         * This is useful when you're designing your form in Visual Studio, but at
         * runtime, we'd rather the controls maintain their state, so we'll save the
         * values of these properties and restore them after we detach the IDesigner.
         */
        visible = control.Visible;
        enabled = control.Enabled;

        foreach(Control child in control.Controls)
            GetComponents(child, level + 1, action);
    }else visible = enabled = false;

    /*
     * The TypeDescriptor class has a handy static method that gets
     * the DesignerAttribute of the type of the component we pass it
     * and creates an instance of the IDesigner class for us.  This
     * saves us a lot of trouble.
     */
    ComponentDesigner des = TypeDescriptor.CreateDesigner(component, typeof(IDesigner)) as ComponentDesigner;
    if(des != null)
        try{
            DummySite site;
            if(component.Site == null)
                component.Site = site = new DummySite(component);
            else site = null;

            try{
                des.Initialize(component);
                foreach(IComponent child in des.AssociatedComponents)
                    GetComponents(child, level + 1, action);
            }finally{
                if(site != null){
                    component.Site = null;
                    site.Dispose();
                }
            }
        }finally{des.Dispose();}

    if(control != null){
        control.Visible = visible;
        control.Enabled = enabled;
    }
}


/* We'll use this in the ListComponents call */
[DllImport("user32.dll", CharSet=CharSet.Auto)]
static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);

const int WM_SETREDRAW = 11;

void ListComponents(){
    /*
     * Invisible controls and disabled controls will be temporarily shown and enabled
     * during the GetComponents call (see the comment within that call), so to keep
     * them from showing up and then disappearing again (or appearing to temporarily
     * change enabled state), we'll disable redrawing of our window and re-enable it
     * afterwards.
     */
    SendMessage(Handle, WM_SETREDRAW, 0, 0);
    GetComponents(this, 0,
        /* You'll want to do something more useful here */
        (component, level)=>System.Diagnostics.Debug.WriteLine(new string('\t', level) + component));
    SendMessage(Handle, WM_SETREDRAW, 1, 0);
}

推荐阅读
郑小蒜9299_941611_G
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有