Dock icon indicating copy to clipboard operation
Dock copied to clipboard

Unable to drag and drop a tool from one dock to another with deserialized layout

Open SparkyTD opened this issue 3 years ago • 6 comments

I'm trying to save the layout of a DockControl to a file by using the 'official' Dock.Serializer package from nuget, but I've run into an issue. The tool is able to serialize a layout into a json file, and it can also load it back and deserialize it, and at first glance it seems fine, but if I try to move a tool tab from one dock to another, it completely fails. The dragged tab disappears, and after a few more tries the whole application crashes.

I've also tried this with my own custom xml serializer, but I get the same results. Note that the original layout that comes out of the Factory works as expected, and I can drag tabs around without any issues.

My Factory class is basically just a stripped-down copy of the sample Factory class, but it only creates two panels and two tools. I assume that this issue is caused by some sort of hidden property that is being set in the Factory class, but it's not saved into the json file by the serializer.

This is a short video that demonstrated this problem:

https://user-images.githubusercontent.com/45818400/118377520-63fbb080-b5d6-11eb-8b66-d11664878578.mp4

And here is the full crash log from the video.

SparkyTD avatar May 15 '21 20:05 SparkyTD

Did you initialize layout?

wieslawsoltes avatar May 15 '21 20:05 wieslawsoltes

Did you initialize layout?

Yes, once the layout is loaded, it is handled the same way as if it was made by a Factory. You can see in the first second of the video, layout is the deserialized object, and layout_f is the one made by the factory. If I use layout_f on line 29, everything works.

SparkyTD avatar May 15 '21 21:05 SparkyTD

What version of Dock are you using ?

wieslawsoltes avatar May 17 '21 13:05 wieslawsoltes

These are the nuget packages in my project: Dock.Avalonia 0.10.4 Dock.Avalonia.Themes.Metro 0.9.12 Dock.Avalonia.Themes.Default 0.10.0 Dock.Model 0.10.4 Dock.Model.Avalonia 0.10.0 Dock.Model.ReactiveUI 0.10.4 Dock.Serializer 0.10.0

SparkyTD avatar May 17 '21 13:05 SparkyTD

Ah Dock.Serializer is deprecated.

wieslawsoltes avatar Aug 29 '21 16:08 wieslawsoltes

Try this


        private class ListContractResolver : DefaultContractResolver
        {
            private readonly Type _type;

            public ListContractResolver(Type type)
            {
                _type = type;
            }

            public override JsonContract ResolveContract(Type type)
            {
                if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(IList<>))
                {
                    return base.ResolveContract(_type.MakeGenericType(type.GenericTypeArguments[0]));
                }
                return base.ResolveContract(type);
            }

            protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
            {
                return base.CreateProperties(type, memberSerialization).Where(p => p.Writable).ToList();
            }
        }
        
            var jsonSettings = new JsonSerializerSettings()
            {
                Formatting = Formatting.Indented,
                TypeNameHandling = TypeNameHandling.Objects,
                PreserveReferencesHandling = PreserveReferencesHandling.Objects,
                ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
                ContractResolver = new ListContractResolver(typeof(ObservableCollection<>)),
                NullValueHandling = NullValueHandling.Ignore,
                Converters =
                {
                    new KeyValuePairConverter()
                }
            };
            var rootDock = default(RootDock);
            var rootDockPath = System.IO.Path.Combine(fileSystem?.GetBaseDirectory(), "Core2D.layout");
            if (fileSystem.Exists(rootDockPath))
            {
                var jsonRootDock = fileSystem?.ReadUtf8Text(rootDockPath);
                if (!string.IsNullOrEmpty(jsonRootDock))
                {
                    rootDock = JsonConvert.DeserializeObject<RootDock>(jsonRootDock, jsonSettings);
                    if (rootDock is { })
                    {
                        editor.LoadLayout(rootDock);
                    }
                }
            }
               var jsonRootDock = JsonConvert.SerializeObject(editor.RootDock, jsonSettings);
                if (!string.IsNullOrEmpty(jsonRootDock))
                {
                    fileSystem?.WriteUtf8Text(rootDockPath, jsonRootDock);
                }

wieslawsoltes avatar Aug 29 '21 18:08 wieslawsoltes