文章出處

使用線程新建窗體

項目中需要一個公用的進度條窗體.大家知道在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

這個由網友熱情的沙漠提供,也很不錯,大家可以參考下

 


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()