Open michelle-barnett-89 opened 5 years ago
Hi, I've looked into this and can confirm the problem - also found that it occurs with my stabilized version of AvalonDock
I'll be trying to debug and hope to find a fix when my time permits but can't really promise anything without knowing more details ...
Here is the stacktrace I got:
System.NullReferenceException
HResult=0x80004003
Message=Object reference not set to an instance of an object.
Source=Xceed.Wpf.AvalonDock
StackTrace:
at Xceed.Wpf.AvalonDock.Controls.DocumentPaneTabPanel.ArrangeOverride(Size finalSize)
at System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)
at System.Windows.UIElement.Arrange(Rect finalRect)
at System.Windows.Controls.Grid.ArrangeOverride(Size arrangeSize)
at System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)
at System.Windows.UIElement.Arrange(Rect finalRect)
at System.Windows.Controls.Grid.ArrangeOverride(Size arrangeSize)
at System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)
at System.Windows.UIElement.Arrange(Rect finalRect)
at System.Windows.Controls.Control.ArrangeOverride(Size arrangeBounds)
at System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)
at System.Windows.UIElement.Arrange(Rect finalRect)
at System.Windows.Controls.Grid.ArrangeOverride(Size arrangeSize)
at System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)
at System.Windows.UIElement.Arrange(Rect finalRect)
at MS.Internal.Helper.ArrangeElementWithSingleChild(UIElement element, Size arrangeSize)
at System.Windows.Controls.ContentPresenter.ArrangeOverride(Size arrangeSize)
at System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)
at System.Windows.UIElement.Arrange(Rect finalRect)
at System.Windows.Controls.Grid.ArrangeOverride(Size arrangeSize)
at System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)
at System.Windows.UIElement.Arrange(Rect finalRect)
at System.Windows.Controls.Border.ArrangeOverride(Size finalSize)
at System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)
at System.Windows.UIElement.Arrange(Rect finalRect)
at System.Windows.Controls.Control.ArrangeOverride(Size arrangeBounds)
at Xceed.Wpf.AvalonDock.DockingManager.ArrangeOverride(Size arrangeBounds)
at System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)
at System.Windows.UIElement.Arrange(Rect finalRect)
at System.Windows.Controls.Grid.ArrangeOverride(Size arrangeSize)
at System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)
at System.Windows.UIElement.Arrange(Rect finalRect)
at MS.Internal.Helper.ArrangeElementWithSingleChild(UIElement element, Size arrangeSize)
at System.Windows.Controls.ContentPresenter.ArrangeOverride(Size arrangeSize)
at System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)
at System.Windows.UIElement.Arrange(Rect finalRect)
at System.Windows.Documents.AdornerDecorator.ArrangeOverride(Size finalSize)
at System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)
at System.Windows.UIElement.Arrange(Rect finalRect)
at System.Windows.Controls.Border.ArrangeOverride(Size finalSize)
at System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)
at System.Windows.UIElement.Arrange(Rect finalRect)
at System.Windows.Window.ArrangeOverride(Size arrangeBounds)
at System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)
at System.Windows.UIElement.Arrange(Rect finalRect)
at System.Windows.ContextLayoutManager.UpdateLayout()
at System.Windows.UIElement.UpdateLayout()
at System.Windows.Controls.TabItem.OnPreviewGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
at System.Windows.UIElement.OnPreviewGotKeyboardFocusThunk(Object sender, KeyboardFocusChangedEventArgs e)
at System.Windows.Input.KeyboardFocusChangedEventArgs.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.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.TabItem.SetFocus()
at System.Windows.Controls.TabControl.OnSelectionChanged(SelectionChangedEventArgs e)
at Xceed.Wpf.AvalonDock.Controls.LayoutDocumentPaneControl.OnSelectionChanged(SelectionChangedEventArgs e)
at System.Windows.Controls.Primitives.Selector.InvokeSelectionChanged(List1 unselectedInfos, List
1 selectedInfos)
at System.Windows.Controls.Primitives.Selector.SelectionChanger.End()
at System.Windows.Controls.Primitives.Selector.SetSelectedHelper(Object item, FrameworkElement UI, Boolean selected)
at System.Windows.Controls.Primitives.Selector.NotifyIsSelectedChanged(FrameworkElement container, Boolean selected, RoutedEventArgs e)
at System.Windows.Controls.Primitives.Selector.OnSelected(Object sender, RoutedEventArgs e)
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.RaiseEvent(RoutedEventArgs e)
at System.Windows.Controls.TabItem.OnSelected(RoutedEventArgs e)
at System.Windows.Controls.TabItem.OnIsSelectedChanged(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.StyleHelper.ApplyStyleOrTemplateValue(FrameworkObject fo, DependencyProperty dp)
at System.Windows.StyleHelper.InvalidateContainerDependents(DependencyObject container, FrugalStructList1& exclusionContainerDependents, FrugalStructList
1& oldContainerDependents, FrugalStructList1& newContainerDependents) at System.Windows.StyleHelper.DoStyleInvalidations(FrameworkElement fe, FrameworkContentElement fce, Style oldStyle, Style newStyle) at System.Windows.StyleHelper.UpdateStyleCache(FrameworkElement fe, FrameworkContentElement fce, Style oldStyle, Style newStyle, Style& styleCache) at System.Windows.FrameworkElement.OnStyleChanged(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.Controls.ItemsControl.ApplyItemContainerStyle(DependencyObject container, Object item) at System.Windows.Controls.ItemsControl.MS.Internal.Controls.IGeneratorHost.PrepareItemContainer(DependencyObject container, Object item) at System.Windows.Controls.ItemContainerGenerator.System.Windows.Controls.Primitives.IItemContainerGenerator.PrepareItemContainer(DependencyObject container) at System.Windows.Controls.Panel.AddChildren(GeneratorPosition pos, Int32 itemCount) at System.Windows.Controls.Panel.OnItemsChangedInternal(Object sender, ItemsChangedEventArgs args) at System.Windows.Controls.Panel.OnItemsChanged(Object sender, ItemsChangedEventArgs args) at System.Windows.Controls.ItemContainerGenerator.OnItemAdded(Object item, Int32 index) at System.Windows.Controls.ItemContainerGenerator.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args) at System.Windows.WeakEventManager.ListenerList
1.DeliverEvent(Object sender, EventArgs e, Type managerType)
at System.Windows.WeakEventManager.DeliverEvent(Object sender, EventArgs args)
at System.Collections.Specialized.CollectionChangedEventManager.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args)
at System.Collections.Specialized.NotifyCollectionChangedEventHandler.Invoke(Object sender, NotifyCollectionChangedEventArgs e)
at System.Windows.Data.CollectionView.OnCollectionChanged(NotifyCollectionChangedEventArgs args)
at System.Windows.Controls.ItemCollection.OnViewCollectionChanged(Object sender, NotifyCollectionChangedEventArgs e)
at System.Windows.WeakEventManager.ListenerList1.DeliverEvent(Object sender, EventArgs e, Type managerType) at System.Windows.WeakEventManager.DeliverEvent(Object sender, EventArgs args) at System.Collections.Specialized.CollectionChangedEventManager.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args) at System.Windows.Data.CollectionView.OnCollectionChanged(NotifyCollectionChangedEventArgs args) at System.Windows.Data.ListCollectionView.ProcessCollectionChangedWithAdjustedIndex(NotifyCollectionChangedEventArgs args, Int32 adjustedOldIndex, Int32 adjustedNewIndex) at System.Windows.Data.ListCollectionView.ProcessCollectionChanged(NotifyCollectionChangedEventArgs args) at System.Windows.Data.CollectionView.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args) at System.Collections.Specialized.NotifyCollectionChangedEventHandler.Invoke(Object sender, NotifyCollectionChangedEventArgs e) at System.Collections.ObjectModel.ObservableCollection
1.OnCollectionChanged(NotifyCollectionChangedEventArgs e)
at System.Collections.ObjectModel.ObservableCollection1.InsertItem(Int32 index, T item) at System.Collections.ObjectModel.Collection
1.Add(T item)
at Xceed.Wpf.AvalonDock.DockingManager.documentsSourceElementsChanged(Object sender, NotifyCollectionChangedEventArgs e)
at System.Collections.ObjectModel.ReadOnlyObservableCollection1.OnCollectionChanged(NotifyCollectionChangedEventArgs args) at System.Collections.ObjectModel.ReadOnlyObservableCollection
1.HandleCollectionChanged(Object sender, NotifyCollectionChangedEventArgs e)
at System.Collections.ObjectModel.ObservableCollection1.OnCollectionChanged(NotifyCollectionChangedEventArgs e) at System.Collections.ObjectModel.ObservableCollection
1.InsertItem(Int32 index, T item)
at System.Collections.ObjectModel.Collection`1.Add(T item)
at DocumentOpenSample.WorkSpace.OnNew(Object parameter) in
I found the source of the problem and the fix does not appear to be difficult either :-) I located the problem in Xceed.Wpf.AvalonDock.Controls.DocumentPaneTabPanel class at line 54 where the following code crashes at the line where the if statement checks
layoutContent
withif( layoutContent.IsSelected && !doc.IsVisible )
Here is the listing of the offending code and a fix is shown below:
protected override Size ArrangeOverride( Size finalSize )
{
var visibleChildren = Children.Cast<UIElement>().Where( ch => ch.Visibility != System.Windows.Visibility.Collapsed );
var offset = 0.0;
var skipAllOthers = false;
foreach( TabItem doc in visibleChildren )
{
var layoutContent = doc.Content as LayoutContent;
if( skipAllOthers || offset + doc.DesiredSize.Width > finalSize.Width )
{
if( layoutContent.IsSelected && !doc.IsVisible )
{
var parentContainer = layoutContent.Parent as ILayoutContainer;
var parentSelector = layoutContent.Parent as ILayoutContentSelector;
var parentPane = layoutContent.Parent as ILayoutPane;
int contentIndex = parentSelector.IndexOf( layoutContent );
if( contentIndex > 0 &&
parentContainer.ChildrenCount > 1 )
{
parentPane.MoveChild( contentIndex, 0 );
parentSelector.SelectedContentIndex = 0;
return ArrangeOverride( finalSize );
}
}
doc.Visibility = System.Windows.Visibility.Hidden;
skipAllOthers = true;
}
else
{
doc.Visibility = System.Windows.Visibility.Visible;
doc.Arrange( new Rect( offset, 0.0, doc.DesiredSize.Width, finalSize.Height ) );
offset += doc.ActualWidth + doc.Margin.Left + doc.Margin.Right;
}
}
return finalSize;
}
A fix is to insert these two lines in the foreach
loop to continue looping if the layoutContent
appears to be null (see below). I attach a source version with the fix and wanted to ask if you could test and verify that it really fixes your problem without introducing new issues - I'll be testing as well and if thats going good we'll have another fix to be applied here ;-)
if (layoutContent == null)
continue;
protected override Size ArrangeOverride( Size finalSize )
{
var visibleChildren = Children.Cast<UIElement>().Where( ch => ch.Visibility != System.Windows.Visibility.Collapsed );
var offset = 0.0;
var skipAllOthers = false;
foreach( TabItem doc in visibleChildren )
{
var layoutContent = doc.Content as LayoutContent;
if (layoutContent == null)
continue;
if( skipAllOthers || offset + doc.DesiredSize.Width > finalSize.Width )
{
if( layoutContent.IsSelected && !doc.IsVisible )
{
var parentContainer = layoutContent.Parent as ILayoutContainer;
var parentSelector = layoutContent.Parent as ILayoutContentSelector;
var parentPane = layoutContent.Parent as ILayoutPane;
int contentIndex = parentSelector.IndexOf( layoutContent );
if( contentIndex > 0 &&
parentContainer.ChildrenCount > 1 )
{
parentPane.MoveChild( contentIndex, 0 );
parentSelector.SelectedContentIndex = 0;
return ArrangeOverride( finalSize );
}
}
doc.Visibility = System.Windows.Visibility.Hidden;
skipAllOthers = true;
}
else
{
doc.Visibility = System.Windows.Visibility.Visible;
doc.Arrange( new Rect( offset, 0.0, doc.DesiredSize.Width, finalSize.Height ) );
offset += doc.ActualWidth + doc.Margin.Left + doc.Margin.Right;
}
}
return finalSize;
}
On a second thought about this - there is a much better fix that lets the rest of the code work as before but won't crash on your test case :-) So, the better solution is to move the layoutContent
variable inside the if
statement (because its only used there) and use a boolean to determine whether the layoutContent
is selected or not:
Any opionions on this? DocumentOpenSample_V2.zip
protected override Size ArrangeOverride( Size finalSize )
{
var visibleChildren = Children.Cast<UIElement>().Where( ch => ch.Visibility != System.Windows.Visibility.Collapsed );
var offset = 0.0;
var skipAllOthers = false;
foreach( TabItem doc in visibleChildren )
{
if( skipAllOthers || offset + doc.DesiredSize.Width > finalSize.Width )
{
bool isLayoutContentSelected = false;
var layoutContent = doc.Content as LayoutContent;
if (layoutContent != null)
isLayoutContentSelected = layoutContent.IsSelected;
if (isLayoutContentSelected && !doc.IsVisible )
{
var parentContainer = layoutContent.Parent as ILayoutContainer;
var parentSelector = layoutContent.Parent as ILayoutContentSelector;
var parentPane = layoutContent.Parent as ILayoutPane;
int contentIndex = parentSelector.IndexOf( layoutContent );
if( contentIndex > 0 &&
parentContainer.ChildrenCount > 1 )
{
parentPane.MoveChild( contentIndex, 0 );
parentSelector.SelectedContentIndex = 0;
return ArrangeOverride( finalSize );
}
}
doc.Visibility = System.Windows.Visibility.Hidden;
skipAllOthers = true;
}
else
{
doc.Visibility = System.Windows.Visibility.Visible;
doc.Arrange( new Rect( offset, 0.0, doc.DesiredSize.Width, finalSize.Height ) );
offset += doc.ActualWidth + doc.Margin.Left + doc.Margin.Right;
}
}
return finalSize;
}
Solution is available in Version 3.5.3 on Nuget https://www.nuget.org/packages/Dirkster.AvalonDock/
This will be fixed in v3.9.
I have an application using the AvalonDock library, and to fix an issue with new documents not showing content correctly (https://github.com/xceedsoftware/wpftoolkit/issues/1480), we have to set the IsActive property on the LayoutDocument to true in the BeforeInsertDocument method of the ILayoutUpdateStrategy implementation.
With this setup, the library throws a Null Reference Exception under these circumstances:
I have been able to produce a sample application that produces the same error; which is simply the DocumentOpenSample modified to set the IsActive property as described. DocumentOpenSample.zip
Is there a fix or work around for this? I cannot simply remove setting the IsActive property, as that causes the previously mentioned bug.