2012-08-24 37 views
0

我一直在嘗試將現有的C#WPF API與Jav​​a應用程序進行接口。在Java應用程序中使用WPF庫時的線程問題?

到目前爲止,我已經成功使用jni4net來生成Java和.NET代碼之間接口的代理。

這種整合生產STA線程問題與正在顯示的WPF UI的:

System.InvalidOperationException: The calling thread must be STA, because many UI components require this. 
    at System.Windows.Input.InputManager..ctor() 
    at System.Windows.Input.InputManager.GetCurrentInputManagerImpl() 
    at System.Windows.Input.KeyboardNavigation..ctor() 
    at System.Windows.FrameworkElement.FrameworkServices..ctor() 
    at System.Windows.FrameworkElement.EnsureFrameworkServices() 
    at System.Windows.FrameworkElement..ctor() 
    at System.Windows.Controls.Control..ctor() 
    at System.Windows.Window..ctor() 

這是通過使用以下模式加載的WPF UI的使用ShowDialog的克服:但是現在

Thread thread = new Thread(new ParameterizedThreadStart(ParameterizedMethodName)); 
thread.SetApartmentState(ApartmentState.STA); 
thread.Start(parameter); 
thread.Join(); 

,在使用WPF UI時,我遇到類似於以下的異常,鼠標單擊或按鍵可觸發以下內容(此示例來自於鼠標單擊):

System.InvalidOperationException: The calling thread cannot access this object because a different thread owns it. 
    at System.Windows.Threading.Dispatcher.VerifyAccess() 
    at System.Windows.DependencyObject.GetValue(DependencyProperty dp) 
    at System.Windows.Input.InputBinding.get_Command() 
    at System.Windows.Input.InputBindingCollection.FindMatch(Object targetElement, InputEventArgs inputEventArgs) 
    at System.Windows.Input.CommandManager.TranslateInput(IInputElement targetElement, InputEventArgs inputEventArgs) 
    at System.Windows.UIElement.OnMouseDownThunk(Object sender, MouseButtonEventArgs e) 
    at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget) 
    at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target) 
    at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs) 
    at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised) 
    at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args) 
    at System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs args) 
    at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted) 
    at System.Windows.Input.InputManager.ProcessStagingArea() 
    at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input) 
    at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport) 
    at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel) 
    at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam, Boolean& handled) 
    at System.Windows.Interop.HwndSource.InputFilterMessage(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 MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler) 
    at System.Windows.Threading.Dispatcher.InvokeImpl(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.Threading.Dispatcher.PushFrame(DispatcherFrame frame) 
    at System.Windows.Window.ShowHelper(Object booleanBox) 
    at System.Windows.Window.Show() 
    at System.Windows.Window.ShowDialog() 

我目前不確定如何解決此問題並從堆棧跟蹤中確定問題的原因。

任何幫助/意見是非常感謝。

回答

0

對於解決方案,我無法提供多少建議,但我可以告訴你這個問題。你所有的WPF代碼必須運行在同一個線程(大概是你正在創建的)。你得到的錯誤是因爲有人試圖從不同的線程訪問WPF控件。

因此,假設您有一個顯示對話框的API調用,並且您的java代碼調用MyApi.ShowDialog。您的API ShowDialog方法不能簡單地調用MyDialog.ShowDialog(),因爲對UI組件的調用將來自java線程。相反,您的API需要足夠聰明以將這些調用編組到相應的WPF(UI)線程。

所以應該這樣做:

if(!CheckAccess()) 
    MyDialog.Dispatcher.BeginInvoke(DeleageToShowDialog); 

不幸的是,這可能意味着你將不得不做了很多工作,對您的API,因爲它可能不會考慮這樣的線程問題。

+0

謝謝。我已經意識到使用CheckAccess()並且已經爲此寫了一個擴展方法。唯一的問題是我不知道從哪裏開始測試!來自異常的堆棧跟蹤並不指向我的問題的方向,因爲它是一個.NET堆棧跟蹤... – Paul

+0

我不認爲它真的很重要,找到WPF API調用ShowDialog()的任何地方, '並確保它是線程安全的。你需要這樣做,否則你最終會修復這個特定的錯誤,然後運行到另一個,另一個,另一個。 – CodingGorilla

+0

即使使用CheckAccess()和BeginInvoke()包裝了ShowDialog(),我仍然在主WPF UI上遇到同樣的異常。 – Paul