zoukankan      html  css  js  c++  java
  • 实现等待窗体的几种方式[转]

    实现等待窗体的几种方式

    原文来自:http://www.cnblogs.com/bluewater/archive/2007/06/13/781708.html

    实现等待窗体的几种方式: 

    下面说明了五种可以实现等待窗体的方式,其中三种给出了代码。

    准备资料

    安全访问控件成员

    为了保证在创建控件的线程上调用控件成员,用下面的方式封装控件的属性、方法、其他自定义成员的访问。

    如: winWordControl.LoadDocument()封装为:

    delegate void VoidDelegate();  

    private void LoadDocument()

            {

                if (InvokeRequired)

                {

                    Invoke(new VoidDelegate(LoadDocument));

                    return;

                }

                this.winWordControl.LoadDocument();      

            }

    下面的代码封装了winWordControl.OpenMode=Opration

    private delegate void OpenModeDelegate(Operation op);

            private void OpenMode(Operation value)

            {

                if (InvokeRequired)

                {

                    Invoke(new OpenModeDelegate(OpenMode), new object[] { value });

                    return;

     

                }

                winWordControl.OpenMode = value;

          

            }

    这些封装保证了对控件成员的访问在任何线程都是安全的。

    例子说明

    例子假定有三个窗体:

    MainForm:

    Preview preview;//Preview 是在此线程创建

    Privite void SomeMethod()

    {

    Thread wordInit = new Thread(new ThreadStart(preview.InitWordDocControl));

         wordInit.Start();

    }

    第二个窗体

    PreviewForm:

    WinWordControl winWordControl = new WinWordControl();

    Private void InitWordDocControl()

    {

         //执行初始化加载word、实现延迟窗体

         //TODO

    }

    第三个窗体

    WaitForm:提示信息

    实现方式

    InitWordDocControl为了在加载word时不出现假死,必须开启新线程。
    由于用到了非托管资源,最简单的方式是把托管资源(WaitForm)放在工作线程,线程结束,窗体会自动销毁,不用自己写清理代码。

    第一种:ShowDialog

    ShowDialog自动阻塞当前线程,这使它成为最优的解决方式。

    Private void InitWordDocControl()

    {

         Thread thread = new Thread(new ThreadStart(Waiting));

         thread.Start();

         LoadDocument();

    thread.Abort();//销毁线程,自动回收托管资源

    }

      private void Waiting()

            {

              //局部变量,在此线程创建,可以直接操作其成员

                Wait FormWait = new Wait();

                FormWait.StartPosition = FormStartPosition.CenterScreen;

                FormWait.ShowDialog(); //线程等待         

            }

    private void LoadDocument()

            {

                if (InvokeRequired)

                {

                    Invoke(new VoidDelegate(LoadDocument));

                    return;

                }

                this.winWordControl.LoadDocument();       

            }

    最简单的解决方式,利用了托管资源的优势和ShowDialog本身的特性。

    第二种:Show

    如果简单的修改Waiting为:

      private void Waiting()

            {

               Wait FormWait = new Wait();

                FormWait.StartPosition = FormStartPosition.CenterScreen;

                FormWait.Show();       //窗体立即被销毁 

            }

    窗体肯定会一闪而过,因为FormWait是局部变量,出了方法体就会被回收。

    因此要改成下面的形式:

    首先把局部变量改为字段,让他在加载类型时分配内存。其次,做如此修改后,创建Wait的线程就变成了创建Preview的线程,这样就不能直接修改此窗体属性,必须用Invoke。

    private void Waiting()

            {

    //下面的调用都是线程安全的,内部都会判断是否是创建线程,不是会调用Invoke

                CreateWait();

                SetFormStartPosition(FormStartPosition.CenterScreen);

                ShowWait();

            }

    修改:

    Private void InitWordDocControl()

    {

         Thread thread = new Thread(new ThreadStart(Waiting));

         thread.Start();

         thread.Join();//阻塞调用线程,让其先执行完show

         LoadDocument();

    }

    修改LoadDocument()

    private void LoadDocument()

            {

                if (InvokeRequired)

                {

                    Invoke(new VoidDelegate(LoadDocument));

                    return;

                }

                this.winWordControl.LoadDocument(); 

                CloseWait(); //释放资源,线程自动销毁。注意也要使用线程安全的形式。    

            }

    第三种:异步委托

    本质上通过线程池中的线程执行委托方法,仍然是线程问题。但是可以用show和异步委托结合,简单的实现等待。可以看出代码比上面实现简单许多。

    首先这次把加载word放到新线程中,而WaitForm在原线程。

    修改:

    Private void InitWordDocControl()

    {

         Waiting();

         MethodInvoker mi = new MethodInvoker(LoadDocument);

         mi.BeginInvoke(AsyncCallClose,null);//执行完委托方法,执行AsyncCallClose来关闭等待窗体。

    }

    private void AsyncCallClose(IAsyncResult ar)

            {

                FormWait.Close();             

            }

     MethodInvoker,只是系统定义的委托,提供些许便利,更好的方式是自己定义如:

    delegate void VoidDelegate();VoidDelegate 和MethodInvoker是等价的。

    在这种实现中发现了下面的问题:控件成员可以不在创建控件的线程中使用!!如FormWait.Close();调用此语句的是线程池中的线程,而FormWait是在另外的线程中创建。不知道是什么原因??按照必须在创建控件线程调用成员,则会抛异常。按照许多资料,这种情况也是非法调用,但在此却没有问题?!

    第四种:信号量

    以前没有用过线程,遇到这个问题,首先想到的是信号量来控制线程通信。可以参考后面的资料或者我以前的文章:

    http://www.cnblogs.com/bluewater/archive/2006/08/14/476720.html

    第五种:Timer

    本质也是线程,有同学说,他一直在VB中用Timer来模拟线程来控制时间片。应该也能实现等待窗体。

    在此使用线程,主要是为了有好的用户体验,避免假死。

    第一次使用线程,查了许多资料,但仍然有个问题没有解决,再写一遍,希望有人指点原因。

    在这种实现中发现了下面的问题:控件成员可以不在创建控件的线程中使用!!如FormWait.Close();调用此语句的是线程池中的线程,而FormWait是在另外的线程中创建。不知道是什么原因??按照必须在创建控件线程调用成员,则会抛异常。按照许多资料,这种情况也是非法调用,但在此却没有问题?!
    资料:

    一系列关于线程的入门文章,非常好

    http://www.yoda.arachsys.com/csharp/threads/parameters.shtml

    关于UI

    http://msdn.microsoft.com/msdnmag/issues/03/02/Multithreading/

    关于Timer

    http://msdn.microsoft.com/msdnmag/issues/04/02/TimersinNET/default.aspx

  • 相关阅读:
    1461. Check If a String Contains All Binary Codes of Size K
    1460. Make Two Arrays Equal by Reversing Sub-arrays
    1466. Reorder Routes to Make All Paths Lead to the City Zero
    1464. Maximum Product of Two Elements in an Array
    js 获取select的值 / js动态给select赋值【转】
    js在HTML中的三种写法【转】
    php中 elseif和else if 的区别【转】
    PhpStorm 常用快捷键
    PhpStorm 2018最新汉化包 解决”设置”不可用问题【转】
    PHP json_encode里面经常用到的 JSON_UNESCAPED_UNICODE和JSON_UNESCAPED_SLASHES【转】
  • 原文地址:https://www.cnblogs.com/yran/p/3590105.html
Copyright © 2011-2022 走看看