对于窗体间的数据传递,是刚开始从事.Net窗体应用程序开发人员碰到的一个常见问题,在此讲几个常见的实现方式。
一. 构造函数参数传递
通过构造函数传递参数应该是比较基本的参数传递方式,重载构造函数,通过带参数的构造函数来实例化窗体。
1. 在窗体类内部定义参数变量
private object myParams;
2. 实现构造函数
public OptionForm(object parameters) { InitializeComponent(); this.myParams = parameters;//设置参数引用 }
3. 实例化窗体
OptionForm form = new OptionForm( myParams );
在实际使用过程中,需要注意传入的是引用类型还是值类型,处理方式会有所不同。
二.使用窗体的属性
1. Form.Owner 属性:获取或设置拥有此窗体的窗体。
语法:
public Form Owner { get; set; }
若要使某窗体归另一个窗体所有,可为其 Owner 属性分配一个对将成为所有者的窗体的引用。
当一个窗体归另一窗体所有时,它便随着所有者窗体最小化和关闭。例如,如果 Form2 归窗体 Form1 所有,则关闭或最小化 Form1 时,Form2 也会关闭或最小化。并且附属窗体从不显示在其所有者窗体后面。
可以将附属窗体用于查找和替换窗口之类的窗口,当选定所有者窗体时,这些窗口不应消失。
2. Form.OwnedForms 属性:获取 Form 对象的数组,这些对象表示此窗体拥有的所有窗体。
语法:
public Form[] OwnedForms { get; }
此属性返回包含此窗体拥有的所有窗体的数组。
要使某窗体归另一个窗体所有,可调用 AddOwnedForm 方法。分配给所有者窗体的窗体将保持被拥有状态,直到调用了 RemoveOwnedForm 方法。
如果窗体是多文档界面 (MDI) 父窗体,则除了当前打开的所有 MDI 子窗体外,此属性将返回所有显示的窗体。
3. Form.MdiChildren 属性:获取窗体的数组,这些窗体表示以此窗体作为父级的多文档界面 (MDI) 子窗体。
语法:
public Form[] MdiChildren { get; }
此属性使您得以获取对当前在某 MDI 父窗体中打开的所有 MDI 子窗体的引用。
若要创建 MDI 子窗体,请将要成为 MDI 父窗体的 Form 分配给该子窗体的 MdiParent 属性。可以使用此属性依次通过所有 MDI 子窗体,以执行一些操作,如当 MDI 父窗体关闭时将数据保存到数据库中,或者根据应用程序中执行的操作更新子窗体上的字段。
4. Form.MdiParent 属性:获取或设置此窗体的当前多文档界面 (MDI) 父窗体。
语法:
public Form MdiParent { get; set; }
若要创建 MDI 子窗体,请将要成为 MDI 父窗体的 Form 分配给该子窗体的 MdiParent 属性。
可以从某 MDI 子窗体使用此属性来获取所有子窗体都需要的全局信息或者调用对所有子窗体执行操作的方法。
5. Form.ActiveForm 静态属性:获取此应用程序的当前活动窗体。
语法:
public static Form ActiveForm { get; }
可以使用此方法获得对当前活动窗体的引用,以在该窗体或其控件上执行操作。
6. Form.ActiveMdiChild 属性:获取当前活动的多文档界面 (MDI) 子窗口。
语法:
public Form ActiveMdiChild { get; }
可使用此方法确定 MDI 应用程序中是否有任何打开的 MDI 子窗体。也可使用此方法从 MDI 子窗口的 MDI 父窗体或者从应用程序中显示的其他窗体对该 MDI 子窗口执行操作。
7. ContainerControl.ParentForm 属性:获取将容器控件分配给的窗体。
语法:
public Form ParentForm { get; }
三.使用公共属性
使用公共属性也是一种比较常用的方式,通过窗体设计器添加的控件默认访问修饰符为private级别,可以设置成public或Internal(在程序集内部可见)来对外公开。
比如对窗体中的Button进行公开,那就可以访问Button的相关属性,同时也可以注册事件或撤销事件注册。如,
OptionForm form = new OptionForm(); form.buttonOK.Click += new EventHandler(buttonOK_Click); form.ShowDialog();
对于只允许读取访问或修改访问的控件或变量可以通过属性来控制。
对(一.1)方式进行修改,去除重载构造函数,增加属性也可以实现同样的效果。
public object MyParams { get { return this.myParams; } set { this.myParams = value; } }
四. 使用公共方法
使用公共方法类似于属性,对上面的同等实现如下
//获取参数 public object GetParams() { return this.myParams; } //设置参数 public void SetParams(object myParams ) { this.myParams = myParams; }
五. 使用静态类
该方式可以简单的理解为静态变量全局共享。
1. 先来定义静态类
public static class ParameterSettings { //公共静态变量 public static string Username = "Zhengzuo"; //私有静态变量 private static string userRole = "Administrators"; //私有静态变量 private static string password = "http://blog.csdn.net/zhzuo"; //内部属性 internal static string UserRole { get { return userRole; } } //公共属性 public static string Password { get { return password;} private set { password = value;} } }
在需要访问的地方通过以下方式进行
string username = ParameterSettings.Username; //公共静态变量赋值 string password = ParameterSettings.Password; //公共静态属性赋值 string userRole = ParameterSettings.UserRole; //内部属性赋值 ParameterSettings.Username = "郑佐";//修改成新用户名
六. 窗体实现Singleton模式
Singleton模式是我们开发过程中最常用的模式之一。在技术社区经常看到有人谈及对主窗体实现Singleton,但个人认为这不是一种妥当的做法,因为没有这个必要。
这里通过另一个自定义类来进行演示。假设UserLoginInfo类用来保存登录系统后的用户凭据。
public class UserLoginInfo { //实现Singleton模式,线程安全。 private readonly static UserLoginInfo currentUserInfo = new UserLoginInfo(); //提供全局访问点 public static UserLoginInfo CurrentUserInfo { get { return currentUserInfo; } } //阻止显式实例化,但不能阻止反射方式调用。 private UserLoginInfo() { } //公共变量 public string Username; //私有变量 private static string userRole; //私有变量 private static string password; //内部属性 internal string UserRole { get { return userRole; } set { userRole = value; } } //公共属性 public string Password { get { return password; } internal set { password = value; } } }
在其他代码中进行访问
UserLoginInfo.CurrentUserInfo.Username ="郑佐"; UserLoginInfo.CurrentUserInfo.UserRole = "dotnetlover"; UserLoginInfo.CurrentUserInfo.Password = "http://blog.csdn.net/zhzuo";
对于Singleton模式的实现方式有很多,编写时需要考虑是否需要保证实例访问的线程安全问题,以免引发不可预料的情况,为了提高性能可以考虑惰性实例化。关于Singleton模式的更多信息可以参考另一篇文章。
七. 发布事件进行订阅
通过事件来传递参数应该说是一种推荐的实现方式,在产生事件时进行被动的获取相关数据。
这里将通过一个自定义事件来演示数据的传输。在自定义事件时,标准的做法都会先定义一个事件参数类,要么直接使用基类EventArgs,或者从EventArgs继承实现自己的参数类,假设自定义基类取名为OptionSettingEventArgs,
//选项设置事件参数类 public class OptionSettingEventArgs : EventArgs { private string changedPath; //构造函数 public OptionSettingEventArgs(string changedPath) { this.changedPath = changedPath; } //读取参数 public string ChangedPath { get { return this.changedPath; } } }
以上参数类只包含一个修改后的路径参数。接下去我们要对原先的OptionForm窗体增加事件定义,这里使用.net 2.0中提供的泛型类来实现。
//定义事件 public event EventHandler<OptionSettingEventArgs> OptionSettingChanged;
编写事件引发程序如下
//引发OptionSettingChanged事件 protected virtual void OnOptionSettingChanged(OptionSettingEventArgs e) { if (OptionSettingChanged != null) { OptionSettingChanged(this, e); } }
对文件目录选择按钮事件处理程序进行修改来实现事件激发,并没有考虑直接从文本框直接数据输入方式。
//通过目录对话框设置新的路径 private void buttonBrowser_Click(object sender, EventArgs e) { FolderBrowserDialog dialog = new FolderBrowserDialog(); DialogResult result = dialog.ShowDialog(this); if (result == DialogResult.OK) { if(this.textBoxPath.Text != dialog.SelectedPath) { this.textBoxPath.Text = dialog.SelectedPath; OptionSettingEventArgs args = new OptionSettingEventArgs(dialog.SelectedPath); OnOptionSettingChanged(args); } } }
调用代码如下
OptionForm form = new OptionForm(); //注册事件 form.OptionSettingChanged += new EventHandler (form_OptionSettingChanged); form.ShowDialog();
通过以下事件处理程序来验证其正确性
private void form_OptionSettingChanged(object sender, OptionSettingEventArgs e) { string newPath = e.ChangedPath; MessageBox.Show(this, String.Format("新路径为“{0}”。", newPath), "提示"); }
以上就是其中窗体之间数据传递的方法。