I'm launching an external application from a ContextMenu, and I must block the the source application while the target application is running. To achieve this I'm using Process.WaitForExit()
to avoid the source application responding to events.
The problem is the context menu is still ahead the target application. Let's see it with a simple example:
This is the code I'm using for the example.
public MainWindow()
{
InitializeComponent();
this.ContextMenu = new ContextMenu();
MenuItem menuItem1 = new MenuItem();
menuItem1.Header = "Launch notepad";
menuItem1.Click += MyMenuItem_Click;
this.ContextMenu.Items.Add(menuItem1);
}
void MyMenuItem_Click(object sender, RoutedEventArgs e)
{
Process p = new Process();
p.StartInfo.FileName = "notepad.exe";
p.StartInfo.CreateNoWindow = false;
p.Start();
p.WaitForExit();
p.Close();
}
How could I make the ContextMenu to disappear before the target application is displayed?
One possible solution is to start process when menu is closed:
Tested and seems to work, but I doubt if idea with blocking UI thread for a long time is a good idea.
Blocking the UI thread (drawing, Window interaction) makes horrible UX: it looks like the application is frozen, which it actually is. I would go like this given the constraints:
Disabling the Window itself (
IsEnabled = false
) will achieve "I must block the source application" by not letting the user interact with your app, other than Moving, Resizing and Closing it. If you need to block exiting as well you can do so like this:It should be also general courtesy to the user to indicate you're waiting for notepad and once that's finished (closed) your app will be usable again, I did this in the window
Title
for simplicity and due to lack of any controls in the demo app.Based on the great ideas given by Jcl...
I found a simple solution using custom MenuItems for the menu. It delays the
MenuItem.Click()
event until the parentContextMenu
is closed.After some tests, this seems to work ok:
Since (in the comments) you say you are using
ICommand
s, I guess you are binding them in XAML and don't want to lose that.A general-purpose way (ugly, and won't allow you to have
CanExecute
bound to theEnabled
state of the menuitem, but the least ugly I could figure out in so little time) could be binding them to another property (for example:Tag
), while also binding to a singleClick
handler. Something like:In the XAML:
In the code-behind:
Note: This won't block the main application so if that is necessary, this answer won't work for you
The ui thread is being blocked so it can't undraw the context menu. Why you can see it over other programs likely has to do with how it is drawn on the screen. As noted in the Process.WaitForExit docs
So you need to change your code to this
and then