在单独的线程中显示WPF ProgressBar窗口

时间:2012-10-18 10:59:14

标签: c# wpf xaml mvvm

我想在运行耗时的任务时显示一个带有Indeterminate="True"进度条的简单WPF窗口。

我在this示例之后实施了我的解决方案 - Reed Copsey。

一旦完成该过程,我需要关闭窗口。 我的猜测是要实现这一点,我要么要杀死线程要么关闭视图(窗口)。

不幸的是,两种方式都会给我以下错误:

1)在线程上调用Abort()

窗口关闭,这是正确的,但我仍然收到以下错误:

无法评估表达式,因为代码已优化或本机框位于调用堆栈之上

2)View.Close()

调用线程无法访问此对象,因为另一个线程拥有它。

需要在StopThread()方法中实现所需的逻辑,知道如何优雅地关闭Window:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Threading;
using Microsoft.Practices.Composite.Presentation.Commands;

namespace ProgressBar
{
    public class ProgressBarViewModel
    {
        public DelegateCommand<object> CloseCommand { get; set; }
        Thread newWindowThread;

        string _closeButton;
        public string CloseButton 
        {
            get { return _closeButton; }
            set { _closeButton = value; }
        }

        ProgressBarView _view;
        public ProgressBarView View
        {
            get { return _view; }
            set { _view = value; }
        }

        public ProgressBarViewModel(ProgressBarView view)
        {
                CloseButton = "Close";
                CloseCommand = new DelegateCommand<object>(CloseForm);

                View = view;
                View.Closing +=new System.ComponentModel.CancelEventHandler(View_Closing);
                View.DataContext = this;
        }

        public void View_Closing(object sender,CancelEventArgs e)
        {
            StopThread();
        }

        public void CloseForm(object p)
        {
            StopThread();
        }

        private void StopThread()
        {
            try
            {
                //View.Close();
                newWindowThread.Abort();
            }
            catch (Exception eX)
            {
                Debugger.Break();
                //Getting an error when attempting to end the thread:
                //Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack
            }
        }

        public void ShowProgress()
        {
                newWindowThread = new Thread(new ThreadStart(() =>
                {
                    ProgressBarView tempWindow = new ProgressBarView();
                    tempWindow.DataContext = this;
                    tempWindow.Show();
                    System.Windows.Threading.Dispatcher.Run();
                }));

                newWindowThread.SetApartmentState(ApartmentState.STA);
                newWindowThread.IsBackground = true;
                newWindowThread.Start();
        }
    }
}

2 个答案:

答案 0 :(得分:0)

您应该做的是将您的操作封装在自己的类中,并在事件完成时(或者您想要关闭视图)引发事件

事件处理程序需要使用Dispatcher在与视图相同的线程中运行close()

答案 1 :(得分:0)

也许您应该考虑使用BackgroundWorker进行此操作?您可以响应RunWorkerCompleted事件以关闭视图。

public void YourFunction(Dispatcher dispatcher)
{
    BackgroundWorker bw = new BackgroundWorker();
    bw.DoWork += (sender, args) =>
      {
         ...do your long running operation
      };

    bw.RunWorkerCompleted += (sender, args) =>
      { 
         dispatcher.BeginInvoke(...close your view here);
      }

    bw.RunWorkerAsync();
}