2016-03-21 2 views
0

Nous ajoutons une deuxième thread d'interface utilisateur à notre application MVEL catel 4.4.0.InvalidOperationException lors de l'utilisation d'une commande sur un deuxième thread d'interface utilisateur

J'ai créé ma vue et mon modèle sur le second thread de l'interface utilisateur et j'utilise un DispatcherTimer pour mettre à jour le modèle de vue périodiquement. Cette partie semble fonctionner correctement. Toutefois, lorsque je crée un Catel.MVVM.Command dans le constructeur de mon modèle de vue, je rencontre des problèmes. Lorsque le CanExecute de la commande se déclenche, j'obtiens une exception System.InvalidOperationException sur mon deuxième thread d'interface utilisateur.

La commande n'a rien de spécial.

private bool ImageClickCanExecute() 
{ 
    return true; 
} 

public void ImageClickAction() 
{ 
    if(ImageClickTarget != null) 
     Process.Start(ImageClickTarget.ToString()); 
} 

La vue n'est pas non plus.

<Grid> 
    <Button Command="{Binding ImageClickCommand}"> 
     <Image Name="ImageSource" Source="{Binding ImageSource, FallbackValue={x:Null}}"/> 
    </Button> 
</Grid> 

La trace de la pile est ci-dessous.

0:010> !PrintException /d 00000282cb8effd0 
Exception object: 00000282cb8effd0 
Exception type: System.Reflection.TargetInvocationException 
Message:   Exception has been thrown by the target of an invocation. 
InnerException: System.InvalidOperationException, Use !PrintException 00000282cb8edee8 to see more. 
StackTrace (generated): 
    SP    IP    Function 
    000000B0459FD510 0000000000000000 mscorlib_ni!System.RuntimeMethodHandle.InvokeMethod(System.Object, System.Object[], System.Signature, Boolean)+0x1 
    000000B0459FD510 00007FFFCC5E1C20 mscorlib_ni!System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(System.Object, System.Object[], System.Object[])+0x80 
    000000B0459FD580 00007FFFCC5BE789 mscorlib_ni!System.Delegate.DynamicInvokeImpl(System.Object[])+0x99 
    000000B0459FD5D0 00007FFF70FC83AE UNKNOWN!Catel.EventHandlerExtensions.SplitInvoke(System.Delegate, System.Object[])+0xfe 
    000000B0459FD630 00007FFF7164E085 UNKNOWN!Catel.EventHandlerExtensions.SafeInvoke(System.EventHandler, System.Object, System.EventArgs)+0x55 
    000000B0459FD680 00007FFF71674998 UNKNOWN!Catel.MVVM.Command`2+<<RaiseCanExecuteChanged>b__32_0>d[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].MoveNext()+0x38 
    000000B0459FD7B0 00007FFFCD2E1224 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0xd3f9c4 
    000000B0459FD7F0 00007FFFCC5A17AD mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x3d 
    000000B0459FD820 00007FFF71674515 UNKNOWN!Catel.MVVM.Command`2+<>c__DisplayClass35_0+<<AutoDispatchIfRequiredAsync>b__0>d[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].MoveNext()+0xf5 
    000000B0459FD9B0 00007FFFCCFCDA88 mscorlib_ni!System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b__6_0(System.Object)+0x38 
    000000B0459FD9E0 00007FFFA8119C0E WindowsBase_ni!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate, System.Object, Int32)+0xae 
    000000B0459FDA50 00007FFFA8119AC6 WindowsBase_ni!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(System.Object, System.Delegate, System.Object, Int32, System.Delegate)+0x36 
    000000B0459FDAA0 00007FFFA811CA2B WindowsBase_ni!System.Windows.Threading.DispatcherOperation.InvokeImpl()+0x10b 
    000000B0459FDB20 00007FFFCC5CA79E mscorlib_ni!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)+0x15e 
    000000B0459FDBF0 00007FFFCC5CA637 mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)+0x17 
    000000B0459FDC20 00007FFFCC5CA5F2 mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)+0x52 
    000000B0459FDC70 00007FFFA8333810 WindowsBase_ni!MS.Internal.CulturePreservingExecutionContext.Run(MS.Internal.CulturePreservingExecutionContext, System.Threading.ContextCallback, System.Object)+0x80 
    000000B0459FDCD0 00007FFFA811C784 WindowsBase_ni!System.Windows.Threading.DispatcherOperation.Invoke()+0x64 
    000000B0459FDD30 00007FFFA8117C24 WindowsBase_ni!System.Windows.Threading.Dispatcher.ProcessQueue()+0x1a4 
    000000B0459FDDB0 00007FFFA8118061 WindowsBase_ni!System.Windows.Threading.Dispatcher.WndProcHook(IntPtr, Int32, IntPtr, IntPtr, Boolean ByRef)+0x71 
    000000B0459FDE30 00007FFFA8119E53 WindowsBase_ni!MS.Win32.HwndWrapper.WndProc(IntPtr, Int32, IntPtr, IntPtr, Boolean ByRef)+0xc3 
    000000B0459FDEC0 00007FFFA8119D82 WindowsBase_ni!MS.Win32.HwndSubclass.DispatcherCallbackOperation(System.Object)+0x82 
    000000B0459FDF10 00007FFFA8119BC9 WindowsBase_ni!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate, System.Object, Int32)+0x69 
    000000B0459FDF80 00007FFFA8119AC6 WindowsBase_ni!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(System.Object, System.Delegate, System.Object, Int32, System.Delegate)+0x36 
    000000B0459FDFD0 00007FFFA8117583 WindowsBase_ni!System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority, System.TimeSpan, System.Delegate, System.Object, Int32)+0x173 
    000000B0459FE070 00007FFFA81194FF WindowsBase_ni!MS.Win32.HwndSubclass.SubclassWndProc(IntPtr, Int32, IntPtr, IntPtr)+0x11f 
    000000B0459FE390 0000000000000000 WindowsBase_ni!MS.Win32.UnsafeNativeMethods.DispatchMessage(System.Windows.Interop.MSG ByRef)+0x1 
    000000B0459FE450 00007FFFA812D8FC WindowsBase_ni!System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame)+0xec 
    000000B0459FE4E0 00007FFFA26A98B3 PresentationFramework_ni!System.Windows.Application.RunDispatcher(System.Object)+0x73 
    000000B0459FE520 00007FFFA26A969D PresentationFramework_ni!System.Windows.Application.RunInternal(System.Windows.Window)+0x8d 
    000000B0459FE580 00007FFF70FD70F7 UNKNOWN!xxx.Wpf.App.Main()+0x67 
    000000B0459FF0C0 0000000000000000 mscorlib_ni!System.AppDomain._nExecuteAssembly(System.Reflection.RuntimeAssembly, System.String[])+0x1 
    000000B0459FF0C0 00007FFFCCD57EBF mscorlib_ni!System.AppDomain.ExecuteAssembly(System.String, System.Security.Policy.Evidence, System.String[])+0x7f 
    000000B0459FF110 00007FFF7053434E UNKNOWN!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()+0x3e 
    000000B0459FF150 00007FFFCC5CA79E mscorlib_ni!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)+0x15e 
    000000B0459FF220 00007FFFCC5CA637 mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)+0x17 
    000000B0459FF250 00007FFFCC5CA5F2 mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)+0x52 
    000000B0459FF2A0 00007FFFCC51BEF2 mscorlib_ni!System.Threading.ThreadHelper.ThreadStart()+0x52 

