zoukankan      html  css  js  c++  java
  • 黑马程序员 SaveFileDialog的跨线程调用 (专题三)

    <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IO开发S</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流

    我的博客园网址:http://www.cnblogs.com/lingzeng/MyPosts.html

       有编程基础的道友恐怕对 SaveFileDialog都不陌生,一个保存对话框,所以今天目的不是对SaveFileDialog用法的探讨。

     今天我所讲述的是SaveFileDialog的跨线程问题,相信很对人都试过在单击事件按钮下弹出SaveFileDialog进行操作,那么如果在一个事件下调用一个线程,且该线程所调用的方法中有队SaveFileDialog的操作,这个时候会出现什么情况?

    下面的代码做出演示:

      首先解释,该代码是一个客户端发出一个发送文件请求,服务端收到该请求后弹出一个SaveFileDialog进行路径的保存。

    客户端的代码省略,附上服务器代码:

               private void button1_Click(object sender, EventArgs e)
            {
                 //线程,调用下面的一段程序method1()
            }

              //省略代码

             method1():

          ...........................................
                    else if (revMes[0] == 1)//1代表对方发送来的是文件
                    {
                        SaveFileDialog sf = new SaveFileDialog();
                        byte[] revMesToTrue = new byte[length - 2];
                        //自定义规则0-〉图片,1-〉文本文件,2->音频文件,3-〉屏幕截图
                        if (revMes[1] == 0)
                        {
                            sf.Filter = "图片|*.jpg;*.png;*.gif;*.JPG;*.PNG;*.GIF";
                            txtRecord.AppendText("接收到服务器图片文件 ");
                        }
                        else if (revMes[1] ==1)
                        {
                            sf.Filter = "文本文件|*.txt";
                            txtRecord.AppendText("接收到服务器文本文件 ");
                        }
                        else if (revMes[1] == 2)
                        {
                            sf.Filter = "音频文件|*.mp3;*.wav;*.3gp";
                            txtRecord.AppendText("接收到服务器音频文件 ");
                        }
                        else if(revMes[1]==3)//3代表截取屏幕
                        {
                            //将图片放在picturebox上,之后将截图窗口的背景图片设为该图
                             Buffer.BlockCopy(revMes, 2, revMesToTrue, 0, revMesToTrue.Length);
                             MemoryStream memorystream = new MemoryStream(revMesToTrue);

                             pictureBox1.Image = Image.FromStream(memorystream);//770
                             while (this.Width < 770)
                             {
                                 this.Width += 50;
                                 Thread.Sleep(500);
                             }
                             截图窗口 jietu = new 截图窗口();

                             for (int i = 0; i < jietu.Controls.Count; i++)
                             {
                                 if (jietu.Controls[i] is PictureBox)
                                 {
                                     PictureBox picturebox = jietu.Controls[i] as PictureBox;
                                     picturebox.Image = Image.FromStream(memorystream);
                                 }
                             }
                             jietu.Show();
                             Application.Run(jietu);
                              return;
                        }
                        //保存文件对话框
                        if (sf.ShowDialog() == DialogResult.OK)
                        {
                            using (FileStream fs = new FileStream(sf.FileName, FileMode.Create, FileAccess.Write))
                            {
                                // byte[] sendMsg = new byte[1024 * 1024 * 5];
                                Buffer.BlockCopy(revMes, 2, revMesToTrue, 0, revMesToTrue.Length);
                                fs.Write(revMesToTrue, 0, revMesToTrue.Length);
                            }
                            txtRecord.AppendText("将文件保存到了" + sf.FileName + "下面 ");
                        }
                        else
                        {
                            txtRecord.AppendText("你放弃了保存文件 ");
                        }

            .........................................

    注意红色部分为SaveFileDialog的操作,执行该代码后发现即使收到文件请求,SaveFileDialog对话框也并未弹出。

    经过调试,以及msdn查看,发现问题在sf.ShowDialog();

    这里大家看sf.ShowDialog()的两个相关函数

      //
            // 摘要:
            //     用默认的所有者运行通用对话框。
            //
            // 返回结果:
            //     如果用户在对话框中单击“确定”,则为 System.Windows.Forms.DialogResult.OK;否则为 System.Windows.Forms.DialogResult.Cancel。
            [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
            public DialogResult ShowDialog();
            //
            // 摘要:
            //     运行具有指定所有者的通用对话框。
            //
            // 参数:
            //   owner:
            //     任何实现 System.Windows.Forms.IWin32Window(表示将拥有模式对话框的顶级窗口)的对象。
            //
            // 返回结果:
            //     如果用户在对话框中单击“确定”,则为 System.Windows.Forms.DialogResult.OK;否则为 System.Windows.Forms.DialogResult.Cancel。
            public DialogResult ShowDialog(IWin32Window owner);
        }

    不带参数的sf.ShowDialog()表示默认当前所有者运行对话框,而在本程序中所有者为用户自定义的,并非在button_click()所在的ui界面

    所以大家看第二个带参数sf.ShowDialog(IWin32Window owner),运行具有指定所有者的通用对话框。

    这里我们传一个参数 this 即sf.ShowDialog(this),this代表当前的Form()窗体,再次运行即可成功实现。

    附:从网上搜的另一个方法(没有验证)

         在调用的线程后加上thr.SetApartmentState(ApartmentState.STA)这一句就可以了。这句的意思是在线程启动之前设置线程的单元状态为STA,MSDN中将这种问题定义为“STA 线程失去线程令牌”,它将导致作为一个的结果来打开文件、数据库,和等上的安全调用可能会失败。

    <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IOS开发</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! ----------------------


    <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IO开发S</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>

  • 相关阅读:
    学习视频收集
    vscode 编译器插件
    vue2.0父子组件之间传值
    js 案例
    插件
    【转】30分钟掌握 C#6
    【初码干货】关于.NET玩爬虫这些事
    上机作业七 系统进程与计划任务管理
    客户端与服务器双向密钥对验证
    DHCP中继配置
  • 原文地址:https://www.cnblogs.com/lingzeng/p/3204271.html
Copyright © 2011-2022 走看看