-
Notifications
You must be signed in to change notification settings - Fork 321
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
All documents disappear if document stops close application in Caliburn.Micro #184
Comments
Hi Ryan, I am not sure about the I use the: binding in AvalonDock to close documents when I need to close them vie ViewModel in an MVVM app. Not sure why I would want to cancel this because if so you could evaluate relevant conditions before invoking the comman(?). For the sake of understanding the problem better it might be more useful to manipulate one of the demo apps in this repo to better indicate the problem your are looking at (without using Caliburn.Mirco?). The question I find not answered in this issue is the AvalonDock API that you are intending to use? |
Thanks for the response. I am pretty busy right now, but my plan is to test Caliburn 3.2 as well as the Xceed version of AvalonDock and see if the bug still occurs. Depending on the results, I'll build the issue project with AvalonDock as a project reference so I can step into the source code. In the issue project, I'm binding against Caliburn When I created the test project, I wasn't exactly sure which component caused the bug (I thought it was going to be Caliburn). I have been using AvalonDock since 2013 through the Gemini WPF project (somewhat similar to EDI). When I put AvalonDock side-by-side to a TabControl, it does appear the bug is in this version/fork of AvalonDock. I didn't see it with the Xceed versions, but I hadn't updated or tested it recently either. The Caliburn In the test app, if there is a mix of changed and unchanged documents, all document disappear in AvalonDock, but in the TabControl only the cancelled close documents remain. I haven't fully tested, but it appears that if at least one document closes, then they all disappear. I'll try to figure out more later. |
I just downgraded to Caliburn.Micro 3.2 and the issue does not occur (using the synchronous close logic). So I'm not sure where the bug actually occurs, because the TabControl works with the asynchronous close. I'll test the Xceed libraries for comparison. |
I just tested Xceed.Products.Wpf.Toolkit.AvalonDock 4.0.20315.13310 and the issue occurred. So the likely culprit is Caliburn 4.0. It is still strange since the TabControl behaves as expected. I'd still like to debug the AvalonDock source code, but that will take more time and I'm not sure when I'll get to it. |
Apparently in Caliburn 4.0, the
I assume AvalonDock assumes this means there are no items and closes all documents. I haven't had a chance to look at the AvalonDock source code or debug though. But since the TabControl works, I assume an alternate assumption is to iterate through the collection and check what it actually contains. Based on net searches, at one time |
Looking at the source code, I believe this is the relevant code:
if (e.Action == NotifyCollectionChangedAction.Reset)
{
//NOTE: I'm going to clear every document present in layout but
//some documents may have been added directly to the layout, for now I clear them too
var documentsToRemove = Layout.Descendents().OfType<LayoutDocument>().ToArray();
foreach (var documentToRemove in documentsToRemove)
{
(documentToRemove.Parent as ILayoutContainer).RemoveChild(
documentToRemove);
RemoveViewFromLogicalChild(documentToRemove);
}
} There is a similar block of code for Just for reference, here is the sequence of events occurring in the issue project:
So I think there is indeed a bug in AvalonDock and how it handles |
I came up with the following and it appears to fix the bug - in DockingManager.cs:2076 if (e.Action == NotifyCollectionChangedAction.Reset)
{
//NOTE: Previous implementations cleared all documents from the layout. The current
//guidance is that the collection has changed signficantly, so only remove the
//documents that are no longer in the DocumentSource.
var documentsThatRemain = new HashSet<object>(DocumentsSource.Cast<object>());
var documentsToRemove = Layout.Descendents()
.OfType<LayoutDocument>()
.Where(x => !documentsThatRemain.Contains(x.Content))
.ToArray();
foreach (var documentToRemove in documentsToRemove)
{
(documentToRemove.Parent as ILayoutContainer).RemoveChild(
documentToRemove);
RemoveViewFromLogicalChild(documentToRemove);
}
} I had to use the HashSet constructor instead of the There are several other uses of
|
Hi Ryan, thanks for the detailled analysis - I think your suggested change looks good but I am completely lost when it comes to testing it since I am normally not using this but that's of course no excuse for keeping a bug :-) I understand that the:
So, for consistencies sake its probably best to handle both events the same way unless we can come up with an excuse not to (and I cannot see a reason for keeping this different). The change would just feel much better for me if I had a test case based on the test clients in the repo - so, I better understand when these methods are invoked - and I think we should state a description of that in front of either method - can you suggest something here? For the last two references I am even less sure. I am thinking why fix something that's not broken? So, unless you can come up with a test case + Bug description that justifies a change I'd rather wait until we find a reason for this change. So, in summary, I think we should:
Beyond this I am not sure about changing more - what do you think? |
I think your proposal looks good. I'll try to create a test or two to make sure things actually work. First I need to figure out how to emulate the Another site mentioned that sorting the collection could generate a Reset, although I'm not sure how AvalonDock should behave if the collection was sorted. At the moment, I would recommend just handling the Reset as proposed and not do any reordering of LayoutDocument/Anchorable items. I am busy on other work right now, but I can probably get a pull request with the fix and test cases out sometime next week. |
This reminds me of a custom ObservableRangeCollection I've been using somewhere else. Maybe we can use something like this (with a custom method) to implement a unit test? |
I noticed an issue where all of my documents disappeared even though I cancelled the close (
CanCloseAsync
returns false). When a document closes, it prompts the user to save (Yes, No, or Cancel) where cancel stops the document from closing. I had upgraded several components including AvalonDock, Gemini, and Caliburn.Micro, so I wasn't sure where the error originated. I'm fairly sure the issue is in AvalonDock.I created a test repo to demonstrate the issue: https://github.com/ryanvs/AvalonDockIssue - I also compared AvalonDock to a standard TabControl.
I haven't figured out exactly what is happening, but after the close is stopped, the
PART_SelectedContentHost
is empty and the ActualWidth is 0.The text was updated successfully, but these errors were encountered: