Dispatcher.CurrentDispatcher.BeginInvokeShutdown closes the main thread c# - c#

I am opening a wpf UI in a separate thread using
helperThread = new Thread(() =>
{
//ShowHelpInDialog(e.Url, -1, -1, -1, -1, e.HelpContext);
//System.Windows.Threading.Dispatcher.Run();
dispatcher.Invoke(new Action(() => ShowHelpInDialog(e.Url, -1, -1, -1, -1, e.HelpContext)));
});
helperThread.SetApartmentState(ApartmentState.STA);
helperThread.IsBackground = true;
helperThread.Start();
During dialog close event, I am calling
Dispatcher.CurrentDispatcher.BeginInvokeShutdown(DispatcherPriority.Background);
which is causing main thread/Application to close, Which i don't want.
I don't want my parent application to close.

Please observe the following example on how to open a new Window from another thread:
private void NewWindowHandler(object sender, RoutedEventArgs e)
{
Thread newWindowThread = new Thread(new ThreadStart(ThreadStartingPoint));
newWindowThread.SetApartmentState(ApartmentState.STA);
newWindowThread.IsBackground = true;
newWindowThread.Start();
}
private void ThreadStartingPoint()
{
Window1 tempWindow = new Window1();
tempWindow.Show();
System.Windows.Threading.Dispatcher.Run();
}
From the Multiple Windows, Multiple Threads section of the Threading Model page at MSDN.
UPDATE >>>
This code is 100% tested and will definitely open a new Window in a new thread. If you don't want to shut down the other Window, then don't call the BeginInvokeShutdown method which will shut the Window down. You're calling it on Dispatcher.CurrentDispatcher which is running on the MAIN thread (where the MainWindow.xaml is running).

You would have to invoke BeginInvokeShutdown on the dialog's Dispatcher not on Dispatcher.CurrentDispatcher.
Your dialog closed event handler should look like this:
dialog.Closed += (sender, e) => dialog.Dispatcher.BeginInvokeShutdown();

Related

how to avoid Server busy window if used thread.join() in wpf c#

I have a c++ application and use clr to call the below c# method. Everything is going good except for one thing. As wpf window needs STA thread, I'm trying to create a new thread with STA state and start it. This makes the wpf window modeless, even if the window is started with show dialog. So I tried using thread.join() to make the caller thread to wait until the thread completes or window closes. using thread.join() shows server busy window after a few seconds. (I'm not doing any operation related to the internet in my application).
How to make the caller thread to wait until the window closes? or How to get rid of Server busy window?
void ShowWindow()
{
_ownerHandle = Process.GetCurrentProcess().MainWindowHandle;
Thread newWindowThread = new Thread(new ThreadStart(() =>
{
MyWpfWindow window = new MyWpfWindow();
MyWpfWindowViewModel vm = new MyWpfWindowViewModel();
WindowInteropHelper helper = new WindowInteropHelper(window);
helper.Owner = _ownerHandle;
window.DataContext = vm;
window.ShowDialog();
}));
// set the apartment state this will only invoke the WPF window
newWindowThread.SetApartmentState(ApartmentState.STA);
newWindowThread.IsBackground = true;
// start the thread
newWindowThread.Start();
//waits this thread here untill the newWindowThread execution completes.
newWindowThread.Join();
}
Also, I tried with a while loop as below to block the current main thread.
while(!windowShown)
{
}
in the place of newWindowThread.join(). After using this, my window is not visible.
I'm getting a server busy window as below
Calling Join() blocks the current thread. If you want to wait asynchronously, you could use a SemaphoreSlim:
static async Task ShowWindowAsync()
{
SemaphoreSlim semaphore = new SemaphoreSlim(0, 1);
_ownerHandle = Process.GetCurrentProcess().MainWindowHandle;
Thread newWindowThread = new Thread(new ThreadStart(() =>
{
MyWpfWindow window = new MyWpfWindow();
MyWpfWindowViewModel vm = new MyWpfWindowViewModel();
WindowInteropHelper helper = new WindowInteropHelper(window);
helper.Owner = _ownerHandle;
window.DataContext = vm;
window.Closed += (s, e) =>
{
semaphore.Release();
semaphore.Dispose();
};
window.ShowDialog();
}));
// set the apartment state this will only invoke the WPF window
newWindowThread.SetApartmentState(ApartmentState.STA);
newWindowThread.IsBackground = true;
// start the thread
newWindowThread.Start();
//waits this thread here untill the newWindowThread execution completes.
await semaphore.WaitAsync();
}

