zoukankan      html  css  js  c++  java
  • 使用线程新建WPF窗体(公用进度条窗体)

    使用线程新建窗体

    项目中需要一个公用的进度条窗体.大家知道在wpf中,有两个线程,一个是UI线程,另一个是监听线程(一直监听用户的输入).如果我们后台有阻塞UI线程的计算存在,那么界面上的比如进度条什么动态的UI都会被因为阻塞而静止不动.

    所以我的想法就是新起一个线程来负责进度条窗体的显示与关闭,具体实现代码如下:

     

    复制代码
       private static Thread th;
            /// <summary>
            /// 显示进度条 线程
            /// </summary>
            /// <param name="msg">进度条界面需要显示的文字</param>
            /// <param name="sleep">增加进度条存在的延迟时间,单位为毫秒</param>
            public static void BeginProgressBar(string msg, int sleep)
            {
                try
                {
                    if (th == null || th.ThreadState == ThreadState.Aborted)
                    {
                        th = new Thread(new ThreadStart(() =>
                       {
                           WinProgressBar win = new WinProgressBar();
                           win.Tips = msg;
                           win.Topmost = true;
                           win.Show();
                           System.Windows.Threading.Dispatcher.Run();
                       }));
    
                        th.SetApartmentState(ApartmentState.STA);
                        th.IsBackground = true;
                    }
                    if (th.ThreadState != ThreadState.Background || th.ThreadState == ThreadState.Unstarted || th.ThreadState != ThreadState.Running)
                    {
                        th.Start();
                    }
                }
                catch (Exception)
                {
                    th = new Thread(new ThreadStart(() =>
                    {
                        WinProgressBar win = new WinProgressBar();
                        win.Tips = msg;
                        win.Topmost = true;
                        win.Show();
                        System.Windows.Threading.Dispatcher.Run();
                    }));
    
                    th.SetApartmentState(ApartmentState.STA);
                    th.IsBackground = true;
                    th.Start();
                }
                Thread.Sleep(sleep);
            }
    
            /// <summary>
            /// 结束进度条
            /// </summary>
            public static void EndProgressBar()
            {
                if (th.IsAlive)
                    th.Abort();
            }
    复制代码

     

    呵呵,大家仔细分析下代码看有什么问题没有?而你们又有什么好的解决方案没有?

    在使用过程中发现一个很严重的问题,出现一个进度条窗体,系统内存就会增大一点,到最后要么卡死,要么自动退出.

         原来在多线程程序运行中,由用户取消操作是一种非常常见的场景,比如用户使用windows资源管理器在当前文件夹中搜索文件时,可以通过点击其它文件夹而取消搜索。
    中途停止一个线程的执行,通常用Thread.Abort方法,但这种方式会造成程序涉及的数据完整性受到破坏,线程所占用的一些系统资源(比如文件句柄等)也可能无法完成。比较合理的方式是外界提出"取消操作"的请求,然后由线程自身来决定如何处理这一请求。
    在设计多线程程序时,可设置一个用于接收外部取消消息的属性,然后在线程函数中分阶段地检测这一属性,每个阶段的检查点由软件开发者确定,并且决定线程如何优雅退出。

    所以对上述代码进行了改进

    首先设置一个公共变量:

     public static bool IsClsoeProgeressBar = true;

    然后在进度条窗体中实时读这个数据

     

    复制代码
    /// <summary>
        /// WinProgressBar.xaml 的交互逻辑
        /// </summary>
        public partial class WinProgressBar : Window
        {
            public string Tips { get; set; }
    
            DispatcherTimer timer;
            public WinProgressBar()
            {
                InitializeComponent();
    
                timer = new DispatcherTimer();
                timer.Interval = TimeSpan.FromMilliseconds(200);
                timer.Tick += new EventHandler(timer_Tick);
                timer.IsEnabled = true;
    
                this.Topmost = true;
                //this.Loaded += delegate
                //{
                //    if (this.Tips != "")
                //        tbTips.Text = this.Tips;
                //};
            }
    
            void timer_Tick(object sender, EventArgs e)
            {
                if (Common.CommWindow.IsClsoeProgeressBar)
                {
                    if (this.Visibility == Visibility.Visible)
                    {
                        progressBar1.IsIndeterminate = false;
                        this.Hide();
                    }
                }
                else
                {
                    if (this.Visibility != Visibility.Visible)
                    {
                        progressBar1.IsIndeterminate = true;
                        this.Show();
                    }           
                }
            }
        }
    复制代码

     

    然后在系统加载的时候,创建这个进度条窗体

    复制代码
       try
                {
                    Thread th = new Thread(new ThreadStart(() =>
                    {
                        WinProgressBar win = new WinProgressBar();
    
                       // win.Tips = msg;
                        win.Show();
    
                        System.Windows.Threading.Dispatcher.Run();
    
                    }));
    
                    th.SetApartmentState(ApartmentState.STA);
                    th.IsBackground = true;
    
                    th.Start();
                }
                catch (Exception)
                {
                }
    复制代码

    我们只需改变公共变量来控制窗体的显示与隐藏

    复制代码
             /// <summary>
            /// 显示进度条 线程
            /// </summary>
      
            public static void BeginProgressBar()
            {
                IsClsoeProgeressBar = false;
            }
    
            /// <summary>
            /// 结束进度条
            /// </summary>
            public static void EndProgressBar()
            {
                //cts.Cancel();
                IsClsoeProgeressBar = true;
            }
    复制代码

    还有一个比较好的方法:

    复制代码
     #region Methods
    
            /// <summary>
            /// 一个耗时的任务
            /// </summary>
            private void BigTask()
            {
                Thread.Sleep(3000);
            }
    
            private void button1_Click(object sender, RoutedEventArgs e)
            {
                MyProgressBar(BigTask);
            }
    
            private void MyProgressBar(Action mywork)
            {
                var worker = new BackgroundWorker();
                var window = new BusyWindow();
                worker.DoWork += (s, e2) => { mywork(); };
                worker.RunWorkerCompleted += (s, e2) =>
                {
                    MessageBox.Show("任务已经完成");
                    window.Close();
                };
                worker.RunWorkerAsync();
                window.Show();
            }
    
            #endregion
    复制代码

    这个由网友热情的沙漠提供,也很不错,大家可以参考下


  • 相关阅读:
    Summary for sql join in Oracle DB
    Merge data into table in Oracle
    PLSQL存储过程传出大量异常错误信息
    oracle 11g plsql解析json数据示例
    识别'低效执行'的SQL语句
    如何开启MySQL 5.7.12 的二进制日志
    Linux下ps命令详解 Linux下ps命令的详细使用方法
    Linux(Unix)时钟同步ntpd服务配置方法
    MySQL 常用命令总结
    MySQL 数据库通过日志恢复
  • 原文地址:https://www.cnblogs.com/keanuyaoo/p/3297099.html
Copyright © 2011-2022 走看看