gpt4 book ai didi

c# - 一般枚举 .Net 控件的项目(MenuStrip、ToolStrip、StatusStrip)

转载 作者:行者123 更新时间:2023-11-30 20:14:37 25 4
gpt4 key购买 nike

我有一些代码通常会获取表单中的所有控件并将它们放入列表中。下面是一些代码:

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

return controlList;
}

private void AddControlsToList(Control.ControlCollection rootControls, List<Control> 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) 但我希望不必进行特定类型测试。

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

非常感谢

最佳答案

我相信 VS 设计器是通过获取控件设计器的实例(参见 Designer attribute )来实现的,如果设计器是 ComponentDesigner , 得到 AssociatedComponents属性(property)。

编辑:

好吧,我想这有点含糊。不过,有一个警告:接下来的内容有点复杂,可能不值得为此付出努力。

关于命名的注释:
下面,我将同时指代 Visual Studio 中的设计器——这个名称用于指代 Visual Studio 中的功能,通过该功能可以直观地编辑窗体和控件的布局和内容——以及设计器类——这将在下文中进行解释以下。为了防止混淆我在任何给定时间指的是什么,我总是将 Visual Studio 中的设计器功能称为“设计器”,并且我将始终将设计器类称为“IDesigner”,这是每个接口(interface)都必须实现。

当 Visual Studio 设计器加载组件(通常是控件,但也有 Timer 等)时,它会在类型为 DesignerAttribute 的类上查找自定义属性>。 (不熟悉属性的人在继续之前可能需要 read up on them。)

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

大多数使用自定义 IDesigner 的控件都使用派生自 ControlDesigner 的控件,后者本身派生自 ComponentDesignerComponentDesigner 类有一个名为 AssociatedComponents 的公共(public)虚拟属性,它意味着在派生类中被覆盖以返回对该组件的所有“子”组件的引用集合。

更具体地说,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 类不是公共(public)的。它在 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<IComponent, int> 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);
}

关于c# - 一般枚举 .Net 控件的项目(MenuStrip、ToolStrip、StatusStrip),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/297335/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com