火木棉

木棉道 . 积硅步 至千里

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  36 随笔 :: 6 文章 :: 42 评论 :: 4 引用

公告

2007年12月4日 #

posted @ 2007-12-04 22:12 火木棉 阅读(1852) 评论(1) 编辑

 在windows 编程中用到最多的就是控件的时间了,微软给我们很好的方式,把注意力放到事件执行方法的设计和编码上,但是但我们真正弄懂了事件的真正出发执行原理的话,对我们的编程的提高真是非常榜的,例如在windows编程中 如果我单击了一个button按钮触发了button 的click事件  Button1_Click(){}  , 但是有时候我们编程的时候,不但想要触发button 的单击事件,我还想要把其他的时间也要调用下来顺序执行,要实现这种方式,除了在方法最后对其他方法的调用,还可以利用将其他需要顺序执行的方法封装到button的click 事件的委托对象中,这样就能够顺序执行毁掉方法列表中的程序了,而这种方式的实现是以清楚事件触发和委托的调用为前提的。

    事件是类和对象向外界发出的消息,事件的执行是通过事件委托的方式,调用我们所准备好的处理方法,而是先消息的响应的。要响应某些事件并针对某些事件执行我们意定的方法,需要做到以下几步:

        1、声明事件委托。

        2、声明事件。

        3、添加事件的触发方法。

        4、添加事件的处理程序(响应事件的方法)。

        5、将指定的事件处理程序邦定到要处理的事件上(订阅事件)。

        6、用户信息操作,并触发事件(调用事件的触发方法)。

        7、通过事件委托的回调,执行我们需要的事件处理程序。

      下面我们举一个简单的自定义事件处理程序的例子(控制台程序)

   namespace 事件
   {
    //发布事件的类
    public class TestEventSource
    {
        //定义事件参数类
        public class TestEventArgs : EventArgs
        {
            public readonly char KeyToRaiseEvent;
            public TestEventArgs(char keyToRaiseEvent)
            {
                KeyToRaiseEvent = keyToRaiseEvent;
            }
        }

        //定义delegate
        public delegate void TestEventHandler(object sender, TestEventArgs e);
        //用event 关键字声明事件对象
        public event TestEventHandler TestEvent;

        //事件触发方法
        protected virtual void OnTestEvent(TestEventArgs e)
        {
            if (TestEvent != null)
                TestEvent(this, e);
        }

        //引发事件
        public void RaiseEvent(char keyToRaiseEvent)
        {
            TestEventArgs e = new TestEventArgs(keyToRaiseEvent);
            OnTestEvent(e);
        }

    }
    //监听事件的类
    public class TestEventListener
    {
        //定义处理事件的方法,他与声明事件的delegate具有相同的参数和返回值类型
        public void KeyPressed(object sender, TestEventSource.TestEventArgs e)
        {
            Console.WriteLine("发送者:{0},所按得健为:{1}", sender, e.KeyToRaiseEvent);
        }

        //订阅事件
        public void Subscribe(TestEventSource evenSource)
        {
            evenSource.TestEvent += new TestEventSource.TestEventHandler(KeyPressed);
        }
        //取消订阅事件
        public void UnSubscribe(TestEventSource evenSource)
        {
            evenSource.TestEvent -= new TestEventSource.TestEventHandler(KeyPressed);
        }
    }

    //测试类
    public class Test
    {
        public static void Main()
        {
            //创建事件源对象
            TestEventSource es = new TestEventSource();
            //创建监听对象
            TestEventListener el = new TestEventListener();
            //订阅事件
            Console.WriteLine("订阅事件\n");
            el.Subscribe(es);
            //引发事件
            Console.WriteLine("输入一个字符,再按enter键");
            string s = Console.ReadLine();
            es.RaiseEvent(s.ToCharArray()[0]);
            //取消订阅事件
            Console.WriteLine("\n取消订阅事件\n");
            el.UnSubscribe(es);

            //引发事件
            Console.WriteLine("输入一个字符,再按enter健");
            s = Console.ReadLine();
            es.RaiseEvent(s.ToCharArray()[0]);

 

        }
    }

}

程序执行结

订阅事件

输入一个字符,再按enter键
aaaa
发送者:事件.TestEventSource,所按得健为:a

取消订阅事件

输入一个字符,再按enter健

          TestEventSource类。他就相当于windows控件类一样,是事件的源,里面包含有事件的声明,以及存储调用参数的事件参数类,以及事件的触发方法。       

         TestEventListener类。他提供了事件处理程序,并实现了事件处理程序和事件对象的邦定,当然时间处理程序可以放在别处, 跟邦定程序(订阅事件)放在一起便于理解和调用

        Test 类,实例化自定义事件的事件源对象,并调用 TestEventListener类中的Subscribe(es);方法进行事件对象和事件处理程序的邦定(订阅事件),调用 TestEventSource类中的RaiseEvent(char keyToRaiseEvent)引发对象,并有对象所指定的委托回调处理事件。完成整个自定义事件。

           其中   RaiseEvent(char keyToRaiseEvent)      就相当于main()一样是自定义事件的执行入口,       从这个法开始---〉调用事件委托----〉查找订阅事件程序找到事件所封装的方法集----〉由委托回调事件处理程序并传递参数---〉执行事件处理程序。


posted @ 2007-12-04 22:10 火木棉 阅读(6725) 评论(1) 编辑

曾经对委托和事件非常头疼,好在现在以自己的方式入门了,就行以自己的方式把它过一遍,当作学习日记吧。 

      委托(delegate)是一种引用类型,我们在处理他的时候要当作类来看待而不是方法,说白了委托就是对方法或者方法列表的引用,调用一个委托实例就好像是调用c++中的指针一样,他封装了对制定方法的引用,或者说委托起到的是桥梁的作用,实例后的委托对象会将给定的参数传递给他所回调的方法,并去执行方法。

       看一个简单的例子:

     //声明一个委托
    delegate int myDelegateHandler(int a, int b);

    public class A
    {
        //静态的处理方法
        public static int M1(int a, int b)
        {
            int c = 0;
            c = a + b;
            return c;
        }
    }
    //入口类
    public class B
    {
        public static void Main()
        {
            //实例一个委托
            myDelegateHandler mdh = new myDelegateHandler(A.M1);
            //调用委托
            int sum = mdh(2, 2);
            Console.WriteLine(sum.ToString());

        }
    }

    上面是一个非常简单的例子,具体的实现步骤:

           1、 先声明个委托实例  ;

           2、然后提供要处理的方法;

           3、再实例化委托(把委托看作是类的话,实例化委托就不难理解了,其参数是要处理的方法,这里的方法 不用加括号,实例化的过程就是装载方法的过程,就好像需要参数的构造函数一样)实例化后的委托对象就好比是c++中的指针,它本身就是封装了方法的对象;

          4、最后我们调用委托对象就好比是调用了被封装方法本身,调用时的参数也就传给了被封装的方法。

           5、需要注意的是 所声明的委托无论是 参数个数,参数类型,返回值类型 都要和所要封装的方法保持一致,当调用委托实例对象时,所传入的参数也要保持一致 ,否则会出现错误。 

 

 

        委托链

        我们知道委托是对方法的封装,而且委托可以封装很多方法形成委托链,其实委托就好像是一个容器,他封装了我们想要实现的若干方法,当调用委托对象(相当于c++中的指针)时,就会顺序的执行它所封装的所有的方法,如果有返回值的话,往往返回的是最后一个被执行的方法的返回值,委托链的形成可以用"+="或"-="对不同的委托实例进行二元操作。

    委托链实例:

              //定义一个委托
    public delegate void PrintHandler(string message);

    public class PrintProvider1
    {
        public void Print(string msg)
        {
            Console.WriteLine( msg + "1111111");
        }

    }

    public class PrintProvider2
    {
        public void Print(string msg)
        {
            Console.WriteLine( msg + "2222222");
        }

    }

    class Delegate1
    {
        public static void StaticPrint(string msg)
        {
            Console.WriteLine(msg + "3333333");

        }

        public static void Main()
        {
            string s = "委托链";
            PrintProvider1 pp1 = new PrintProvider1();
            PrintProvider2 pp2 = new PrintProvider2();
            //创建委托实例
            PrintHandler prn1 = new PrintHandler(pp1 .Print );
            PrintHandler prn2 = new PrintHandler(pp2 .Print );
            PrintHandler prn3 = new PrintHandler(StaticPrint );

            Console.WriteLine("委托实例prn1的打印结果");
            prn1(s );

            Console.WriteLine("委托实例prn2的打印结果");
            prn2(s);

            Console.WriteLine("委托实例prn1+prn2的打印结果");
            PrintHandler prn = prn1 + prn2;
            prn(s);

            Console.WriteLine("委托实例prn1+prn2+prn3的打印结果");
             prn += prn3;
            prn(s);

            Console.WriteLine("委托实例prn1+prn3的打印结果");
            prn -= prn2;
            prn(s);

            Console.WriteLine("委托实例prn3的打印结果");
            prn -= prn1;
            prn(s);

            Console.WriteLine("试图调用null委托会引发异常");
            try
            {
                prn -= prn3;
                prn(s);

            }
            catch (NullReferenceException ex)
            {
                Console.WriteLine(ex .Message );
            }

            Console.WriteLine("试图从null中移出委托是无效操作");
            try
            {
                prn -= prn3;
            }
            catch (NullReferenceException ex)
            {
                Console.WriteLine(ex .Message );

            }

            Console.Read();

        }

    }

