Reputation: 4440
We have a project that have a couple years development invested into and it now need a progress window because some process are very long. We deal with 3D CAD, advanced engineering, Simulations Third Party DLL, Web services, WCF services.
Now i am trying to add a generic process window you can start in 1 place and end anywhere else. that's not complicated per say. simple static class that open a window on MyClass.Open(string Message)
and a MyClass.Close()
to hide it once the heavy duty code completed. This works perfectly except the heavy code block the Thread.
The project is a mix of bunch of projects but this part is 99% WPF and i am fairly new to WPF threading as they don't behave like winforms. In winforms thread i create that open other forms are not block by main app heavy work. In WPF the copy pasted code the form is frozen.
I tried Thread and Background Worker without success. then to make sure it wasn't my window the issue or my static class i tried opening the window manually with a Form.Show();
and a Form.Close();
in one of the heavy work function an the form still showed and close properly but yet still frozen. then i removed the Form.Close();
and it started to move right after the work completed. Now i find very strange that the main thread when working at full capacity freeze other threads. I have an actual Exact copy in winform for that progress window except that instead being a Form with label i have a WPF window with a label in a grid.
I tried doing it the right way which is creating a thread for the heavy function but compiler now give me 2,404 errors. I would have at least a week of work just o try if something works and i'd rather not as changing the whole project like so would take at least a year and half and we mostly have 2-3 weeks to complete this so i am looking or any solution that might help finishing that. I can be very dirty. as long as it works.
thank you very much.
Edit : @Baldrick requested more detail about thread.
I went very simple for thread.
public static class CWaitingMessage
{
private static frmWaiting window = new frmWaiting();
private static Thread t = null;
private static string Message = "";
public static void Open(string sMessage)
{
Message = sMessage;
t = new Thread(new ThreadStart(RunForm));
t.SetApartmentState(ApartmentState.STA);
t.IsBackground = true;
t.Start();
}
private static void RunForm()
{
try
{
window = new frmWaiting();
window.UpdateText(Message);
window.Show();
System.Windows.Threading.Dispatcher.Run();
}
catch
{
window.Close();
}
}
public static void Close()
{
if (t != null)
{
t.Abort("Completed");
}
}
}
If i use System.Windows.Threading.Dispatcher.Run();
instead while (ShowForm) { }
the form isn't frozen but my thread disappear by that i mean it never reach f.Close();
... ever.
Edit #2 : Managed to make the abort of the thread using the dispatcher.Run but now i have a bigger issue. the program never stop. the thread start, then i call the abort with a special catch on thread exception and on abort i call a method in the window to save the amount of time it's been opened and close the form. I checked and the file is created so the abort does work but if Dispatche.Run is calle in a thread that is aboded it seems to live on his own. now i have created a monster that never stop running. i close my app completely an visual studio still see it as running.
I am very close to forget about a solution in WPF and go for a winform form to show that message as i know it works perfectly in winforms without that freeze up annoyance.
Edit #3 : Updated my current class i use. I have checked my old exampled and background worker i was only doing a normal form load then running a background worker to loop. the form was in a the same thread as the main code which is completely normal as Background worker are MTA and therefore block UI thread. for UI i need Threads which are STA.
I cannot call dispatcher.Invoke to test it. i couldn't find the assembly for it. my compiler and intellisense don't like it by default :)
Upvotes: 3
Views: 920
Reputation: 4440
Found it. after 3 days of work.
For people wondering how to open and close a thread in WPF without freezing he main thread when the new form have animation and no process work.
public static class CWaitingMessage
{
private static event Action CloseWindow = delegate { };
public static void Open(string sMessage)
{
Thread t = new Thread(delegate()
{
frmWaiting window = new frmWaiting(sMessage);
CloseWindow += () => window.Dispatcher.BeginInvoke(new ThreadStart(() => window.Close()));
window.Closed += (sender2, e2) => Window.Dispatcher.InvokeShutdown();
window.Show();
System.Windows.Threading.Dispatcher.Run();
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
public static void Close()
{
CloseWindow();
}
}
Note that no error handling and multiple window opening is supported. this is simple the skeleton working and ready to use. I know at least 2 handful of people that will be very interested in this piece of code.
If you required process also on that window background worker works perfectly in the window. This is very useful for mouse over over a grid being filled asynchronously and while you mouse over you can still open secondary window with another DataGrid and heavy work without issue.
Upvotes: 3
Reputation: 69959
The Thread
class is not used so much these days as there are now much simpler ways of creating asynchronous methods. For example, please take a look at the Task
Class page on MSDN for examples on how to easily create asynchronous methods in WPF.
If you are using .NET 4.5, you can also use the new async
and await
keywords for even easier asynchronous methods. Please see the await (C# Reference) page on MSDN for a detailed description of this new functionality with code examples.
Having said that, using a BackgroundWorker
may actually be your best bet for implementing ProgressBar
update functionality with its easy access to update the UI on the UI thread. Please take a look at the BackgroundWorker
Class page on MSDN for a full example.
If you need specific help with something, please edit your question in order to add the relevant code.
Upvotes: 3