DispatcherTimer and Show Modal Window

Let's see if anyone can explain me this behaviour and maybe how can I solve this. I have a WPF app, and in my ViewModel I have a DispatcherTimer. In that ViewModel i have a command to show a modal window, something like this:
private void ShowWindowCommandExecuted()
{
wnNewWindow window = new wnNewWindow();
window.ShowDialog();
}
When i call this Command from a button, the new window is shown and the DispatcherTimer keeps running in the background. So far so good. The problem is when i try to show the window from the DispatcherTimer like this:
DispatcherTimer timerInstrucciones;
timerInstrucciones = new DispatcherTimer();
timerInstrucciones.Interval = TimeSpan.FromMilliseconds(1000);
timerInstrucciones.Tick += (s, e) =>
{
wnNewWindow window = new wnNewWindow();
window.ShowDialog();
};
timerInstrucciones.Start();
In this case, the new window is also shown, but as long it is visible, the DispatcherTimer stops "ticking". I understand the DispatcherTimer runs in the UI thread, but why it behaves in a different way in this case?
Generally, ShowDialog is a modal dialog that will block the calling thread, and show the dialog. It will also block interaction with the parent/owning window too.
As long as you close the Modal Dialog, the UI-Thread is blocked. Because its a DispatcherTimer, it belongs to the Window's Dispatcher and runs in the same thread. So if this thread is blocked, the DispatcherTimer stops running.
UPDATE BASED ON YOUR COMMENTS:
I haven't went through any documentation on this, but the basic difference would be DispatcherTimer will run Synchronously and not in Asynchronous way.
Won't block the Dispatcher:
timerInstrucciones.Tick += (s, e) =>
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
wnNewWindow mn = new wnNewWindow();
mn.ShowDialog();
}));
};
Will block the Dispatcher:
timerInstrucciones.Tick += (s, e) =>
{
this.Dispatcher.Invoke(new Action(() =>
{
wnNewWindow mn = new wnNewWindow();
mn.ShowDialog();
}));
};
Since, Dispatcher will Invoke the Event on every n seconds, Event cannot be called anymore, if the thread got blocked for any operation inside the calling Event .

DispatcherTimer not firing in wpf app

I refactored my WPF code recently and now my DispatcherTimer stopped firing. I checked other similar posts here, but they all seemed to be problems with having the wrong dispatcher thread set, which I tried...
My code looks like this:
class MainWindow : Window
{
private async void GoButton_Click(object sender, RoutedEventArgs e)
{
Hide();
m_files = new CopyFilesWindow();
m_files.Show();
m_dispatcherTimer = new DispatcherTimer();
m_dispatcherTimer.Tick += dispatcherTimer_Tick;
m_dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 250);
m_dispatcherTimer.Start();
await SomeLongRunningTask();
m_files.Hide();
Show();
}
(The current class is my main Window object, which I hide for the duration of file copying. CopyFilesWindow is a simple Xaml window that contains controls I modify...CopyFilesWindow does absolutely nothing itself.)
Basically, I await a long running task (copying a bunch of large files), and my DispatcherTimer is supposed to update the progress in dispatcherTimer_Tick. However, I set a breakpoint on that function and it doesn't get hit.
I have also tried setting the Dispatcher with the constructor like so:
m_dispatcherTimer = new DispatcherTimer(DispatcherPriority.Normal, m_files.Dispatcher);
m_dispatcherTimer = new DispatcherTimer(DispatcherPriority.Normal, this.Dispatcher);
But neither of these things change the behavior...it still doesn't fire.
What am I doing wrong here?
The DispatcherTime runs on the ... Dispatcher thread. Which is stuck waiting SomeLongRunningTask() to finish.
Indeed, when you press the button Go, it is the dispatcher thread which executes GoButton_Click. Thus, you should never make a method called by UI (the dispatcher thread) async.
private void GoButton_Click(object sender, RoutedEventArgs e)
{
Hide();
m_files = new CopyFilesWindow();
m_files.Show();
m_dispatcherTimer = new DispatcherTimer();
m_dispatcherTimer.Tick += dispatcherTimer_Tick;
m_dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 250);
m_dispatcherTimer.Start();
SomeLongRunningTask.ContinueWith(() =>
{
// Executes this once SomeLongRunningTask is done (even if it raised an exception)
m_files.Hide();
Show();
}, TaskScheduler.FromCurrentSynchronizationContext()); // This paramater is used to specify to run the lambda expression on the UI thread.
}

