2016-07-12 12 views
5

A volte, facendo clic con il tasto destro del mouse su treeviewitem, i risultati non vengono gestiti InvalidOperationException. Nel codice sottostante seleziono la riga su cui è stato fatto clic:Perché l'albero di clic genera "System.Windows.Documents.Run" non è un InvalidOperationException di Visual o Visual3D?

static TreeViewItem VisualUpwardSearch(DependencyObject source) 
    { 
     while (source != null && !(source is TreeViewItem)) 
      source = VisualTreeHelper.GetParent(source); 

     return source as TreeViewItem; 
    } 

    private void OnPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e) 
    { 
      TreeViewItem treeViewItem = VisualUpwardSearch(e.OriginalSource as DependencyObject); 

      if (treeViewItem != null) 
      { 
       treeViewItem.Focus(); 
       e.Handled = true; 
      } 
    } 

Secondo stacktrace sopra è la fonte del problema.

XAML:

<UserControl.Resources> 
    <HierarchicalDataTemplate ItemsSource="{Binding ClassesItemsSource}" DataType="{x:Type pnls:FavoriteObjectTableViewModel}"> 
     <StackPanel Orientation="Horizontal"> 
      <Image Source="{Binding Converter={StaticResource nameToBitmapSource}}" DataContext="{Binding Bitmap}" /> 
      <Label Content="{Binding TableName}"/> 
     </StackPanel> 
    </HierarchicalDataTemplate> 
    <DataTemplate DataType="{x:Type pnls:FavoriteObjectClassViewModel}"> 
     <StackPanel Orientation="Horizontal"> 
      <Image Source="{Binding Bitmap, Converter={StaticResource UriToCachedImageConverter}}"/> 
      <Label Content="{Binding ClassName}"/> 
     </StackPanel> 
    </DataTemplate> 
</UserControl.Resources> 

<TreeView Name="Insert_ObjectTreeIE" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" ItemsSource="{Binding TablesItemsSource}"> 
     <TreeView.ItemContainerStyle> 
      <Style TargetType="TreeViewItem"> 
       <Setter Property="IsSelected" Value="{Binding IsSelected}" /> 
       <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" /> 
       <EventSetter Event="PreviewMouseRightButtonDown" Handler="OnPreviewMouseRightButtonDown"></EventSetter> 
       <EventSetter Event="MouseDoubleClick" Handler="OnMouseDoubleClick" /> 
      </Style> 
     </TreeView.ItemContainerStyle> 
</TreeView> 

Stacktrace:

e.StackTrace " at MS.Internal.Media.VisualTreeUtils.AsVisual(DependencyObject element, Visual& visual, Visual3D& visual3D)\r\n 
at MS.Internal.Media.VisualTreeUtils.AsNonNullVisual(DependencyObject element, Visual& visual, Visual3D& visual3D)\r\n 
at System.Windows.Media.VisualTreeHelper.GetParent(DependencyObject reference)\r\n 
at Tekla.Nis.Application.Shared.UI.Panels.FavoriteObjectsView.VisualUpwardSearch(DependencyObject source) in c:\\XXX\\161wpf\\src\\SharedAppFeature\\Panels\\FavoriteObjectsView.xaml.cs:line 45\r\n 
at Application.Shared.UI.Panels.FavoriteObjectsView.OnPreviewMouseRightButtonDown(Object sender, MouseButtonEventArgs e) in c:\\XXX\\161wpf\\src\\NisSharedAppFeature\\Panels\\FavoriteObjectsView.xaml.cs:line 52\r\n 
at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)\r\n 
at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)\r\n 
at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)\r\n 
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)\r\n 
at System.Windows.UIElement.ReRaiseEventAs(DependencyObject sender, RoutedEventArgs args, RoutedEvent newEvent)\r\n 
at System.Windows.UIElement.OnPreviewMouseDownThunk(Object sender, MouseButtonEventArgs e)\r\n 
at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)\r\n 
at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)\r\n at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)\r\n 
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)\r\n 
at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)\r\n at System.Windows.ContentElement.RaiseTrustedEvent(RoutedEventArgs args)\r\n 
at System.Windows.Input.InputManager.ProcessStagingArea()\r\n 
at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)\r\n 
at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)\r\n 
at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)\r\n 
at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam, Boolean& handled)\r\n 
at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)\r\n 
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)\r\n at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)\r\n 
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)\r\n 
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)\r\n 
at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)\r\n 
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)\r\n 
at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)\r\n 
at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)\r\n 
at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)\r\n 
at System.Windows.Application.RunDispatcher(Object ignore)\r\n 
at System.Windows.Application.RunInternal(Window window)\r\n 
at System.Windows.Application.Run(Window window)\r\n 
at System.Windows.Application.Run()\r\n at "my application start location" 

posso riprodurre questo solo a volte. Il mio collega ha detto che l'elemento clic sinistro 1 e il clic destro 2 lo produce ogni volta in un determinato albero.

+0

Un 'Run' non è Visual e richiede una gestione separata. fa 'VisualUpwardSearch (e.Source come DependencyObject);' già lo aggiusta per te? Inoltre: per riprodurre il clic deve avvenire sull'etichetta non sull'immagine! –

+0

clicco su un blocco di testo, non sull'immagine ma ora clicco per minuti e non riesco a riprodurlo. quindi non so se questo cambiamento fa la differenza. –

+0

oltre a cambiarlo in e.Source risulta che l'elemento principale è stato selezionato –

risposta

6

I problemi si verificano quando si fa clic in qualche punto nel testo dell'etichetta. In questo caso, lo e.OriginalSource sarà un oggetto Run che fa parte della composizione interna di Label o TextBox. L'elemento Run non eredita da una classe Visual, quindi non può essere una parte dell'albero visivo, in questo caso lo VisualTreeHelper.GetParent(source); genererà InvalidOperationException.

La soluzione più semplice è quello di rendere ogni controllo di testo (Label nel tuo caso) IsHitTestVisible="False", questo escludere questi controlli dalla logica di rilevamento del contatto, il che significa che non sarà mai la e.OriginalSource di un evento, invece è genitore sarà raccolto e molto probabilmente il genitore sarà un elemento Visual.

+0

grazie! test approfonditi diranno se questo lo risolve. per me era quasi impossibile da riprodurre. in 1h di clic sono riuscito a ottenere l'eccezione 2 volte. +1 per spiegazione. puoi parlarmi di "parte più probabile"? quindi questo può accadere anche se imposto IsHitTestVisible = "False"? –

+0

quindi è possibile aggiungere "if (source is Visual)" solo per essere sicuri? –

+0

No, non preoccuparti del controllo, potrebbe mascherare problemi futuri, ho detto che sarà "molto probabilmente un Visual" perché ci possono essere casi se aggiungi altri elementi di testo ai tuoi modelli senza impostare IsHitTestVisible su false. Nel tuo caso è sicuro al 100%, potresti voler mettere IsHitTestVisible solo sullo StackPanel radice dei tuoi modelli per evitare il problema con altri elementi di testo nel modello. –

Problemi correlati