我在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关闭失败?但没有例外被抛出......
答案 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) { };
}
}