KirillOsenkov / MSBuildStructuredLog

A logger for MSBuild that records a structured representation of executed targets, tasks, property and item values.
MIT License
1.41k stars 188 forks source link

`TreeViewExtensions.OnRequestBringIntoView` NRE #758

Closed Youssef1313 closed 4 months ago

Youssef1313 commented 4 months ago

image

Unfortunately, I have no repro steps. Looks like it was a one-off for me, but thought it might be still helpful to report.

Youssef1313 commented 4 months ago

Nope, it doesn't seem a one-off. Not sure why it's happening this way :'(

---------------------------

---------------------------
Unexpected exception. Sorry about that.

Please Ctrl+C to copy this text and file an issue at https://github.com/KirillOsenkov/MSBuildStructuredLog/issues/new

System.NullReferenceException: Object reference not set to an instance of an object.

   at StructuredLogViewer.Controls.TreeViewExtensions.OnRequestBringIntoView(Object sender, RequestBringIntoViewEventArgs e) in C:\MSBuildStructuredLog\src\StructuredLogViewer\Controls\TreeViewExtensions.cs:line 97

   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.Controls.TreeViewItem.HandleBringIntoView(RequestBringIntoViewEventArgs e)

   at System.Windows.Controls.TreeViewItem.OnRequestBringIntoView(Object sender, RequestBringIntoViewEventArgs e)

   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.Controls.VirtualizingStackPanel.BringContainerIntoView(ItemsControl itemsControl, Int32 itemIndex)

   at StructuredLogViewer.Controls.TreeViewExtensions.SelectContainerFromItem[T](ItemsControl container, SelectInfo`1 selectInfo, TreeView treeView) in C:\MSBuildStructuredLog\src\StructuredLogViewer\Controls\TreeViewExtensions.cs:line 406

   at StructuredLogViewer.Controls.TreeViewExtensions.SelectContainerFromItem[T](ItemsControl container, SelectInfo`1 selectInfo, TreeView treeView) in C:\MSBuildStructuredLog\src\StructuredLogViewer\Controls\TreeViewExtensions.cs:line 451

   at StructuredLogViewer.Controls.BuildControl.ResultsList_SelectionChanged(Object sender, RoutedPropertyChangedEventArgs`1 e) in C:\MSBuildStructuredLog\src\StructuredLogViewer\Controls\BuildControl.xaml.cs:line 1318

   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.Controls.TreeView.ChangeSelection(Object data, TreeViewItem container, Boolean selected)

   at System.Windows.Controls.TreeViewItem.Select(Boolean selected)

   at System.Windows.Controls.TreeViewItem.OnGotFocus(RoutedEventArgs e)

   at System.Windows.UIElement.IsFocused_Changed(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.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType, Boolean isInternal)

   at System.Windows.DependencyObject.SetValue(DependencyPropertyKey key, Object value)

   at System.Windows.Input.FocusManager.OnFocusedElementChanged(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.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType, Boolean isInternal)

   at System.Windows.Input.FocusManager.SetFocusedElement(DependencyObject element, IInputElement value)

   at System.Windows.Input.KeyboardNavigation.UpdateFocusedElement(DependencyObject focusTarget)

   at System.Windows.FrameworkElement.OnGotKeyboardFocus(Object sender, KeyboardFocusChangedEventArgs e)

   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.Input.InputManager.ProcessStagingArea()

   at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)

   at System.Windows.Input.KeyboardDevice.ChangeFocus(DependencyObject focus, Int32 timestamp)

   at System.Windows.Input.KeyboardDevice.TryChangeFocus(DependencyObject newFocus, IKeyboardInputProvider keyboardInputProvider, Boolean askOld, Boolean askNew, Boolean forceToNullIfFailed)

   at System.Windows.Input.KeyboardDevice.Focus(DependencyObject focus, Boolean askOld, Boolean askNew, Boolean forceToNullIfFailed)

   at System.Windows.Input.KeyboardDevice.Focus(IInputElement element)

   at System.Windows.UIElement.Focus()

   at System.Windows.Controls.TreeViewItem.OnMouseLeftButtonDown(MouseButtonEventArgs e)

   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.ReRaiseEventAs(DependencyObject sender, RoutedEventArgs args, RoutedEvent newEvent)

   at System.Windows.UIElement.OnMouseDownThunk(Object sender, MouseButtonEventArgs e)

   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.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 System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
---------------------------
OK   
---------------------------
Youssef1313 commented 4 months ago

@KirillOsenkov I tried to debug this, looks like trying to get _tv_scrollviewer_ is returning null.

I looked into template child names, and interestingly the scroll viewer is named 1_T:

image

So, changing _tv_scrollviewer_ to 1_T fixes it, but that doesn't make sense to me.

The other thing is this:

https://github.com/KirillOsenkov/MSBuildStructuredLog/blob/39f61e3ae023e25e716eed7e7841f1e73cde9205/src/StructuredLogViewer/Controls/TreeViewExtensions.cs#L90-L93

Why this is looking at ancestors? Changing this to FindVisualChild works for me.

KirillOsenkov commented 4 months ago

I think this regressed in https://github.com/KirillOsenkov/MSBuildStructuredLog/commit/9a131c0e4584e720c636dd24dda9a56d4296703b

RequestBringIntoView had the code to just return if scrollViewer is null

Youssef1313 commented 4 months ago

@KirillOsenkov My thought is that it shouldn't be null in the first place. I opened #759 to look into children instead of ancestors. But what I don't understand is why WPF is returning null when trying to find _tv_scrollviewer_ and what this 1_T come from. The TreeView template from WPF repo has _tv_scrollviewer_: https://github.com/dotnet/wpf/blob/3f3c5c3af19ca8f6fcd64b87905358a5e704136c/src/Microsoft.DotNet.Wpf/src/Themes/XAML/TreeView.xaml#L44

KirillOsenkov commented 4 months ago

Very interesting, thanks for investigating! Are you running this on net472? or .NET? I have no idea where 1_T would be coming from.

It was looking for FindAncestor for an unrelated scenario that doesn't apply to this repo. I had this code in another place where it was possible that a re-templated treeview didn't have a scroll viewer, because it was itself inside another scroll viewer. That way FindAncestor worked. But this was only a fallback path. Our tree always contains a scroll viewer.

Weird.

KirillOsenkov commented 4 months ago

oh, are you using the dark theme? I think it retemplates the TreeView.

Youssef1313 commented 4 months ago

Yes, I'm using dark theme!

KirillOsenkov commented 4 months ago

I see, thanks! I decided to be a bit more defensive in https://github.com/KirillOsenkov/MSBuildStructuredLog/commit/670ced2367fbdd3865442357e079e3ac2fc27412

KirillOsenkov commented 4 months ago

Could you please check if this works fine for you? I searched https://github.com/benruehl/adonis-ui/tree/1.16 for 1_T but I still can't find it there.

Youssef1313 commented 4 months ago

@KirillOsenkov Yes, it does work.

image

KirillOsenkov commented 4 months ago

OK great, I'm publishing an update then.

KirillOsenkov commented 4 months ago

I'm guessing if this ScrollViewer has no name, 1_T is assigned automatically?

https://github.com/benruehl/adonis-ui/blob/535a89c666c99e679738d1e38ed09a1b7a9caa16/src/AdonisUI.ClassicTheme/DefaultStyles/TreeView.xaml#L254

Youssef1313 commented 4 months ago

That could be it. Because accessing .Name returns empty string. And getting the style setters, they appear to be the same that you linked

KirillOsenkov commented 4 months ago

Published 2.2.207, thanks!