How to wait a thread out of that thread without freeze my APP?

I'm running some scripts in runtime, but it's freezing my UI, I'm calling the CodeProvider inside a Thread, but it still freezing.
In my form I call:
var mre = new ManualResetEvent(false);
Thread tr = new Thread(() =>
{
Script sp = new Script();
code = textBox.Text;
sp.Comp(code);
mre.Set();
});
tr.Start();
mre.WaitOne();
I'm using the mre.WaitOne() because I want to wait the thread finish to keep running my code.
Tried to use the same way inside the Compile method too:
public bool Comps(string code)
{
var mre = new ManualResetEvent(false);
Thread tr = new Thread(() =>
{
//Code to generate a CompilerResult and generate the assembly
Run();
mre.Set();
});
tr.Start();
mre.WaitOne();
return true;
}
But while it's waiting it still freezing the UI.
Any ideas?
Thanks
I'm using the mre.WaitOne() because I want to wait the thread finish
to keep running my code.
What did you expect to happen if you force the calling thread to freeze until your processing thread has completed processing? Doing it this way, there is no point in having that extra thread and if the calling thread is the UI thread, of course it will freeze.
If you do background processing you cannot wait for the result synchronously, instead you have to notify the UI in some sort of fashion that the processing is done, i.e. using a callback or dispatching the result back to the UI in some other form.
The entire point of multi-threading is to allow the Thread to execute on it's own, independent of any other threads. What you want to do is use a callback to signal the completion of your thread and then have your UI respond to the completion.
The BackgroundWorker class has an event already built in for this purpose.
There are three events you want to subscribe to:
bw.DoWork +=
new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged +=
new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
DoWork is where your work will happen. ProgressChanged allows you to update the UI of progress. RunWorkerCompleted will pop the event with your DoWork function has completed.
This object handles the threading and can be set to run asynchronously by running the bw.RunWorkerAsync() call.
See the following page for detail for this:
http://msdn.microsoft.com/en-us/library/cc221403%28v=vs.95%29.aspx
As an example:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show(String.Format("UI thread: {0}", Thread.CurrentThread.ManagedThreadId));
this.Invoke(new MethodInvoker(delegate() { MessageBox.Show(String.Format("Invoke thread: {0}", Thread.CurrentThread.ManagedThreadId)); }));
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
MessageBox.Show(String.Format("Worker thread: {0}", Thread.CurrentThread.ManagedThreadId));
}
}
This example can be built by adding one button and one background worker to a form. Wire up the events through the events designer for the button1_Click and the backgroundWorker1_DoWork function. You should have three MessagesBoxes that pop up after clicking button1. You'll notice the Id for the UI thread and the Invoke thread are the same, which means that any processing you do from the invoke will cause your UI thread to wait. The third popup is from the worker thread, which has a different ID.
Use BeginInvoke when done. For example:
delegate void MyAction();
void Form1_Load( object sender, EventArgs e )
{
Thread tr = new Thread( () =>
{
Script sp = new Script();
code = textBox.Text;
sp.Comp(code);
BeginInvoke( new MyAction( ThreadOperationEnded ) );
} );
tr.Start();
}
void ThreadOperationEnded()
{
MessageBox.Show( "Finished!" );
}

How to update textbox in new window opened by new thread?

I am able to open a new window in a new thread by the following code.
The following code is from MainWindow.xaml.cs
private void buttonStartStop_Click(object sender, RoutedEventArgs e)
{
Test test = new Test();
Thread newWindowThread = new Thread(new ThreadStart(test.start));
newWindowThread.SetApartmentState(ApartmentState.STA);
newWindowThread.IsBackground = true;
newWindowThread.Start();
}
and the following from test.start()
public void start()
{
OutputWindow outputwindow = new OutputWindow();
outputwindow.Show();
Output.print("Begin");
System.Windows.Threading.Dispatcher.Run();
Output.print("FINAL");
System.Windows.Threading.Dispatcher.Run();
}
And the following is from the Output class
public static void print(String str)
{
Dispatcher uiDispatcher = OutputWindow.myOutputWindow.Dispatcher;
uiDispatcher.BeginInvoke(new Action(delegate() { OutputWindow.myOutputWindow.textBoxOutput.AppendText(str + "\n"); }));
uiDispatcher.BeginInvoke(new Action(delegate() { OutputWindow.myOutputWindow.textBoxOutput.ScrollToLine(OutputWindow.myOutputWindow.textBoxOutput.LineCount - 1); }));
}
public static void printOnSameLine(String str)
{
Dispatcher uiDispatcher = OutputWindow.myOutputWindow.Dispatcher;
uiDispatcher.BeginInvoke(new Action(delegate() { OutputWindow.myOutputWindow.textBoxOutput.AppendText(str); }));
uiDispatcher.BeginInvoke(new Action(delegate() { OutputWindow.myOutputWindow.textBoxOutput.ScrollToLine(OutputWindow.myOutputWindow.textBoxOutput.LineCount - 1); }));
}
"Begin" Does get printed in the textbox but "FINAL" does not, I want the start method in Test class to update the textbox in outputwindow through out the program. What is the best way to do this?
Thank you in advance
I'm not sure what are you trying to do. It is normal that FINAL does not print because you called System.Windows.Threading.Dispatcher.Run(). This method keeps thread alive and listens for events. You can look at it like if you have while(true){} inside the Run method. Method will continue to run until Dispatcher is shutdown. You should keep background thread alive and call your static methods from another thread when you need to set a message. Here's an example:
// reference to window in another thread
Window outputWindow = null;
Thread thread = new Thread(() =>
{
// another thread
outputWindow = new Window();
outputWindow.Show();
// run event loop
System.Windows.Threading.Dispatcher.Run();
}) { ApartmentState = ApartmentState.STA, IsBackground = true };
thread.Start();
while (outputWindow == null)
{
// wait until the window in another thread has been created
Thread.Sleep(100);
}
// simulate process
for (int i = 0; i < 10; i++)
{
outputWindow.Dispatcher.BeginInvoke((Action)(() => { outputWindow.Title = i.ToString(); }), System.Windows.Threading.DispatcherPriority.Normal);
Thread.Sleep(500); // simulate some hard work so we can see the change on another window's title
}
// close the window or shutdown dispatcher or abort the thread...
thread.Abort();
EDIT:
This could be quick & dirty generic solution. DoSomeHardWork creates another GUI thread for wait window which displays progress information. This window creates work thread which actually does the work. Work is implemented in method Action. 1st argument is wait window so you can change it from work thread. Of course, in the real world you should go through interface and not directly to window implementation but this is just an example. 2nd argument is object so you can pass whatever you need to the work thread. If you need more arguments pass object[] or modify method signature. In this example I simulate hard work with counter and sleep. You can execute this code on button click multiple times and you will see all wait windows counting their own counter without freezing. Here is the code:
public static void DoSomeHardWork(Action<Window, object> toDo, object actionParams)
{
Thread windowThread = new Thread(() =>
{
Window waitWindow = new Window();
waitWindow.Loaded += (s, e) =>
{
Thread workThread = new Thread(() =>
{
// Run work method in work thread passing the
// wait window as parameter
toDo(waitWindow, actionParams);
}) { IsBackground = true };
// Start the work thread.
workThread.Start();
};
waitWindow.Show();
Dispatcher.Run();
}) { ApartmentState = ApartmentState.STA, IsBackground = true };
// Start the wait window thread.
// When window loads, it will create work thread and start it.
windowThread.Start();
}
private void MyWork(Window waitWindow, object parameters)
{
for (int i = 0; i < 10; i++)
{
// Report progress to user through wait window.
waitWindow.Dispatcher.BeginInvoke((Action)(() => waitWindow.Title = string.Format("{0}: {1}", parameters, i)), DispatcherPriority.Normal);
// Simulate long work.
Thread.Sleep(500);
}
// The work is done. Shutdown the wait window dispather.
// This will stop listening for events and will eventualy terminate
// the wait window thread.
waitWindow.Dispatcher.InvokeShutdown();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
DoSomeHardWork(MyWork, DateTime.Now);
}
Ideally the thread(UI thread) that creates the UI elements own's the elements too. With dispatcher all you are doing is that you are pushing the non-UI related processing into a background thread. Once the background process is completed, the result again will be pushed back to the main UI thread. For sample example check out : http://weblogs.asp.net/pawanmishra/archive/2010/06/06/understanding-dispatcher-in-wpf.aspx

Categories