GithubHelp home page GithubHelp logo

Comments (23)

Dirkster99 avatar Dirkster99 commented on May 12, 2024

Hi I cannot verify your problem since you do not show your code

  • but you have to implement a
.LayoutSerializationCallback += (s, e) =>
{
...
}

handler to handle the case in which you load a layout item that cannot be matched to a registered viewmodel/view.

Your description sounds like this is what you are missing?

If thats not the problem please either attach your code or try to explain your problem based on any of the demo projects in this repository, thanx

from avalondock.

dazawa avatar dazawa commented on May 12, 2024

Thanks for your response.

We already have a handler:
serializer.LayoutSerializationCallback += SerializerLayoutSerializationCallback;

Unfortunately, I cannot show any more of the internal code than what I have already posted,
but I will try to reproduce with one of the demo projects today as you suggested and get back to you with the result.

from avalondock.

Dirkster99 avatar Dirkster99 commented on May 12, 2024

The error message 'Collection was modified; enumeration operation may not execute.' does not appear to be a XML serializer specific message. It seems more likely that you are using a foreach loop somewhere in your code to iterate through all toolwindows/documents and the collection gets changed while your foreach iterateration is still on-going.

I would follow the suggestion on StackOverflow (change to foreach(var i in ....ToList())) just to confirm if this fixes the error message. If it does you are probably doing two things in a bad timing and you have to review that problem more carefully.

This could of course also be a bug in AvalonDock but I'd be realy surprised if it was since nobody else has ever mentioned this specific exception...

from avalondock.

dazawa avatar dazawa commented on May 12, 2024

I was able to reproduce the exception only once using the TestApp demo project by randomly closing and reloading toolboxes.
The exception was thrown somewhere within Manager.Layout = layout; in the Deserialize(System.IO.TextReader reader) method in DockingManager... which is weird since all that does is call GetValue/SetValue from DependencyObject.
Unfortunately, I haven't been able to reproduce again....

I also tried downgrading our AvalonDock version from 3.5.10 to 3.5.4.1 which solved the issue.

from avalondock.

Dirkster99 avatar Dirkster99 commented on May 12, 2024

Do you mean using version 3.5.4 solved your issue? Thats really strange because I don't think we've changed anything in particular about the layout serializer. Can you determine the version where it works for you and where it stops working (eg. version 3.5.4 works but version 3.5.5 dows not work)?

from avalondock.

dazawa avatar dazawa commented on May 12, 2024

Yes, 3.5.4 works fine for me but 3.5.5 does not.

from avalondock.

Dirkster99 avatar Dirkster99 commented on May 12, 2024

Thats interesting. The 2 versions are different by a small number of commits shown below in the commit history spanning from 2. May to 13. May. The actual number of commits relevant to us is smaller than whats shown in the history because we only need to look at commits that resulted in a change in the source/Components/Xceed.Wpf.AvalonDock/ library.

Would you be able to setup a test project with the sources from 2. May (verify your problem does not exist) and move forward in the commit history (until 13 May) to see when your problem appears for the first time? This should enable us to find the actual commit that causes your problem and maybe even determine a fix for it :-)

Commit history for version 3.5.4 to 3.5.5

from avalondock.

Dirkster99 avatar Dirkster99 commented on May 12, 2024

Question on the side: Does your exception also occur when you initialize the layout within the ui thread?

I am only asking because I had this other issue with two other users and it turned out that one possible solution was to initialize the layout in the context of the ui thread (you may load the string within a background task but do the deserialization in the ui thread as shown in the link above).

from avalondock.

dazawa avatar dazawa commented on May 12, 2024

Hi, sorry for the late reply.
I did what you suggested and went through each commit between 3.5.4 and 3.5.5.
The issue appears for the first time after the merge you did on 13.05. (ID: f818c88).
The commits before (0996752 and earlier) that all do not have the issue.

initializing the layout inside or outside of the ui thread does not affect the issue.

