4

I am getting an exception when I use Command binding in WPF and MVVM.

Stack trace:

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 xxx.TcpConnection.get_IsOpen() in C:\xxx\TcpConnection.cs:line 70
   at xxx.CommunicationViewModel.<.ctor>b__5_0() in C:\xxx\CommunicationViewModel.cs:line 53
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at GalaSoft.MvvmLight.Helpers.WeakFunc`1.Execute()
   at MS.Internal.Commands.CommandHelpers.CanExecuteCommandSource(ICommandSource commandSource)
   at System.Windows.Controls.Primitives.ButtonBase.UpdateCanExecute()
   at System.Windows.Controls.Primitives.ButtonBase.OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
   at System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
   at System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
   at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)
   at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType)
   at System.Windows.DependencyObject.InvalidateProperty(DependencyProperty dp, Boolean preserveCurrentValue)
   at System.Windows.Data.BindingExpressionBase.Invalidate(Boolean isASubPropertyChange)
   at System.Windows.Data.BindingExpression.TransferValue(Object newValue, Boolean isASubPropertyChange)
   at System.Windows.Data.BindingExpression.Activate(Object item)
   at System.Windows.Data.BindingExpression.AttachToContext(AttachAttempt attempt)
   at System.Windows.Data.BindingExpression.MS.Internal.Data.IDataBindEngineClient.AttachToContext(Boolean lastChance)
   at MS.Internal.Data.DataBindEngine.Task.Run(Boolean lastChance)
   at MS.Internal.Data.DataBindEngine.Run(Object arg)
   at System.Windows.ContextLayoutManager.fireLayoutUpdateEvent()
   at System.Windows.ContextLayoutManager.UpdateLayout()
   at System.Windows.Interop.HwndSource.SetLayoutSize()
   at System.Windows.Interop.HwndSource.set_RootVisualInternal(Visual value)
   at System.Windows.Window.SetRootVisual()
   at System.Windows.Window.SetRootVisualAndUpdateSTC()
   at System.Windows.Window.SetupInitialState(Double requestedTop, Double requestedLeft, Double requestedWidth, Double requestedHeight)
   at System.Windows.Window.CreateSourceWindow(Boolean duringShow)
   at System.Windows.Window.ShowHelper(Object booleanBox)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.DispatcherOperation.InvokeImpl()
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at MS.Internal.CulturePreservingExecutionContext.Run(CulturePreservingExecutionContext 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, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
   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.Application.RunDispatcher(Object ignore)
   at System.Windows.Application.RunInternal(Window window)
   at xxx.App.Main()

The Exception probably happened on Dispose, but there is a null checking.

Here are the interesting parts of code:

CommunicationViewModel.cs:

53          this.ConnectCommand = new RelayCommand(this.Connect, () => this.CanConnect);
...   
91      public bool CanConnect
92      {
93          get { return !this.Connection.IsOpen; }
94      }

this.Connection is an instance of TcpConnection

TcpConnection.cs:

63      public bool IsOpen
64      {
65          get
66          {
67              var c = this.client;
68              if (c == null)
69              {
70                  return false;
71              }
72
73              return c.Connected;
74          }
75      }

I think this is a weird behavior of data binding. Has anyone faced to similar problem? Also, it is weird that the line 93 of CommunicationViewModel.cs is not included in the stack trace. Is the WPF doing some optimization to the code?

Steven2105
  • 540
  • 5
  • 20
user3387366
  • 99
  • 1
  • 6
  • 10
    `Connection` isn't checked for `null` – Pavel Anikhouski Jul 16 '20 at 09:24
  • Welcome to StackOverflow! This is a well-written question, +1. Are you running a release build? I ask because the line number in `TcpConnection.cs` doesn't quite line up. Is it possible that you're running an older binary, which doesn't quite match the source you're looking at? – canton7 Jul 16 '20 at 09:26
  • 1
    See [this answer](https://stackoverflow.com/a/17226156/1136211) for why line 93 is not in the stack trace. – Clemens Jul 16 '20 at 09:29
  • If `Connection` was null, then I wouldn't expect to see `TcpConnection.cs:line 70` in the stack trace (unless they're running on a net5 preview, perhaps?) – canton7 Jul 16 '20 at 09:32
  • 2
    OP, although you've asked a good question, I'm afraid you need to follow it up with answers to our questions in the comments, otherwise this is likely to be closed as "Needs more details" – canton7 Jul 16 '20 at 09:52
  • The line given in errors is unreliable. Canexecute should be a method rather than a property. Personally, i prefer the style used here. See figure 5 https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/may/mvvm-commands-relaycommands-and-eventtocommand#the-relaycommand – Andy Jul 16 '20 at 09:53
  • @Andy in a Debug build I'd expect it to at least be close. The fact that it's so far off suggests that the binary might be out of sync with the source, so it's a question worth asking at least – canton7 Jul 16 '20 at 10:04
  • @canton7 It is a release build, and the program debug information is consistent with source code for sure. (It happened after fresh build and also no file related to this was changed for more than a year) I am using .NET Framework 4.5 – user3387366 Jul 16 '20 at 10:43
  • Ah right, in a release build everything goes out of the window. Is it possible that the implementation of `c.Connected` is throwing? – canton7 Jul 16 '20 at 10:43
  • @Andy the figure what you are referring to also uses a Lambda function, like my example. The only difference is, that in my case I am getting a value of Property instead of Field. Do you think this may be the key difference? – user3387366 Jul 16 '20 at 10:46
  • @canton7 maybe it is throwing, the `c.Connected` is built-in `System.Net.Sockets.TcpClient.Connected`. Maybe the problem is really under line 73, and the stack trace was confused because of missing line 93 (as @Clemens pointed out) – user3387366 Jul 16 '20 at 10:51
  • Well, line numbers moving around in a release build is normal. Clemens' point is about entire frames getting removed, with is also normal in release builds. `TcpClient.Connected` will throw if it's accessed after being disposed, see here: https://dotnetfiddle.net/2ku9Z2 (this was [fixed in .NET Core](https://source.dot.net/#System.Net.Sockets/System/Net/Sockets/TCPClient.cs,22efae515d6f014f)) . Since you mention disposal, maybe that's it? – canton7 Jul 16 '20 at 10:55
  • Is the viewmodel responsible for the lifecycle of the Connection object, or is it reused ? This could be a race condition in threads, if the Connection object is shared. – Aabid Ali Jul 17 '20 at 14:14

0 Answers0