Problems loading a screen in a separate thread

I have an old application in Windows Forms that in many places does some database searches. Sometimes it takes a lot of time, so I decided to create a loading screen in wpf to show the user that something is loading into a separate stream. Basically it is just a transparent window with a loading indicator (turntable). Everything works fine on my host computer and on my virtual machine, but when I try to deploy it in our demo environments, it seems like it starts to load, the indicator displays, and after a few seconds it disappears, and the application stops responding like forever. My first thought was that this is a GPU acceleration issue, that it cannot handle transparency, but it displays for a few seconds, so this may not be a problem. Therefore, most likely, I did something bad. Below you can see my code, did you notice something that might be wrong / cause a dead end or something like that?

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.

I noticed that on these machines it usually (sometimes it also fails on the first click) works when I click search for the first time. If I click again until it shows a second, but disappears, and the application stops responding. So, it looks like Thread was not turned off, Dispatcher shutdown failed? But no exceptions are thrown ...

+5
source share
1 answer

Your BeginLoading method can be called more than once before it completes and therefore can create more than one wpf window. This ruined all kinds of links. Also do not interrupt the flow, let it decide. Here are two changes:

 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 } 

Also, if it's all just for a busy screen, I would say that there should be a better and safer way than this. For academic purposes, this is an interesting problem, but not production code, especially if some junior developer could understand this.

Edit: there is still a crash on my machine if I reduce the delay between repeated caldes to BeginLoading and EndLoading. This may be due to the way the wpf window closes asynchronously. I removed the Closed event handler and simply used the boolean flag, indicating whether the window isLoaded or not, and I did not see any problems with this:

 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) { }; } } 
+2
source

All Articles