from avalondock.

Dirkster99 avatar Dirkster99 commented on May 12, 2024

Hey, thanks for testing this but your result looks really impossible because you can see in the change log that the merge did not change anything in the source/Components/Xceed.Wpf.AvalonDock/ library.

All that was changed was the Readme.md file, and some files in MLibTest which is a demo project (unless I am missing something here).

So, the problem must at least either be one (or more) commit(s) before or after this commit, but not the linked commit (would you agree?)

from avalondock.

dazawa avatar dazawa commented on May 12, 2024

Yes, I fully agree, it does look strange, I'm just saying what results I came to.
I will double check.
In the meantime, I've narrowed the source of the issue down to the following foreach located in /Layout/Extensions.cs by analyzing the stack-trace a bit closer:
foreach( var childElement in container.Children ) { yield return childElement; foreach( var childChildElement in childElement.Descendents() ) yield return childChildElement; }

This is where the exception is thrown.
Does this help you in any way?

I will check the commits again.

from avalondock.

Dirkster99 avatar Dirkster99 commented on May 12, 2024

The reference is relevant as it shows what I initially suggested. So, you could go ahead and replace the Foreach loops with the ToList() statements using for loops instead to test whether this results in a crash somewhere else - since that crash could indicate the real source of your problem.

The code you are refering to is used in 81 places to recursively visit all Children of all Children in the Hierarchy of containers that can be configured in AvalonDock

public static IEnumerable<ILayoutElement> Descendents( this ILayoutElement element )
{
  var container = element as ILayoutContainer;
  if( container != null )
  {
    foreach( var childElement in container.Children )
    {
      yield return childElement;
      foreach( var childChildElement in childElement.Descendents() )
        yield return childChildElement;
    }
  }
}

The originating call seems to be coming from the DockingManager's.InternalSetActiveContent(...) method (if I read the stack trace correctly):

private void InternalSetActiveContent( object contentObject )
{
  var layoutContent = Layout.Descendents().OfType<LayoutContent>().FirstOrDefault( lc => lc == contentObject || lc.Content == contentObject );
  _insideInternalSetActiveContent = true;
  Layout.ActiveContent = layoutContent;
  _insideInternalSetActiveContent = false;
}

So, this makes me wonder, if the controls that you use within the AvalonDock containers are:

  1. aquiring a focus or
  2. try to activate themeselves when being loaded - or
  3. try to add a type of layoutanchorable while deserialization takes place?

this may even be initiated through a bound viewmodel. So, another way of isolating this problem could be to test whether deactivating code attached to OnLoadEvents of each control (and other such events) would lead to an absence of the error - if yes - we would know at last how the problem was triggered but not why, yet...

Either way, it should be possible to isolate the problem either in the test appliactions in this repository (by adjusting the test application such that your problem is visible) or adjusting a test version of you own application such that the problem is no longer verifyable...

The result should be that we find:

  1. its connected to a certain control being used in your AvalonDock app or
  2. a certain layout that cause the problem no matter was control is used.

I take it the layout is not the problem as you were able to check with the test apps? Maybe its time to take a hard look at your app then?

from avalondock.

Martin5630 avatar Martin5630 commented on May 12, 2024

@Dirkster99 I also get an error with the MFLibTest application. I used the application to find out why the AutoHide not working. I get the error in the DockingManager Class in the method DockingManager_Loaded

AvalonDock.Layout.txt

image

And I also get the error in the Extension method in my Application when I load different Layouts at runtime.I have only Tool-Windows in my Application. So what I do actually is, before I load a new Layout I set by all the Toolwindows the property isvisible = false. I hope this helps to find the error in AvalonDock. It must be a race condition when AvalonDock add and removes anchorables.

from avalondock.

Dirkster99 avatar Dirkster99 commented on May 12, 2024

OK, I can verify the exception with the Layout from @Martin5630 thanks for that - I can now look deeper into it :-)