StackTraceString: <none> 
HResult: 80131604 
0:010> !PrintException /d 00000282cb8edee8 
Exception object: 00000282cb8edee8 
Exception type: System.InvalidOperationException 
Message:   The calling thread cannot access this object because a different thread owns it. 
InnerException: <none> 
StackTrace (generated): 
    SP    IP    Function 
    000000B0459FCD70 00007FFFA8446977 WindowsBase_ni!System.Windows.Threading.Dispatcher.VerifyAccess()+0x32faf7 
    000000B0459FCDA0 00007FFFA8112806 WindowsBase_ni!System.Windows.DependencyObject.GetValue(System.Windows.DependencyProperty)+0x26 
    000000B0459FCE00 00007FFFA27EBB5B PresentationFramework_ni!System.Windows.Controls.Primitives.ButtonBase.get_Command()+0x2b 
    000000B0459FCE30 00007FFFA27EBB00 PresentationFramework_ni!System.Windows.Controls.Primitives.ButtonBase.UpdateCanExecute()+0x10 

StackTraceString: <none> 
HResult: 80131509 

Répondre

0

En effet, par défaut, les commandes transmet automatiquement les notifications de modification à l'aide du DispatcherService. Puisque vous utilisez un scénario de bordure (2 threads), je vous recommande de désactiver le dispatching automatique et de prendre soin de vous-même. Comme il s'agit d'un membre protégé statique, vous devrez dériver votre propre classe de commande de CommandBase et définir AutomaticallyDispatchEvents à false.

ps. Je recommande d'utiliser le IProcessService au lieu d'utiliser directement Process.Start, il vous permet de le simuler ou de le remplacer si nécessaire.

+1

Actuellement, AutomaticallyDispatchEvents est disponible dans catel 4.4.0. Je l'ai mis à faux et cela a résolu mon problème. – JonDrnek