在net中轻松掌握Windows窗体间的数据交互.docx
《在net中轻松掌握Windows窗体间的数据交互.docx》由会员分享,可在线阅读,更多相关《在net中轻松掌握Windows窗体间的数据交互.docx(43页珍藏版)》请在冰豆网上搜索。
在net中轻松掌握Windows窗体间的数据交互
Windows窗体是用于MicrosoftWindows应用程序开发的、基于.NETFramework的新平台。
此框架提供一个有条理的、面向对象的、可扩展的类集,它使您得以开发丰富的Windows应用程序。
一个Windows窗体就代表了.NET架构里的System.Windows.Forms.Form类的一个实例。
作者在CSDN技术论坛.NET板块下的C#分类经常看到有人问起如何在两个Form间传递数据,访问修改对方窗体里面的值。
对于有经验的程序员来说不是什么高深的东西,而对于初学者来说这些基础的东西往往是一个问题,并且存在这种现象,往往比较复杂的东西他们会,要用什么了就去学什么,实际上并没有真正的去理解掌握它,基础不扎实,所以就有了想通过自己对窗体编程积累的经验来写一些这方面的文章,以供学.NET的朋友参考,也借此机会同各位朋友进行交流,写得不合理的地方请各位朋友提宝贵意见,下面我分了三个部分来讲。
一.使用带参数的构造函数
我们要做的准备工作就是新建两个窗体,下面是两个窗体的布局,很简单:
<第一个例子>
说明:
Form1为主窗体,包含控件:
文本框textBoxFrm1,多选框checkBoxFrm1和按钮buttonEdit;
Form2为子窗体,包含控件:
文本框textBoxFrm2,多选框checkBoxFrm2和按钮buttonOK,buttonCancel。
当我们新建一个窗体的时候,设计器会生成默认的构造函数:
publicForm2()
{
InitializeComponent();
}
它不带参数,既然我们要把Form1中的一些数据传到Form2中去,为什么不在Form2的构造函数里做文章呢?
假设我们要实现使Form2中的文本框显示Form1里textBoxFrm1的值,修改子窗体的构造函数:
publicForm2(stringtext)
{
InitializeComponent();
this.textBoxFrm2.Text=text;
}
增加Form1中的修改按钮点击事件,处理函数如下:
privatevoidbuttonEdit_Click(objectsender,System.EventArgse)
{
Form2formChild=newForm2(this.textBoxFrm1.Text);
formChild.Show();
}
我们把this.textBoxFrm1.Text作为参数传到子窗体构造函数,以非模式方式打开,这样打开的formChild的文本框就显示了”主窗体”文本,是不是很简单,接下来我们传一个boolean数据给子窗体。
PublicForm2(stringtext,boolcheckedValue)
{
InitializeComponent();
this.textBoxFrm2.Text=text;
this.checkBoxFrm2.Checked=checkedValue;
}
在主窗体中的修改按钮点击处理,我采用了打开模式窗口的方式,其实在这个例子中看不出有什么分别,
privatevoidbuttonEdit_Click(objectsender,System.EventArgse)
{
Form2formChild=newForm2(this.textBoxFrm1.Text,this.checkBoxFrm1.Checked);
formChild.ShowDialog();
}
结果在预料之中,但是这里明显存在不足,在子窗体里的数据修改后不能传给主窗体,也就是说主窗体不受子窗体的影响。
而在实际的开发过程中我们经常使用子窗体来修改主窗体里面的数据,那怎么解决呢?
在.NET中有两种类型,值类型和引用类型。
值类型是从ValueType继承而来,而ValueType又是从Object继承;对于引用类型它直接继承Object类型。
这下让我们看看怎样通过Form2来修改Form1里的数据。
还是让我们来修改Form2的代码。
PrivateTextBoxtextBoxFrm12;
privateCheckBoxcheckBoxFrm12;
publicForm2(TextBoxheckbo,CheckBoxheckbox)
{
InitializeComponent();
this.textBoxFrm2.Text=heckbo.Text;
this.checkBoxFrm2.Checked=heckbox.Checked;
this.textBoxFrm12=heckbo;
this.checkBoxFrm12=heckbox;
}
现在我们传了两个引用类型的数据:
TextBox类型,和CheckBox;另外在Form2中增加了两个类数据成员textBoxFrm12、checkBoxFrm12用来分别保存构造函数传来的变量,不过他们并不属于Form2的Controls容器。
修改Form2的确定按钮点击事件函数:
privatevoidbuttonOK_Click(objectsender,System.EventArgse)
{
this.textBoxFrm12.Text=this.textBoxFrm2.Text;
this.checkBoxFrm12.Checked=this.checkBoxFrm2.Checked;
this.Close();
}
上面的代码我们通过把textBoxFrm2的Text和checkBoxFrm2.Checked赋给textBoxFrm12和checkBoxFrm12完成了对主窗体中的textBoxFrm1和checkBoxFrm2的修改,因为textBoxFrm1和textBoxFrm12是同一个引用,而checkBoxFrm2和checkBoxFrm12也是。
到这里为止功能是实现了,但是总觉得不是很合理,让两个窗体控件传来传去,现在我举一个恰当一点的例子。
修改了两个窗体:
<第二个例子>
说明:
在这个例子中我们的两个窗体都加了一个ListBox用来显示ArrayList中的内容。
主窗体中控件:
listBoxFrm1,buttonEdit;
子窗体中控件:
listBoxFrm2,textBoxAdd,buttonAdd,buttonEdit,buttonOK。
这次我们用ArrayList来作为传递数据,在Form1中定义类数据成员:
privateArrayListlistData1;
在构造函数中增加了对listData1进行内存分配,并生成数据最终绑定到listBoxFrm1,
publicForm1()
{
InitializeComponent();
this.listData1=newArrayList();
this.listData1.Add("DotNet");
this.listData1.Add("C#");
this.listData1.Add("A");
this.listData1.Add("WebService");
this.listData1.Add("XML");
this.listBoxFrm1.DataSource=this.listData1;
}
另外,对修改按钮点击事件处理函数的修改如下:
privatevoidbuttonEdit_Click(objectsender,System.EventArgse)
{
Form2formChild=newForm2(this.listData1);
formChild.ShowDialog();
this.listBoxFrm1.DataSource=null;
this.listBoxFrm1.DataSource=this.listData1;
}
相对与主窗体,对子窗体作相应修改,也在Form2中增加了类数据成员:
privateArrayListlistData2;
用来保存对主窗体中listData1的引用。
修改构造函数:
publicForm2(ArrayListlistData)
{
InitializeComponent();
this.listData2=listData;
foreach(objectointhis.listData2)
{
this.listBoxFrm2.Items.Add(o);
}
}
这里让listData2同listData1指向同一个引用;另外没有对listBoxFrm进行绑定,采用了填充。
好了,下面是对数据操作的时候了。
添加处理函数代码如下:
privatevoidbuttonAdd_Click(objectsender,System.EventArgse)
{
if(this.textBoxAdd.Text.Trim().Length>0)
{
this.listData2.Add(this.textBoxAdd.Text.Trim());
this.listBoxFrm2.Items.Add(this.textBoxAdd.Text.Trim());
}
else
MessageBox.Show("请输入添加的内容!
");
}
删除处理代码如下:
privatevoidbuttonDel_Click(objectsender,System.EventArgse)
{
intindex=this.listBoxFrm2.SelectedIndex;
if(index!
=-1)
{
this.listData2.RemoveAt(index);
this.listBoxFrm2.Items.RemoveAt(index);
}
else
MessageBox.Show("请选择删除项或者没有可删除的项!
");
}
退出Form2子窗体:
privatevoidbuttonOK_Click(objectsender,System.EventArgse)
{
this.Close();
}
编译运行程序,在子窗体中对数据进行修改,关闭后,主窗体就会显示更新后的数据。
这里有一点要提醒一下,比较两个例子,我们都传的是引用类型,一个是String,另一个是ArrayList,为什么string类型不能修改主窗体的数据呢?
其实在.Net中对string类型的修改并不是修改原来的值,原来的值没有变化,而是重新生成一个新的字符串,下面是一个很好的说明。
publicclassZZConsole
{
[STAThread]
staticvoidMain(string[]args)
{
stringstr1="abc";
stringstr2=str1;
str1="123";
Console.WriteLine(str1);
Console.WriteLine("--------------");
Console.WriteLine(str2);
Console.WriteLine("--------------");
ArrayListal1=newArrayList();
al1.Add("abc");
ArrayListal2=al1;
al2.Add("123");
foreach(objectoinal1)
Console.WriteLine((string)o);
Console.WriteLine("--------------");
foreach(objectoinal2)
Console.WriteLine((string)o);
Console.ReadLine();
}
}
运行一下看看输出结果就明白了,另外对值类型的数据操作要使用ref关键字。
总结,我们通过带参数的构造函数实现了窗体间的数据交互,代码看上去也比较清楚,在实际开发过程中,可以把DataSet,DataTable,或者是DataView当作参数,当然如果只是想修改一行,可以传个DataRow或者DataRowView。
二.给窗体添加属性或方法
1.使用Form类的Owner属性
获取或设置拥有此窗体的窗体。
若要使某窗体归另一个窗体所有,请为其Owner属性分配一个对将成为所有者的窗体的引用。
当一个窗体归另一窗体所有时,它便随着所有者窗体最小化和关闭。
例如,如果Form2归窗体Form1所有,则关闭或最小化Form1时,也会关闭或最小化Form2。
并且附属窗体从不显示在其所有者窗体后面。
可以将附属窗体用于查找和替换窗口之类的窗口,当选定所有者窗体时,这些窗口不应消失。
若要确定某父窗体拥有的窗体,请使用OwnedForms属性。
上面是SDK帮助文档上讲的,下面我们就来使用它。
首先还是使用第一篇文章中的第二个例子,窗体如下:
说明:
在这个例子中我们的两个窗体都加了一个ListBox用来显示ArrayList中的内容。
主窗体中控件:
listBoxFrm1,buttonEdit;
子窗体中控件:
listBoxFrm2,textBoxAdd,buttonAdd,buttonEdit,buttonOK。
主窗体中还是定义类数据成员,
privateArrayListlistData1;
在构造函数里实例化它,填充数据,最后绑定到listBoxFrm1。
构造函数如下:
publicForm1()
{
InitializeComponent();
this.listData1=newArrayList();
this.listData1.Add("DotNet");
this.listData1.Add("C#");
this.listData1.Add("A");
this.listData1.Add("WebService");
this.listData1.Add("XML");
this.listBoxFrm1.DataSource=this.listData1;
}
主窗体的修改按钮处理函数:
privatevoidbuttonEdit_Click(objectsender,System.EventArgse)
{
Form2formChild=newForm2();
formChild.Owner=this;
formChild.ShowDialog();
this.listBoxFrm1.DataSource=null;
this.listBoxFrm1.DataSource=this.listData1;
}
我们设置了formChild.Owner为this,这样,子窗体和主窗体就有联系了,
当然我们也可以改成如下:
privatevoidbuttonEdit_Click(objectsender,System.EventArgse)
{
Form2formChild=newForm2();
formChild.ShowDialog(this);
this.listBoxFrm1.DataSource=null;
this.listBoxFrm1.DataSource=this.listData1;
}
不过这样还不行,目前主窗体的listData1变量外部访问不到,
privateArrayListlistData1;
必须修改为public访问修饰符,
publicArrayListlistData1;
也可以通过属性(property)来实现,
publicArrayListListData1
{
get{returnthis.listData1;}
}
这里我采用属性,感觉语法更灵活,清楚。
下面是对Form2的修改,
构造函数又恢复原貌了。
publicForm2()
{
InitializeComponent();
}
另外又新增了一个窗体的Load事件,在它的事件处理函数中来获取主窗体中的数据,
privatevoidForm2_Load(objectsender,System.EventArgse)
{
Form1pareForm=(Form1)this.Owner;
this.listData2=pareForm.ListData1;
foreach(objectointhis.listData2)
this.listBoxFrm2.Items.Add(o);
}
有人会问,为什么不把上面的代码放到构造函数里面去呢?
如下不是更好,
publicForm2()
{
InitializeComponent();
Form1pareForm=(Form1)this.Owner;
this.listData2=pareForm.ListData1;
foreach(objectointhis.listData2)
this.listBoxFrm2.Items.Add(o);
}
那我会对你说错了,因为在主窗体修改按钮被点击后,开始执行
Form2formChild=newForm2();
而在Form2的实例化过程中会在构造函数中执行
Form1pareForm=(Form1)this.Owner;
而这时的this.Owner是没有值的,为空引用,那么下面的代码肯定也出问题,
this.listData2=pareForm.ListData1;
foreach(objectointhis.listData2)
this.listBoxFrm2.Items.Add(o);
当整个Form2实例化完成后,才会执行
formChild.Owner=this;
这条代码,所以使用了Form2_Load事件。
那怎样可以不使用Form2_Load事件呢?
等下面我们来修改代码实现它。
下面的子窗体代码没有变化,
privatevoidbuttonAdd_Click(objectsender,System.EventArgse)
{
if(this.textBoxAdd.Text.Trim().Length>0)
{
this.listData2.Add(this.textBoxAdd.Text.Trim());
this.listBoxFrm2.Items.Add(this.textBoxAdd.Text.Trim());
}
else
MessageBox.Show("请输入添加的内容!
");
}
privatevoidbuttonDel_Click(objectsender,System.EventArgse)
{
intindex=this.listBoxFrm2.SelectedIndex;
if(index!
=-1)
{
this.listData2.RemoveAt(index);
this.listBoxFrm2.Items.RemoveAt(index);
}
else
MessageBox.Show("请选择删除项!
");
}
privatevoidbuttonOK_Click(objectsender,System.EventArgse)
{
this.Close();
}
好了,结果同第一篇中的一样,子窗体能修改主窗体的值。
2.使用自定义属性或方法
下面我们来讲讲怎样使用自定义属性或方法来完成数据修改功能而不使用Form2_Load事件。
主窗体的修改按钮点击处理函数如下:
privatevoidbuttonEdit_Click(objectsender,System.EventArgse)
{
Form2formChild=newForm2();
formChild.ListData2=this.listData1;
formChild.ShowDialo