The source of the problem in the layout from @Martin5630 seems to be the LayoutDocumentFloatingWindow tag - I can replace it with <LayoutDocumentFloatingWindow/> and the exception is no longer thrown. Although, the problem is similar in its nature it seems to be different to the original exception which was raised in the Extensions.cs method and the original layout from @dazawa does not contain a LayoutDocumentFloatingWindow item - so, both problems are similar in their nature but probably not the same :-(

    <LayoutDocumentFloatingWindow>
      <LayoutDocument Title="Noname" IsLastFocusedDocument="True" FloatingLeft="1394.28571428571" FloatingTop="321.714285714286" FloatingWidth="770.857142857143" FloatingHeight="433.142857142857" LastActivationTimeStamp="08/13/2019 12:47:24" PreviousContainerId="6f73d732-d2a8-47da-ae59-d6ba0fdeaf15" PreviousContainerIndex="0" />
    </LayoutDocumentFloatingWindow>

More precisly, I can remove the PreviousContainerId="6f73d732-d2a8-47da-ae59-d6ba0fdeaf15" item from the above tag and the exception is no longer happening for me.

A possible fix for the exception from @Martin5630 seems to be to finish the query before adding the new FloatingWindowControls in the DockingManager_Loaded method in line 2396 of DockingManager.cs:

        List<LayoutFloatingWindow> items = new List<LayoutFloatingWindow>(Layout.FloatingWindows.Where(fw => !_fwList.Any(fwc => fwc.Model == fw)));
        foreach ( var fw in items)
          _fwList.Add( CreateUIElementForModel( fw ) as LayoutFloatingWindowControl );

I have to think about this - it looks like there are too many linq queries based on events and events of events that will eventually create a race condition as we see here, so I am not sure if the above is really a solution or just a hack :-(

from avalondock.

Dirkster99 avatar Dirkster99 commented on May 12, 2024

Hi @dazawa and @Martin5630

I have created a fix candidate for the deserializing issues discussed here:

  1. issue 1
  2. issue 2

This candidate is in a seperate branch to make sure it does fix the issue and breaks nothing else - would you guys please download, compile and test the branch to see if this clears your issues that you mentioned?

  • I cannot verify whether this will work for the initial issue reported here :-(

It would also be good if you could do some general testing to amke sure nothing new creps up:

Branch for testing is here: EnumInvalidOperationException

from avalondock.

dazawa avatar dazawa commented on May 12, 2024

Hi @Dirkster99
sorry for the late reply, I've been away.

Thanks for the effort! I will test as soon as I get back, which will be in a couple of days and will post an update here.

from avalondock.

Dirkster99 avatar Dirkster99 commented on May 12, 2024

This issue should be fixed with version 3.6.1 (just released it now)

from avalondock.

dazawa avatar dazawa commented on May 12, 2024

Hey @Dirkster99
We updated to the latest version (3.6.1) but this issue still occurs.
Same error path and exception.

from avalondock.

Dirkster99 avatar Dirkster99 commented on May 12, 2024

That's really strange, I expected this to resolved now :-( can you please post the current stack trace one more time? - at least some line numbers should be different now … I am really at a lost end since I cannot debug your problem so I am not able to find a fix - do you have any suggestion towards a fix?

from avalondock.

dazawa avatar dazawa commented on May 12, 2024

Here's the full StackTrace

Error Message: Collection was modified; enumeration operation may not execute.
Top-level Exception
Type: System.InvalidOperationException
Message: Collection was modified; enumeration operation may not execute.
Source: mscorlib
Stack Trace: at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
at System.Collections.Generic.List1.Enumerator.MoveNextRare() at System.Collections.Generic.List1.Enumerator.MoveNext()
at Xceed.Wpf.AvalonDock.Layout.Extensions.<Descendents>d__0.MoveNext()
at Xceed.Wpf.AvalonDock.Layout.Extensions.<Descendents>d__0.MoveNext()
at Xceed.Wpf.AvalonDock.Layout.Extensions.<Descendents>d__0.MoveNext()
at Xceed.Wpf.AvalonDock.Layout.Extensions.<Descendents>d__0.MoveNext()
at Xceed.Wpf.AvalonDock.Layout.Extensions.<Descendents>d__0.MoveNext()
at Xceed.Wpf.AvalonDock.Layout.Extensions.<Descendents>d__0.MoveNext()
at System.Linq.Enumerable.<OfTypeIterator>d__951.MoveNext() at Xceed.Wpf.AvalonDock.DockingManager.Layout_ElementAdded(Object sender, LayoutElementEventArgs e) at Xceed.Wpf.AvalonDock.Layout.LayoutRoot.OnLayoutElementAdded(LayoutElement element) at Xceed.Wpf.AvalonDock.Layout.LayoutElement.OnRootChanged(ILayoutRoot oldRoot, ILayoutRoot newRoot) at Xceed.Wpf.AvalonDock.Layout.LayoutElement.set_Parent(ILayoutContainer value) at Xceed.Wpf.AvalonDock.Layout.LayoutGroup1._children_CollectionChanged(Object sender, NotifyCollectionChangedEventArgs e)
at System.Collections.Specialized.NotifyCollectionChangedEventHandler.Invoke(Object sender, NotifyCollectionChangedEventArgs e)
at System.Collections.ObjectModel.ObservableCollection1.OnCollectionChanged(NotifyCollectionChangedEventArgs e) at System.Collections.ObjectModel.ObservableCollection1.RemoveItem(Int32 index)
at System.Collections.ObjectModel.Collection1.Remove(T item) at Xceed.Wpf.AvalonDock.Layout.LayoutGroup1.RemoveChild(ILayoutElement element)
at Xceed.Wpf.AvalonDock.DockingManager.DetachAnchorablesSource(LayoutRoot layout, IEnumerable anchorablesSource)
at Xceed.Wpf.AvalonDock.DockingManager.OnLayoutChanged(LayoutRoot oldLayout, LayoutRoot newLayout)
at Xceed.Wpf.AvalonDock.DockingManager.OnLayoutChanged(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(DependencyProperty dp, Object value)
at Xceed.Wpf.AvalonDock.Layout.Serialization.XmlLayoutSerializer.Deserialize(TextReader reader)
at Alpine.Gui.TestSuite.TestSuiteWindow.LoadDefaultLayout(Object sender, RoutedEventArgs e) in D:#ATAT3\ATAT3\src\Core\Alpine.Gui\TestSuite\TestSuiteWindow.xaml.cs:line 383
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.MenuItem.InvokeClickAfterRender(Object arg)
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)

from avalondock.

Dirkster99 avatar Dirkster99 commented on May 12, 2024

OK, since this nut seems to be a little harder to crack, please do also think about additional evidence like screenshot of the case in VS or (even better) a separate test client showing the problem with a certain workflow.

from avalondock.

jacobavenkraft avatar jacobavenkraft commented on May 12, 2024

Hello Dirkster99,
I have just started investigating using AvalonDock and was writing some test applications. I ran across this exact same issue -- I am using the 4.10 version available on NuGet. I downloaded your code from GitHub so that I could debug the issue.

In my test app, it appears that the underlying issue is caused by the following section of code within DockingManager.cs:
image

The "foreach" loop is calling Layout.Descendants() which as you know uses yield returns to return the descendants. I believe the calls to CreateDocumentLayoutItem and CreateAnchorableLayoutItem have the potential to modify the contents of the Layout and thus a "Collection was modified" exception gets thrown.

Changing the code as follows ensured that the exception did not occur (at least with my test app):

image

from avalondock.

Dirkster99 avatar Dirkster99 commented on May 12, 2024

@jacobavenkraft Thanks for the useful feedback - I've implemented a fix as you suggested above and hope this will finally fix this issue. I am going to do another release soon ...
Thanx Drk

from avalondock.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.