Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AvalonDockCrash in LayoutGridControl after Resize - ArgumentException #1379

Open
nonsensesoftware opened this issue Sep 18, 2018 · 14 comments
Open

Comments

@nonsensesoftware
Copy link

nonsensesoftware commented Sep 18, 2018

Avalon Dock will crash in certain cases when resizing using the splitter. I can't reproduce it very often so I can't make a sample project that reproduces the issue, but in certain cases throughout testing I have experienced this issue. I'm currently experiencing the issue in v.3.4 of the WpfToolkit.

It appears to be an issue in the GridLength constructor for LayoutGridControl.OnSplitterDragCompleted (from the call-stack). If you look at MSDN documentation related to the GridLength constructor, you can see that it will throw an ArgumentException if the value is NegativeInfinity, PositiveInfinity, or NaN. There are several places in LayoutGridControl.cs where a GridLength is constructed without checking for these edge cases.

I've included the call-stack at the bottom of this issue.

Framework Version: v4.0.30319 Description: The process was terminated due to an unhandled exception. Exception Info: System.ArgumentException at System.Windows.GridLength..ctor(Double, System.Windows.GridUnitType) at Xceed.Wpf.AvalonDock.Controls.LayoutGridControl`1[[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]].OnSplitterDragCompleted(System.Object, System.Windows.Controls.Primitives.DragCompletedEventArgs) at System.Windows.RoutedEventArgs.InvokeHandler(System.Delegate, System.Object) at System.Windows.RoutedEventHandlerInfo.InvokeHandler(System.Object, System.Windows.RoutedEventArgs) at System.Windows.EventRoute.InvokeHandlersImpl(System.Object, System.Windows.RoutedEventArgs, Boolean) at System.Windows.UIElement.RaiseEventImpl(System.Windows.DependencyObject, System.Windows.RoutedEventArgs) at System.Windows.Controls.Primitives.Thumb.OnMouseLeftButtonUp(System.Windows.Input.MouseButtonEventArgs) at System.Windows.RoutedEventArgs.InvokeHandler(System.Delegate, System.Object) at System.Windows.RoutedEventHandlerInfo.InvokeHandler(System.Object, System.Windows.RoutedEventArgs) at System.Windows.EventRoute.InvokeHandlersImpl(System.Object, System.Windows.RoutedEventArgs, Boolean) at System.Windows.UIElement.ReRaiseEventAs(System.Windows.DependencyObject, System.Windows.RoutedEventArgs, System.Windows.RoutedEvent) at System.Windows.UIElement.OnMouseUpThunk(System.Object, System.Windows.Input.MouseButtonEventArgs) at System.Windows.RoutedEventArgs.InvokeHandler(System.Delegate, System.Object) at System.Windows.RoutedEventHandlerInfo.InvokeHandler(System.Object, System.Windows.RoutedEventArgs) at System.Windows.EventRoute.InvokeHandlersImpl(System.Object, System.Windows.RoutedEventArgs, Boolean) at System.Windows.UIElement.RaiseEventImpl(System.Windows.DependencyObject, System.Windows.RoutedEventArgs) at System.Windows.UIElement.RaiseTrustedEvent(System.Windows.RoutedEventArgs) at System.Windows.Input.InputManager.ProcessStagingArea() at System.Windows.Input.InputManager.ProcessInput(System.Windows.Input.InputEventArgs) at System.Windows.Input.InputProviderSite.ReportInput(System.Windows.Input.InputReport) at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr, System.Windows.Input.InputMode, Int32, System.Windows.Input.RawMouseActions, Int32, Int32, Int32) at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr, MS.Internal.Interop.WindowMessage, IntPtr, IntPtr, Boolean ByRef) at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr, Int32, IntPtr, IntPtr, Boolean ByRef) at MS.Win32.HwndWrapper.WndProc(IntPtr, Int32, IntPtr, IntPtr, Boolean ByRef) at MS.Win32.HwndSubclass.DispatcherCallbackOperation(System.Object) at System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate, System.Object, Int32) at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(System.Object, System.Delegate, System.Object, Int32, System.Delegate) at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority, System.TimeSpan, System.Delegate, System.Object, Int32) at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr, Int32, IntPtr, IntPtr) at MS.Win32.UnsafeNativeMethods.DispatchMessage(System.Windows.Interop.MSG ByRef) at System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame) at System.Windows.Application.RunDispatcher(System.Object) at System.Windows.Application.RunInternal(System.Windows.Window) at
.. truncated

@Dirkster99
Copy link

I was able to verify your problem with one of my test applications in my own repository - strange thing is that I can verify your problem only with the Winforms test app not with the WPF test apps :-(
Can you confirm that your problem is related to Winforms only?
I could try a possible fix if you have a suggestion on a possible fix - any ideas would be welcome...

Stacktrace.txt
Stacktrace_1.txt

@nonsensesoftware
Copy link
Author

I'll try reproducing it with a sample application, but this is definitely occurring in WPF as well.

My desktop applications are strictly in WPF. I'll try creating a sample application to repeat what I've experienced in WPF.

@nonsensesoftware
Copy link
Author

Also, if possible, could you attach your test application in which you were able to get this to happen and reproduction steps? I could take a look at some similarities between your sample and my application and perhaps come up with a solution that would work for both.

@Dirkster99
Copy link

Dirkster99 commented Sep 20, 2018

I was able to produce the Stacktraces with this WinFormsTestApp_Debug.zip sample application:
https://ci.appveyor.com/project/Dirkster99/AvalonDock/build/artifacts

which was build with this 3.4 based branch:
https://github.com/Dirkster99/AvalonDock

The most reliable way to produce it is for me to drag the right border of the AutoHide1 Content ToolWindow to the right. But it does not always work either - takes a minute or two of repetitive playing with it.

The shown stacktraces where produced in VS but I can confirm that the application also dies on me with this standalone version (it just does not capture the stacktrace).

This could also be a layout specific issue - so applying the layout in the app.config file from the Winforms app on a WPF app may also lead to reproducing the issue there(?).

unbenannt
unbenannt1

@nonsensesoftware
Copy link
Author

I'll take a look at your fork of AvalonDock and see what I can do.

@nonsensesoftware
Copy link
Author

Hi @Dirkster99. I was able to reproduce the issue in WPF. The trick is to not have the DockHeight/Width set to GridUnitType.Star. When this value is set, the WPF engine will always make the window a valid double value with * (ratio) size. Therefore, when repeating the same process as in your WinForms app, by copying the layout and loading the XML in the MainWindow.xaml.cs MainWindow_Loaded, you can see that, through the debugger, the Document panes have a very, very small size (0.001691348*). This is not the case when the DockHeight and/or DockWidth is set to Auto or Pixel. In these instances, AvalonDock will crash because you can move the panes into negative space to make it throw the exception.

Therefore, in the 4 cases where DockHeight.Star is not handled, the exception case for the GridLength constructor must be handled beforehand. This is all in the OnSplitterDragCompleted event handler (lines 384-456 in your fork). In the attachment below, this is my proposed fix. Note that if the new requested value is invalid, I'm resetting to it to the old height (i.e. the resize doesn't occur). An argument could be made that if the validation fails, it could just set the respective size to 0.0 instead.
proposedfix

While testing this, I can across another issue. Performing the same steps as above, AvalonDock does not obey the bounds of the Window, and will allow panes to be pushed off the application. If you look at the included attachment, the first LayoutAnchorablePaneGroup and the child LayoutAnchroablePane has a DockWidth of 1982. My monitor is 1080P, so its max resolution is 1920x1080.
avalondocklargerthanapplicationwindow

@Dirkster99
Copy link

Cool - I'll try your fix and see if that fixes the issue for me as well - probably sometime tomorrow

I've seen the issue with the window size too but thought its another issue to discussed and fixed in another thread so lets do one by one - currently, I have no idea how to reproduce the window size issue in a reliant fashion so there is some extra testing to be done - I am afraid :-(

Dirkster99 added a commit to Dirkster99/AvalonDock that referenced this issue Sep 21, 2018
@Dirkster99
Copy link

Hi RecursiveNerd - your fix works me - thanx - its available with all the other fixes in my repository or in the commit link shown above this comment.

I have created another issue for the problem where the DockingManager does no longer align with its container #1381 - I think the problem is that you can actually move the GridSplitter beyond the Window limit, but thats just a guess, I don't really know enough about it and the problem does not always appear you need repeated testing to get it to happen...

@nonsensesoftware
Copy link
Author

Glad that seems to have fixed it. Is there going to be a pull request made in the main XCeed toolkit?

There are a few issues in the control, one of which that I believe you have come up with. There are others that I think are a matter of configuration (i.e setting min dock width and height).

@Dirkster99
Copy link

The commit link is the best I can do because my branch is not a fork in the sense of the usual GitHub forks but a manually maintained branch...

nonsensesoftware added a commit to nonsensesoftware/wpftoolkit that referenced this issue Oct 9, 2018
Conform to the data contract for GridLength constructor and provide a valid double value when using the grid splitter to resize layout panes. In certain situations, a user can resize panes into negative space which is not valid.
@nonsensesoftware
Copy link
Author

Hey Dirkster99, just wanted to give a little more information, since I was finally able to reproduce the issue consistently, which may also help you when looking at the other issue #1381 written up. If you move all of the content out of the LayoutDocumentPaneGroup, and move it to the left, right, top, or bottom of the LayoutDocumentPaneGroup, you are given some empty space for the LayoutDocumentPaneGroup (since all content was removed and so content can be moved back into it). In these cases, the Splitter does not obey the application bounds, and allows the user to drag it as far off the bounds as they wish.

Following those cases, it can easily be repeated. I might attempt to take a look at it and see if there is anything I can come up with to fix it. It doesn't look like issues in the community version of the WpfToolkit get commented on very frequently.

@Dirkster99
Copy link

Hey RecursiveNerd, I am tired of the community edition as well since it is usually so unstable that it can be used for prototyping only but hardly for any serious open source project - some core components like AvalonDock will crash your application on arbitrary user actions and (critical) fixes are usually hold off for a year or so or not fixed in the community edition at all... :-( and there are of course new critical issue in the meantime :-) This is mainly why I started my own branch hoping I'll get a rest from this:

#1354 (comment)

@nonsensesoftware
Copy link
Author

I guess that's the reason why you go to the paid version ^_^. Really doesn't benefit the OSS community when you have critical defects that do not get fixed, or are refused to get fixed and the simple answer is "wait for version X.X or upgrade to the paid version".

nonsensesoftware added a commit to nonsensesoftware/wpftoolkit that referenced this issue Oct 17, 2018
This change temporarily fixes several issues, as described in xceedsoftware#1381 and xceedsoftware#1379. The fix is such that the AvalonDock will no longer crash when the control goes out of bounds. However, this does not prevent the actual control from going out of bounds. Therefore, this fix should only be used as a stop-gap until an actual fix can be implemented.
@XceedBoucherS
Copy link
Collaborator

Hi,
All the call to GridLength constructors have been reviewed in v3.8. They will include a validation check.
Thank you.

#1381 will answer the other question.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants