views:

282

answers:

2

Hi,

I am working through the requirement to make a WPF Application single instance only. However - I have to pass the command line to the first instance and then perform some UI action.

I am using a Mutext to check for already running instances, I do use NamedPipes to transfer the command line to the already running instance.

But of course I am not in the correct Thread to access "Window1". I tried to store a reference to "Window1" in a static class and then use the Dispatcher to call a Method in "Window1", however, as soon as I try to access a variable (class wide scope in "Window1") I receive a "Object reference not set to an instance of an object."

The UI Action is to add a new Tab to a TabControl - during initialization of the new Tab some work is done - and the variables are initialized and even the method I want to call works during the init - but when called from the Dispatcher it fails.

Any hints, how to do this? Am I on the wrong track here?

Thanks!

+2  A: 

That's not right, are you certain that the mutex is passing control correctly to your currently running instance of the application?

If it was a thread UI access issue, you should have received this error: The calling thread cannot access this object because a different thread owns it.

The fact that you're getting an "Object reference not set to an instance of an object." error message means that you've not yet instantiated the object as new.

Stephen Wrighton
I would agree with this assessment. I also believe that there is some other issue here. I would try to debug and find what object is null that you're trying to access.
Scott
It seems I came into some kind of race condition, as I have built step by step I was so fixed on why this damn objects where not initialized.My current working solution is the bad old DoEvents() lend from WinForms. Several tests showed that it is now working, as desired, but if anyone has a better idea than DoEvents() I woudl be happy,....Thanks!!
JerryVienna
+1 for the observation that it is not WPF's Dispatcher complaining
Ray Burns
+3  A: 

This is easy:

void ProcessCommandLine(string commandLine)
{
  Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(() =>
  {
    ... code to process the command line here ...
  });
}

You can call this from your App.Startup and also from your thread that receives messages from the named pipe.

The key considerations here are:

  1. Use of BeginInvoke instead of Invoke to prevent the calling thread from waiting
  2. Use of DispatcherPriority.ApplicationIdle to guarantee the application has finished initializing before the command line is processed
  3. Use of Application.Current.Dispatcher instead of Window1.Dispatcher in case Window1 has not yet been initialzed
Ray Burns
Great Info Ray. The solution I posted awhile back was something I ran across to solve a problem I had and simply forwarded that information on. I did a little more research and found the same thing you posted (that BeginInvoke will likely fix the OP's problem). I am interested in more information about the differences using a lambda expression rather than the callback. I use the code I posted in a few locations and am considering changing it if there is a better way. Do you have any links that go into a deeper explaination? Thanks again!
Scott
@Scott: The lambda expression is really just syntactic sugar. What makes the performance difference I mentioned in my other comment is skipping the call to Dispatcher.CheckAccess. Dispatcher.Invoke already does a Dispatcher.CheckAccess() internally, so doing it before calling Dispatcher.Invoke duplicates effort and clutters the code. When you are on the same thread the performance is equivalent but when you aren't, CheckAccess() gets called thrice if we call it manually (once before the Invoke, once from the Invoke code, and once in the recursive call).
Ray Burns
Thanks again for the response! This is very interesting! All I find are articles(including msdn) that suggest adding Dispatcher.CheckAccess to prevent unneeded invokes (see links). I don't intend to sound doubtful, but I was hoping you could point me to some documentation. Thanks for sharing your knowledge!Links:http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.checkaccess(VS.100).aspxhttp://social.msdn.microsoft.com/Forums/en-US/wpf/thread/14f7ca5e-fb1c-433e-94d4-269c3ddcedechttp://blog.decarufel.net/2009/03/good-practice-to-use-dispatcher-in-wpf.html
Scott
@Scott: None of these three links apply: 1. The example in the CheckAccess docs is for deciding between a direct call and BeginInvoke (not Invoke), so it actually changes the timing. 2. The forum post is only valid at lower DispatcherPriority values: At DispatcherPriority.Send, Invoke does a direct call, no queue is involved. You can verify this by trying a BeginInvoke followed by an Invoke on the UI thread. The Invoke will execute first. 3. Eric De C# misreads the material he quotes, specfically he reads "VerifyAccess" as "CheckAccess" then proceeds on the resulting misunderstanding.
Ray Burns
Thanks again! I appreciate you taking the time to answer my questions!
Scott
Gents thanks for the infos!
JerryVienna