执行结果

委托实例prn1的打印结果
委托链1111111
委托实例prn2的打印结果
委托链2222222
委托实例prn1+prn2的打印结果
委托链1111111
委托链2222222
委托实例prn1+prn2+prn3的打印结果
委托链1111111
委托链2222222
委托链3333333
委托实例prn1+prn3的打印结果
委托链1111111
委托链3333333
委托实例prn3的打印结果
委托链3333333
试图调用null委托会引发异常
未将对象引用设置到对象的实例。
试图从null中移出委托是无效操作

posted @ 2007-12-04 22:09 火木棉 阅读(164) 评论(0) 编辑

 <童年的家园>

泥巴墙   木板房

斑驳的门窗

石堰堰  土坑坑

烟熏得火塘

歌谣在火苗上跳荡

母亲唱着

牵我回故乡

http://www.56.com/u57/v_MTczMzc5ODI.html

posted @ 2007-12-04 22:07 火木棉 阅读(37) 评论(0) 编辑

   动态的给radiobuttonlist 或者dropdownlist 赋值时 如果所赋的数值 在控件的列表中不存在时 往往会发生异常System.ArgumentOutOfRangeException: “DropDownList1”有一个无效 SelectedValue,因为它不在项目列表中)
例如 dropdownlist1中用"111,222,333",如果复制dropdownlist1.text="444"dropdownlist1.selectedvalue="444"时就会出现前面的异常。

      但是有时候这种异常没有出现,那是因为我们没有用到dropdownlist或radiobuttonlist控件的(IsPostBack)indexchange事件,当控件需要事件时上面的错误异常就会被捕获。这是因为SelectedValue 属性还可以用于选择列表控件中的某一项,方法是用该项的值设置此属性。如果列表控件中的任何项都不包含指定值,则会引发 System.ArgumentOutOfRangeException。
同样这样 if ( DropDownList1.Items.FindByValue("中国").Selected)也会出现异常。

      我们可以用selectedindex来解决上面的问题:
      例如:DropDownList1.SelectedIndex = DropDownList1.Items.IndexOf(DropDownList1.Items.FindByValue("中国"));
     这种方法在动态的赋值时先要检索控件列表中是否有匹配的数值,如果数据匹配则dropdownlist.text的值被赋为:“中国”,
    如果通过FindByValue没有找到指定项则为null,而Items.IndexOf(null)会返回-1,这样我们就可以根据判断自动指出默认index的值了
     这样就避免了异常的发生。
posted @ 2007-12-04 22:05 火木棉 阅读(670) 评论(0) 编辑

   

