2

So basically I have a MainWindow, a class SetupViewModel defined in a separate cs file, and another class ImageViewModel in a separate cs file; I am wondering is there anyway I can invoke the operation in MainWindow from ImageViewModel. More details listed below:

  • in ImageViewModel, invoke the change in MainWindow as following (following code in MainWindow):

    this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal,
                    new Action(
                        delegate()
                        {
                                ((SetupViewModel)this.DataContext).ViewType = Convert.ToInt32(ViewTypes.ViewType2D);
                        }
                    )
                );
    
  • The ViewType variable is defined in SetupViewModel as follows

    private int _viewType;
        public int ViewType
        {
            get
            {
                return _viewType;
            }
            set
            {
                _viewType = value;
                OnPropertyChanged("ViewType");
            }
        }
    
  • Here is how I did, but was not successful; The invoke code in ImageViewModel:

    try { Action SwitchTo2DView = delegate() { ((CaptureSetupViewModel)System.Windows.Application.Current.MainWindow.DataContext).ViewType = Convert.ToInt32(ViewTypes.ViewType2D); };

                System.Windows.Application.Current.MainWindow.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, SwitchTo2DView);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Caught exception: " + ex.ToString());
            }
    

and the exception:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at CaptureSetupDll.ViewModel.LiveImageViewModel.<StartZStackPreview>b__2c()
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
   at System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
   at System.Delegate.DynamicInvokeImpl(Object[] args)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.WrappedInvoke(Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
   at System.Windows.Threading.DispatcherOperation.InvokeImpl()
   at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
   at System.Threading.ExecutionContext.runTryCode(Object userData)
   at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Windows.Threading.DispatcherOperation.Invoke()
   at System.Windows.Threading.Dispatcher.ProcessQueue()
   at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.WrappedInvoke(Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Boolean isSingleParameter)
   at System.Windows.Threading.Dispatcher.Invoke(DispatcherPriority priority, Delegate method, Object arg)
   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
   at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
   at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
   at System.Windows.Threading.DispatcherOperation.Wait(TimeSpan timeout)
   at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Boolean isSingleParameter)
   at System.Windows.Threading.Dispatcher.Invoke(DispatcherPriority priority, Delegate method)
   at CaptureSetupDll.ViewModel.LiveImageViewModel.StartZStackPreview()

I am a layman to C#; Any idea how I can make this work? Thanks a lot.

Nick Tsui
  • 524
  • 2
  • 9
  • 29
  • What's the InnerException and its stack trace? – SLaks May 07 '13 at 16:26
  • The exception window that is displayed while Visual Studio is open will offer this information. What you are doing is the correct way to Invoke the MainWindow from a second thread. – Security Hound May 07 '13 at 16:33
  • I am adding add a picture to show you what I am seeing. – Nick Tsui May 07 '13 at 16:38
  • @Ramhound:Yeah, I guess I am very confused, so I am here seeking help. – Nick Tsui May 07 '13 at 16:49
  • @SLaks: I have posted what I can see, does help in anyway? – Nick Tsui May 07 '13 at 16:50
  • @NickTsui - Have you tried to catch the exception? That isn't the normal caught exception dialog. – Security Hound May 07 '13 at 16:54
  • @Ramhound: How do I do catch an exception? – Nick Tsui May 07 '13 at 16:55
  • OK, I tried catching the exception, I am not sure if that will help in anyway, but I am out int he original thread. Looks like some information there. – Nick Tsui May 07 '13 at 17:02
  • @NickTsui - You should update the question with the current code with the exception catching. Could you also indicate which line exactly is causing the exception. Based on the exception it looks like you have a null exception reference to one of your Windows. – Security Hound May 07 '13 at 17:06
  • You should use this thing called a **debugger**. As the program runs, you step through the code. You will eventually find a point at which, when you move from one line to another, execution stops/jumps somewhere unexpected/ends. This is where the exception is happening. Re-run, then riiiight before this point, look at the instances/properties/methods being touched. One of them will be null. Or, inside the method/getter/setter, they will be touching a null. That's either your solution or your real question. –  May 07 '13 at 17:07
  • I'll bet you five bucks your DataContext is null at the time this is being called. Which means its probably being called too early. Which probably means you should push whatever you're doing off on the Dispatcher until the application is loaded. All of which are probably a little too advanced for you now. –  May 07 '13 at 17:09
  • @Will You are right, the DataContext is null! But I think my application is already being loaded at this point? – Nick Tsui May 07 '13 at 17:14
  • @NickTsui: Hey, where's my five bucks?!?! Your application isn't completely loaded at this point. You should check for null before accessing, first off. I don't know what is triggering this method, or when, but it might get triggered more than once when the form loads. So do your check and if null return. If that doesn't solve the problem, you'll have to check for null, and if null, drop an Action on the dispatcher that will try again later (like when the application is idled). Read this: http://msdn.microsoft.com/en-us/magazine/cc163328.aspx –  May 07 '13 at 17:49
  • @Will; Thanks a lot. I'd love to invite you for a cup of coffee for the $5; If you by any chance come by Tennessee. Leave me a message. I will look into it, and I will also try to work around it. So if you can post your answer here, I will accept it. Thanks again! – Nick Tsui May 07 '13 at 19:03

1 Answers1

3

I'll bet you five bucks your DataContext is null at the time this is being called. Which means its probably being called too early. Which probably means you should push whatever you're doing off on the Dispatcher.

While you may assume your application is completely loaded at the time this method is being called, it isn't necessarily true. To test this, set a breakpoint during debugging and check the DataContext to see if it's null.

If it is null, you have two choices. First, just return. Depending on how the method is being called, it may be called multiple times during load. A later call may reveal a non-null context.

The other option is to use the Dispatcher to re-call the method later, once the application is loaded.

Here's a little pseudocode which looks kind of like C# and may even compile:

public void CheckTheDataContext()
{
    // is it null?
    if(this.DataContext == null)
    {
        // then drop an Action re-invoking this method later
        // when the application idles out a bit
        Dispatcher.BeginInvoke((Action)(() =>
        {
            CheckTheDataContext();
        }), System.Windows.Threading.DispatcherPriority.ApplicationIdle);
        return;
    }
    DoSomethingElseWithTheContext(DataContext);
}