winform零基础学习(十一)—C# Winform窗体(类)之间传值的多种方法浅析

摘要

一般的工程都是多个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#程序设计有所帮助。

你可能感兴趣的:(winform零基础自学,C#零基础自学,c#)