一般情况下或许用不到,但是也有特殊情况下会需要使用类似的功能.
1.比如你的软件做了多个界面版本,有中文版,英文版等等,就需要控制界面显示.通常会把控件名称与显示文字以键值对的形式存储到外部数据库或者是语言字典中.
2.又比如对软件做配置文件,配置软件启动时控件的显示,文字,选中状态等.都可以用这个来做.
/// <summary>
/// 递归方法,获取指定controlName的控件;如果控件未找到,则返回null,请注意判断null
/// </summary>
/// <param name="container">容器控件,可以是窗体form,也可以是panel,GroupBox等</param>
/// <param name="controlName">控件名称</param>
/// <returns>返回一个控件类型</returns>
private Control getControlFromName(Control container,string controlName)
{
foreach(Control c in container.Controls)
{
if(c.Name==controlName)
{
return c;
}
if(c.HasChildren)
{
//这里不能直接写return getControlFromName(c, controlName);因为会导致只执行第一个子容器控件,如果未找到就提前返回了Null;
Control myControl = getControlFromName(c, controlName);
if(myControl!=null)
{
return myControl;
}
}
}
//并非所有的代码路径都返回值,未找到就返回null
return null;
}
// 也可以通过反射来查找;
//object obj = this.GetType().GetField("textBox1",System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.IgnoreCase);
//之后需要进行类型转换;
// 也可以通过反射来查找;
object obj = this.GetType().GetField("textBox1",System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.IgnoreCase);
//之后需要进行类型转换;
TextBox tbox1 = (TextBox)obj;
tbox1.Text = "反射";
泛型约束 where T: ContainerControl 可以限定容器控件为条件.
ContainerControl 是由Control派生出一个特殊的基类,既继承了ScrollableControl,也有继承IContainerControl接口. 常见的窗体,用户控件等容器都继承于它.
3. 也可用于在其它线程中控制窗体内容,如textbox或者label的显示文字.
// 定义 委托;
delegate void setTxtCallback(Control con, string text);
//委托的方法;
public void setTxtInvoke(string controlName, string text)
{
Control con = getControlFromName(this, controlName);
if (con == null)
{
return;
}
//实例化委托,用创建创建控件的线程去调用更新;
setTxtCallback setTxtCall = new setTxtCallback(setTxt);
con.Invoke(setTxtCall, new object[] { con, text });
}
private void setTxt(Control control, string text)
{
control.Text = text;
}
//定义一个公开的静态的本窗体类的对象,供外部类使用;
//这样即可解决外部静态函数调用非静态字段与方法等,需要对象引用的问题;
//定义为本窗体类的静态成员
public static Form_main fm_main;
//可以基于某事件机制,在合适的时候,在其它类调用之前,将其赋值为本窗体;
fm_main = this;
//之后再调用外部方法
//在外部方法中的调用方法
//textBox_result为控件的名称,controlName也可以是动态取得的.
Form_main.fm_main.setTxtInvoke("textBox_result",result.ToString());
4.其它的像遍历控件,比如根据控件值遍历,根据控件状态遍历 ,或者根据控件类型遍历如textbox,checkbox等等,或者不根据任何条件,单纯的遍历所有控件,都应该比较严谨的判断是否是容器控件/是否有子控件,并且判断容器内的子控件,而不是简简单单的想当然的只遍历第一层,或者写了个递归却提前终止执行了.
//C#常见面试题中的其中某一题,遍历窗体上所有TextBox控件并给它赋值为string.Empty
/// <summary>
/// 遍历窗体上所有TextBox控件并给它赋值为string.Empty
/// </summary>
/// <param name="container">容器控件,可以是窗体this,也可以是其它容器如panel,groupbox等</param>
public void getControlByType(Control container)
{
foreach (Control con in container.Controls)
{
if (con is TextBox)
{
TextBox txtbox = (TextBox)con;
txtbox.Text = string.Empty;
}
if (con.HasChildren)
{
getControlByType(con);
}
}
}
//调用方法,在具体事件中引用,可以是窗体this,也可以是其它容器如panel,groupbox等
//getControlByType(this);
//遍历窗体上所有某类型控件(label,textbox,checkbox等具有.Text属性的控件)并给它赋值为string.Empty
// 不使用反射直接实现;
public void getControlByType1(Control container, string controlType)
{
string fullType = "System.Windows.Forms." + controlType;
foreach (Control con in container.Controls)
{
string str=con.GetType().FullName;
if (con.GetType().FullName == fullType)
{
con.Text = string.Empty;
}
if (con.HasChildren)
{
getControlByType1(con, controlType);
}
}
}
//遍历窗体上所有某类型控件(label,textbox,checkbox等具有.Text属性的控件)并给它赋值为string.Empty
// 使用反射机制来实现;
public void getControlByType2(Control container, string controlType)
{
string fullType = "System.Windows.Forms." + controlType;
// 反射加载程序集1;Assembly.LoadFrom必须是完整路径(受到操作系统版本和x86与x64的区别,以及框架版本及环境变量等变化影响,LoadFrom并不好使)
//Assembly asmb = Assembly.LoadFrom(@"C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Windows.Forms.dll");
//Assembly asmb = Assembly.LoadFrom(@"C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Windows.Forms.dll");
//System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
//System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
//加载程序集2
//System.Windows.Forms, Version=x.x.x.x, Culture=neutral, PublicKeyToken=b77a5c561934e089
//框架.net版本根据程序生成编译时环境自行修改;
Assembly asmb = Assembly.Load("System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
Type myType = asmb.GetType(fullType);
foreach (Control con in container.Controls)
{
string str = con.GetType().FullName;
if (con.GetType().FullName == fullType)
{
//使用myType获取属性Text,设置属性Text值;
myType.GetProperty("Text").SetValue(con, string.Empty, null);
}
if (con.HasChildren)
{
getControlByType2(con, controlType);
}
}
}
// 在具体事件中调用
//getControlByType(groupBox1, "TextBox");
//getControlByType(this, "Label");
5. 对第三条做一些补充, 第三条适用于多线程应用,在子线程代码中去利用委托更改UI的属性;
而实际工作中,可能涉及更多的往往是仅仅只跨不同窗体的访问,并不是Thread中访问的,
此时其实还有另外一个方法 Controls.Find(string key, bool searchAllChildren);就可以派上用场了. Controls.Find用得比较多(参数不详细说了,这个用法很简单不会就百度查一下),之前写文章的时候漏掉了这个;在非子线程的代码中均可用使用;
如果是第三方控件库的,也能用Controls.Find去找.
这个是反射的两种方式动态创建窗体并且添加到SuperTabControl标签页:
//打开子窗体添加到TabControl
private void openNewTab(string formName)
{
try
{
//获取当前程序集的名称
string assemblyName = Assembly.GetExecutingAssembly().GetName().Name;
// 根据程序集名与类型名称创建窗体 (即 命名空间.实例名)
object obj = Assembly.GetExecutingAssembly().CreateInstance(assemblyName + "." + formName, false);
第二种方法动态创建窗体; 也可用;
//System.Runtime.Remoting.ObjectHandle objHwnd=Activator.CreateInstance(assemblyName,$"{assemblyName}.{fName}");
//object obj = objHwnd.Unwrap();
Form form = (Form)obj;
//去除顶级控件属性(子窗体构造函数内已设定)
//form.TopLevel = false;
SuperTabItem item = superTabControl1.CreateTab(form.Name);
//将标签的文字设置为子窗体的标题文字;
item.Text = form.Text;
item.Name = form.Name;
//添加窗体
item.AttachedControl.Controls.Add(form);
//标签卡切换到新窗体;
superTabControl1.SelectedTab = item;
form.Show();
superTabControl1.Show();
}
catch
{
}
}
这个是在窗体代码中,查找非本窗体自身的控件,查找其它窗体的控件,使用的正是Controls.Find(string key, bool searchAllChildren);
在标签子窗体中,访问主窗体的SuperTabControl控件;
// 在SuperTabControl子标签容器内的子窗体里面,拦截浏览器 target=_blank 弹出新标签页的事件;
// 拦截之后添加一个新的浏览器标签到SuperTabControl
private void openNewURL(string URL)
{
Form_map fmap = new Form_map();
fmap.newURL = URL;
SuperTabControl tabControl=null;
tabControl = FormFullscreen.isFullStyle ? FormFullscreen.FMscreen.Controls.Find("superTabControl1", true)[0] as SuperTabControl : FormMain.fmain.Controls.Find("superTabControl1", true)[0] as SuperTabControl;
SuperTabItem item = tabControl.CreateTab(fmap.Name);
//可以将标签的文字设置为子窗体的标题文字;
item.Text ="浏览器";
item.Name = fmap.Name;
//添加窗体
item.AttachedControl.Controls.Add(fmap);
//标签卡切换到新窗体;
tabControl.SelectedTab = item;
fmap.Show();
tabControl.Show();
}