在单独的线程

时间:2015-07-25 08:10:38

标签: c# wpf multithreading

我在Windows窗体中有一个旧应用程序,它在许多地方对数据库进行一些搜索。有时需要花费很多时间,因此我决定在wpf中创建一个加载屏幕,以向用户显示某些内容正在单独的线程中加载。基本上它只是一个带有加载指示器(转动圆圈)的完全透明窗口。在我的主机和我的虚拟机上一切正常,但是当我试图将它部署到我们的演示环境时,它会开始加载指示器,并在几秒钟后消失,应用程序停止响应就像永远。我的第一个想法是,它是GPU加速的问题,它不能处理透明度,但它会显示几秒钟,因此它不会成为问题。所以我很可能做坏事。下面你可以看到我的代码,你注意到可能出错的东西/造成死锁吗?

  public class LoadingManager
  {
    public LoadingManager()
    { }
    public LoadingManager(string LoadingText)
    {
        loadingText = LoadingText;
    }

    private string loadingText = "Please wait ..";
    private Thread thread;
    private bool ThreadReadyToAbort = false;
    private BusyIndicatorView loadingWindow;

    public void BeginLoading()
    {
        this.thread = new Thread(this.RunThread);
        this.thread.IsBackground = true;
        this.thread.SetApartmentState(ApartmentState.STA);
        this.thread.Start();
    }

    public void EndLoading()
    {
        if (this.loadingWindow != null)
        {
            this.loadingWindow.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() =>
            { this.loadingWindow.Close(); }));
            while (!this.ThreadReadyToAbort) { }; // I also tried to remove this while but it didn't help
        }
        this.thread.Abort();
    }

    public void RunThread()
    {
        this.loadingWindow = new BusyIndicatorView();

        loadingWindow.tbLoadingCaption.Text = loadingText;
        this.loadingWindow.Closing += new System.ComponentModel.CancelEventHandler(waitingWindow_Closed);
        this.loadingWindow.ShowDialog();
    }

    void waitingWindow_Closed(object sender, System.ComponentModel.CancelEventArgs e)
    {
        Dispatcher.CurrentDispatcher.InvokeShutdown();
        this.ThreadReadyToAbort = true;
    }

EDIT。

我注意到在这台机器上它通常(有时它也会在第一次点击时失败)在我第一次点击搜索时起作用。如果我点击另一次,它会显示一秒钟而不是消失,应用程序停止响应。所以似乎Thread没有关闭,Dispatcher关闭失败?但没有例外被抛出......

1 个答案:

答案 0 :(得分:2)

您的BeginLoading方法可以在完成之前多次调用,因此可以创建多个wpf窗口。这会弄乱各种参考文献。也不要中止线程,让它自己决定。以下是两个变化:

public void BeginLoading()
{
    this.thread = new Thread(this.RunThread);
    this.thread.IsBackground = true;
    this.thread.SetApartmentState(ApartmentState.STA);
    this.thread.Start();
    while (this.loadingWindow == null) { } // <--- Add this line
}

public void EndLoading()
{
    if (this.loadingWindow != null)
    {
        this.loadingWindow.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() =>
        { this.loadingWindow.Close(); }));
        while (!this.ThreadReadyToAbort) { }; 
    }
    //this.thread.Abort(); // <-- Remove this line
}

此外,如果这只是一个忙碌的屏幕,我会说必须有一个比这更好,更安全的方式。出于学术目的,这是一个有趣的问题,但不是生产代码,特别是如果一些初级开发人员将来可以解决这个问题。

编辑:如果我将重复的callds之间的延迟减少到BeginLoading和EndLoading,我的机器上仍会崩溃。它可能与wpf窗口异步关闭的方式有关。我删除了Closed事件处理程序,并使用了一个布尔标志来指示窗口是“已加载”#39;与否,我没有看到任何问题:

public class LoadingManager2
{
  public LoadingManager2()
  { }
  public LoadingManager2(string LoadingText)
  {
    loadingText = LoadingText;
  }

  private string loadingText = "Please wait ..";
  private Thread thread;
  private MyWindow loadingWindow;
  private bool isLoaded = false;

  public void BeginLoading()
  {
    this.thread = new Thread(this.RunThread);
    this.thread.IsBackground = true;
    this.thread.SetApartmentState(ApartmentState.STA);
    this.thread.Start();
    while (!this.isLoaded) { };
  }

  public void RunThread()
  {
    this.loadingWindow = new MyWindow();
    this.isLoaded = true;
    this.loadingWindow.ShowDialog();
  }

  public void EndLoading()
  {
    this.loadingWindow.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() =>
    { 
      this.loadingWindow.Close();
      this.isLoaded = false;
    }));
    while (this.isLoaded) { }; 
  }
}
相关问题