diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Database/IReorderable.cs b/src/Snap.Hutao/Snap.Hutao/Core/Database/IReorderable.cs new file mode 100644 index 00000000..2059efd4 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Core/Database/IReorderable.cs @@ -0,0 +1,9 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Core.Database; + +internal interface IReorderable +{ + int Index { get; set; } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Database/ObservableReorderableDbCollection.cs b/src/Snap.Hutao/Snap.Hutao/Core/Database/ObservableReorderableDbCollection.cs new file mode 100644 index 00000000..19a19dac --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Core/Database/ObservableReorderableDbCollection.cs @@ -0,0 +1,66 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Microsoft.EntityFrameworkCore; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Runtime.InteropServices; + +namespace Snap.Hutao.Core.Database; + +internal sealed class ObservableReorderableDbCollection : ObservableCollection + where T : class, IReorderable +{ + private readonly DbContext dbContext; + private bool previousChangeIsRemoved; + + public ObservableReorderableDbCollection(List items, DbContext dbContext) + : base(AdjustIndex(items)) + { + this.dbContext = dbContext; + } + + protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) + { + base.OnCollectionChanged(e); + + switch (e.Action) + { + case NotifyCollectionChangedAction.Remove: + previousChangeIsRemoved = true; + break; + case NotifyCollectionChangedAction.Add: + if (!previousChangeIsRemoved) + { + return; + } + + OnReorder(); + previousChangeIsRemoved = false; + break; + } + } + + private static List AdjustIndex(List list) + { + Span span = CollectionsMarshal.AsSpan(list); + for (int i = 0; i < list.Count; i++) + { + ref readonly T item = ref span[i]; + item.Index = i; + } + + return list; + } + + private void OnReorder() + { + AdjustIndex((List)Items); + + DbSet dbSet = dbContext.Set(); + foreach (ref readonly T item in CollectionsMarshal.AsSpan((List)Items)) + { + dbSet.UpdateAndSave(item); + } + } +} \ No newline at end of file