无论在做web还是在写winform程序是老是在导出excel数据是遇到科学计数法问题,如果字符太长(如身份证号)在导出的excel 文件中就会出现长字符串的科学计数法表示,反复导数据是就会出现错误 。
 

      我解决的办法是在到处是或者存储将要导出时,每条记录字符串形式处理

   在asp.net 中 我一般都是将要导出的数据放到gridview网格里,首先对网格邦定数据时 字符串形式处理,然后再用普通的形式导出excel就把问题解决了。

  我的代码非常简单:在邦定gridview控件时在rowdatabound事件中队数据格式化

 protected void gError_RowDataBound(object sender, GridViewRowEventArgs e)
    {
           //1)  文本:vnd.ms-excel.numberformat:@

          //2)  日期:vnd.ms-excel.numberformat:yyyy/mm/dd

         //3)  数字:vnd.ms-excel.numberformat:#,##0.00

         //4)  货币:vnd.ms-excel.numberformat:¥#,##0.00

         //5)  百分比:vnd.ms-excel.numberformat: #0.00%

        for (int i = 0; i < e.Row.Cells.Count; i++)
        {
            if (e.Row.RowType == DataControlRowType.DataRow)
                e.Row.Cells[i ].Attributes.Add("style", "vnd.ms-excel.numberformat:@");
        }
          

    }

   然后执行到处操作就不会出现问题了

 protected void btnOut_Click(object sender, EventArgs e)
    {
       
       Response.Clear();
       Response.Buffer = true;
        Response.Charset = "GB2312";
       Response.AppendHeader("Content-Disposition", "attachment;filename=FileName.xls");
     
        Response.ContentEncoding = System.Text.Encoding.UTF7;

      //设置输出文件类型为excel文件。
      Response.ContentType = "application/ms-excel";
       System.IO.StringWriter oStringWriter = new System.IO.StringWriter();
       System.Web.UI.HtmlTextWriter oHtmlTextWriter = new System.Web.UI.HtmlTextWriter(oStringWriter);
       this.gError.RenderControl(oHtmlTextWriter);
        Response.Output.Write(oStringWriter.ToString());
        Response.Flush();
        Response.End();

    }

 

public override void VerifyRenderingInServerForm(Control control)
    {
        //base.VerifyRenderingInServerForm(control);
    }

在winform程序开发时,处理的办法就是在导出的过程中,开始试了 处理excel对象的格式 mysheet.Cells.NumberFormat = "#";

后来没有成功。最后还是用了逐条纪录进行字符格式转化的方法,即添加“ '  ”.

 我写得代码主要部分如下

  #region  执行数据导出
            try
            {
                //到导出excel
                Excel.ApplicationClass my = new Excel.ApplicationClass();
                if (my == null)
                {
                    MessageBox.Show("无法创建excel对象,可能您的系统没有安装excel");
                    return;
                }
                my.Visible = false;
                Excel.Workbook mybook = (Excel.Workbook)my.Workbooks.Add(1);
                ((Excel.Worksheet)mybook.Worksheets[1]).Name = "sheet1";
                Excel.Worksheet mysheet = (Excel.Worksheet)mybook.Worksheets[1];
                // mysheet.Cells.NumberFormat = "#";
               //导出列名
                for (int j = 0; j < this.dgvShow.Columns.Count; j++)
                {
                    if (this.dgvShow.Columns[j].Visible == true)
                    {
                        mysheet.Cells[1, j + 1] = "'" + Convert.ToString(this.dgvShow.Columns[j].HeaderText);//加"'"防止科 学计数法
                    }
                }
                //导出数据
                for (int i = 0; i < this.dgvShow.Rows.Count; i++)
                {
                    for (int j = 0; j < this.dgvShow.Columns.Count; j++)
                    {
                        mysheet.Cells[i + 2, j + 1] = "'" + Convert.ToString(this.dgvShow.Rows[i].Cells[j].Value);
                    }
                }

                if (savefilename != "")
                {
                    try
                    {
                        //mybook.Save();
                        mybook.SaveCopyAs(savefilename);
                        MessageBox.Show("excel文件导出成功!");
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("导出文件出现错误,文件可能正被打开!\n" + ex.Message);
                    }
                }


                GC.Collect();
            }
            catch (Exception ex)
            {
                MessageBox.Show("数据导出时出现错误,一下是详细错误信息:\n" + ex.Message);
                return;
            }
            #endregion

   每条记录都进行处理 ,如果数据量很多的话应该会影响到速度,一定还有很多更好的方法,一起学习提高。

posted @ 2007-12-04 22:02 火木棉 阅读(2981) 评论(6) 编辑