摘要
一般的工程都是多个form组成的,各个窗体之间经常要灵活的传递数据。下面分享一点自己的经验:
窗体传值的方法有很多,下面仅介绍我用过的一些,不知道官方叫这些什么方法,大家也可以找找看其他的。
一、通过构造器传值
这是最简单的一种方式,例如我从form1中要传一个字符串去form2
首先,在form2的构造器中稍作修改:
public Form2(String s)
{
InitializeComponent();
this.labelRecieve.Text = s;
}
添加了一个string参数 s
然后,在form1的click事件中,将要传递的参数传入,如下片断:
private void buttonShow_Click(object sender, EventArgs e)
{
Form2 f2;
if (textBoxSend.Text == "")
{
f2 = new Form2("I'm from form1");
}
else
{
f2 = new Form2(textBoxSend.Text);
}
DialogResult r = f2.ShowDialog();//至于Show与ShowDialog就不用再说了吧
}
在触发click事件的时候,form2就接受到f1传过去的textBoxSend.Text或者"I’m from form1",并且用labelRecieve去承接它。
这种方法,虽然简单方便,但是毕竟功能有限,当需要传递较大量的多样的数据时,用构造器就不能胜任了。
二、通过属性传递
属性可以方便的传递多个数据(不就是添加多个属性么?),假设我要从form2传递某字符串到form3,首先我们为form3添加一个属性叫myString
public Form3()
{
InitializeComponent();
}
public string myString
{
get
{
return this.textBoxf3.Text;
}
set
{
if (value == null)
textBoxf3.Text = string.Empty;
else
textBoxf3.Text = value;
}
}
通过该属性去设置文本框的text.
然后,在form2的点击事件中,只需令
f3.myString = "I'm from form2";
这样也很方便,值得一提的是,这样通过属性传递的时候,即可以将数据从form2船到form3又可以从form3传回来。如
if (r == DialogResult.OK)
{
f3.myString = "I'm from form3";
this.labelRecieve.Text = f3.myString;
//form3关闭的时候将myString保存到form2的label中。
}
属性传递是最常用的一种方式。
三、通过事件携带参数传递
坦白说,我目前还很少用到这,准确的说这个应该叫事件结合属性传值。
现在我在form4里面坐了某些操作,假设form4是我们开发的类型库的一部分,我想将它发布给其他的同事使用的时候,我们可以使用这样的事件去传值。
首先,在form4中,添加事件参数类型和事件处理器委托的定义:
public class myEventArgs : EventArgs
{
string myString;
public string MyString
{
get
{
return myString;
}
set
{
if (value != null)
myString = value;
else
myString = string.Empty;
}
}
public myEventArgs(string s)
{
this.MyString = s;
}
}
//事件处理方法的委托
public delegate void myEventHandler(object sender, myEventArgs e);
然后,我们在click事件中去触发这样一个公共的事件myClick
public event myEventHandler myClick;
private void buttonClick_Click(object sender, EventArgs e)
{
if (this.myClick != null)
this.myClick(this,new myEventArgs(textBox4.Text));
this.DialogResult = DialogResult.OK;
}
我们将textBox4中的文本封装到myEventArgs这样一个事件参数对象里面,这样它就会随着事件被传到form3中,同时在form3中我们来添加一个事件处理方法,
void f4_myClick(object sender, Form4.myEventArgs e)
{
myString = e.MyString;
this.textBoxf3.Text = String.Format("From f4: {0}",e.MyString);
}
在点击事件中我们通过委托去调用该方法
Form4 f4 = new Form4();
f4.myClick += new Form4.myEventHandler(f4_myClick);
在f4对象的myClick事件被触发以后,会调用这里的f4_myClick方法,我们就可以通过该方法从事件参数中取得数据了,这里是放到textBoxf3中。
四、使用公共方法
使用公共方法类似于属性,对上面的同等实现如下
//获取参数
public object GetParams()
{
return this.myParams;
}
//设置参数
public void SetParams(object myParams )
{
this.myParams = myParams;
}
五、使用静态方法
使用静态类该方式可以简单的理解为静态变量全局共享,通过下面代码能够比较清楚的理解,先来定义静态类
public static class ParameterSettings
{
//公共静态变量
public static string Username = "Zhengzuo";
//私有静态变量
private static string userRole = "Administrators";
//私有静态变量
private static string password = "https://www.jb51.net/";
//内部属性
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 = "https://www.jb51.net/";
对于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), "提示");
}
希望本文所述对大家的C#程序设计有所帮助。