From 26748e5885344966a040c401b0fd1a37c36daef2 Mon Sep 17 00:00:00 2001 From: Lightczx <1686188646@qq.com> Date: Tue, 6 Feb 2024 11:16:59 +0800 Subject: [PATCH] generic AdvancedCollectionView --- .../AdvancedCollectionView.cs | 182 ++++++++++-------- .../IAdvancedCollectionView.cs | 105 ++++++++++ .../Achievement/AchievementViewModel.cs | 35 ++-- .../ViewModel/Game/GameAccountFilter.cs | 4 +- .../ViewModel/Game/LaunchGameViewModel.cs | 8 +- .../ViewModel/Game/LaunchGameViewModelSlim.cs | 4 +- .../Snap.Hutao/ViewModel/Wiki/AvatarFilter.cs | 4 +- .../Snap.Hutao/ViewModel/Wiki/WeaponFilter.cs | 4 +- .../ViewModel/Wiki/WikiAvatarViewModel.cs | 8 +- .../ViewModel/Wiki/WikiMonsterViewModel.cs | 8 +- .../ViewModel/Wiki/WikiWeaponViewModel.cs | 8 +- 11 files changed, 245 insertions(+), 125 deletions(-) create mode 100644 src/Snap.Hutao/Snap.Hutao/Control/Collection/AdvancedCollectionView/IAdvancedCollectionView.cs diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Collection/AdvancedCollectionView/AdvancedCollectionView.cs b/src/Snap.Hutao/Snap.Hutao/Control/Collection/AdvancedCollectionView/AdvancedCollectionView.cs index 386b4340..d85c64e5 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Collection/AdvancedCollectionView/AdvancedCollectionView.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Collection/AdvancedCollectionView/AdvancedCollectionView.cs @@ -16,25 +16,26 @@ using NotifyCollectionChangedAction = System.Collections.Specialized.NotifyColle namespace Snap.Hutao.Control.Collection.AdvancedCollectionView; -internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyPropertyChanged, ISupportIncrementalLoading, IComparer +internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyPropertyChanged, ISupportIncrementalLoading, IComparer + where T : class { - private readonly List view; + private readonly List view; private readonly ObservableCollection sortDescriptions; - private readonly Dictionary sortProperties; + private readonly Dictionary sortProperties; private readonly bool liveShapingEnabled; - private readonly HashSet observedFilterProperties = []; + private readonly HashSet observedFilterProperties = []; - private IList source; - private Predicate? filter; + private IList source; + private Predicate? filter; private int deferCounter; - private WeakEventListener? sourceWeakEventListener; + private WeakEventListener, object?, NotifyCollectionChangedEventArgs>? sourceWeakEventListener; public AdvancedCollectionView() - : this(new List(0)) + : this(new List(0)) { } - public AdvancedCollectionView(IList source, bool isLiveShaping = false) + public AdvancedCollectionView(IList source, bool isLiveShaping = false) { liveShapingEnabled = isLiveShaping; view = []; @@ -44,22 +45,22 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP Source = source; } - public event VectorChangedEventHandler? VectorChanged; - public event EventHandler? CurrentChanged; public event CurrentChangingEventHandler? CurrentChanging; public event PropertyChangedEventHandler? PropertyChanged; - public IList Source + public event VectorChangedEventHandler? VectorChanged; + + public IList Source { get => source; [MemberNotNull(nameof(source))] set { - if (source == value) + if (ReferenceEquals(source, value)) { return; } @@ -74,22 +75,21 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP sourceWeakEventListener?.Detach(); - if (source is INotifyCollectionChanged sourceNcc) + if (source is INotifyCollectionChanged sourceNotifyCollectionChanged) { - sourceWeakEventListener = - new WeakEventListener(this) - { - // Call the actual collection changed event - OnEventAction = (source, changed, arg3) => SourceNotifyCollectionChangedCollectionChanged(source, arg3), + sourceWeakEventListener = new WeakEventListener, object?, NotifyCollectionChangedEventArgs>(this) + { + // Call the actual collection changed event + OnEventAction = (source, changed, arg3) => SourceNotifyCollectionChangedCollectionChanged(source, arg3), - // The source doesn't exist anymore - OnDetachAction = (listener) => - { - ArgumentNullException.ThrowIfNull(sourceWeakEventListener); - sourceNcc.CollectionChanged -= sourceWeakEventListener.OnEvent; - }, - }; - sourceNcc.CollectionChanged += sourceWeakEventListener.OnEvent; + // The source doesn't exist anymore + OnDetachAction = (listener) => + { + ArgumentNullException.ThrowIfNull(sourceWeakEventListener); + sourceNotifyCollectionChanged.CollectionChanged -= sourceWeakEventListener.OnEvent; + }, + }; + sourceNotifyCollectionChanged.CollectionChanged += sourceWeakEventListener.OnEvent; } HandleSourceChanged(); @@ -112,9 +112,9 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP get => default!; } - public object? CurrentItem + public T? CurrentItem { - get => CurrentPosition > -1 && CurrentPosition < view.Count ? view[CurrentPosition] : null; + get => CurrentPosition > -1 && CurrentPosition < view.Count ? view[CurrentPosition] : default; set => MoveCurrentTo(value); } @@ -122,7 +122,7 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP public bool HasMoreItems { - get => (source as ISupportIncrementalLoading)?.HasMoreItems ?? false; + get => source is ISupportIncrementalLoading { HasMoreItems: true }; } public bool IsCurrentAfterLast @@ -140,7 +140,7 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP get => true; } - public Predicate Filter + public Predicate? Filter { get => filter; set @@ -165,12 +165,17 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP get => sortDescriptions; } - public IEnumerable SourceCollection + public IEnumerable SourceCollection { get => source; } - public object this[int index] + public IReadOnlyList View + { + get => view; + } + + public T this[int index] { get => view[index]; set => view[index] = value; @@ -191,7 +196,7 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP HandleSortChanged(); } - public IEnumerator GetEnumerator() + public IEnumerator GetEnumerator() { return view.GetEnumerator(); } @@ -201,7 +206,7 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP return view.GetEnumerator(); } - public void Add(object item) + public void Add(T item) { ThrowHelper.NotSupportedIf(IsReadOnly, "Collection is read-only."); source.Add(item); @@ -213,29 +218,30 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP source.Clear(); } - public bool Contains(object item) + public bool Contains(T item) { return view.Contains(item); } - public void CopyTo(object[] array, int arrayIndex) + public void CopyTo(T[] array, int arrayIndex) { view.CopyTo(array, arrayIndex); } - public bool Remove(object item) + public bool Remove(T item) { ThrowHelper.NotSupportedIf(IsReadOnly, "Collection is read-only."); source.Remove(item); return true; } - public int IndexOf(object item) + [SuppressMessage("", "SH007")] + public int IndexOf(T? item) { - return view.IndexOf(item); + return view.IndexOf(item!); } - public void Insert(int index, object item) + public void Insert(int index, T item) { ThrowHelper.NotSupportedIf(IsReadOnly, "Collection is read-only."); source.Insert(index, item); @@ -246,9 +252,9 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP Remove(view[index]); } - public bool MoveCurrentTo(object? item) + public bool MoveCurrentTo(T? item) { - return item == CurrentItem || MoveCurrentToIndex(IndexOf(item)); + return (item is not null && item.Equals(CurrentItem)) || MoveCurrentToIndex(IndexOf(item)); } public bool MoveCurrentToPosition(int index) @@ -296,14 +302,14 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP return new NotificationDeferrer(this); } - int IComparer.Compare(object? x, object? y) + int IComparer.Compare(T? x, T? y) { if (sortProperties.Count <= 0) { - Type? listType = source?.GetType(); + Type listType = source.GetType(); Type? type; - if (listType is { IsGenericType: true }) + if (listType.IsGenericType) { type = listType.GetGenericArguments()[0]; } @@ -323,7 +329,7 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP foreach (SortDescription sd in sortDescriptions) { - object cx, cy; + T? cx, cy; if (string.IsNullOrEmpty(sd.PropertyName)) { @@ -332,17 +338,17 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP } else { - PropertyInfo pi = sortProperties[sd.PropertyName]; + PropertyInfo? pi = sortProperties[sd.PropertyName]; - cx = pi.GetValue(x!); - cy = pi.GetValue(y!); + cx = (T?)pi?.GetValue(x); + cy = (T?)pi?.GetValue(y); } int cmp = sd.Comparer.Compare(cx, cy); - if (cmp != 0) + if (cmp is not 0) { - return sd.Direction == SortDirection.Ascending ? +cmp : -cmp; + return sd.Direction is SortDirection.Ascending ? +cmp : -cmp; } } @@ -361,25 +367,28 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP return; } - bool? filterResult = filter?.Invoke(item); + ArgumentNullException.ThrowIfNull(item); + T typedItem = (T)item; + + bool? filterResult = filter?.Invoke(typedItem); if (filterResult.HasValue && observedFilterProperties.Contains(e.PropertyName)) { - int viewIndex = view.IndexOf(item); + int viewIndex = view.IndexOf(typedItem); if (viewIndex != -1 && !filterResult.Value) { - RemoveFromView(viewIndex, item); + RemoveFromView(viewIndex, typedItem); } else if (viewIndex == -1 && filterResult.Value) { - int index = source.IndexOf(item); - HandleItemAdded(index, item); + int index = source.IndexOf(typedItem); + HandleItemAdded(index, typedItem); } } if ((filterResult ?? true) && SortDescriptions.Any(sd => sd.PropertyName == e.PropertyName)) { - int oldIndex = view.IndexOf(item); + int oldIndex = view.IndexOf(typedItem); // Check if item is in view: if (oldIndex < 0) @@ -388,7 +397,7 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP } view.RemoveAt(oldIndex); - int targetIndex = view.BinarySearch(item, this); + int targetIndex = view.BinarySearch(typedItem, this); if (targetIndex < 0) { targetIndex = ~targetIndex; @@ -397,15 +406,15 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP // Only trigger expensive UI updates if the index really changed: if (targetIndex != oldIndex) { - OnVectorChanged(new VectorChangedEventArgs(CollectionChange.ItemRemoved, oldIndex, item)); + OnVectorChanged(new VectorChangedEventArgs(CollectionChange.ItemRemoved, oldIndex, typedItem)); - view.Insert(targetIndex, item); + view.Insert(targetIndex, typedItem); - OnVectorChanged(new VectorChangedEventArgs(CollectionChange.ItemInserted, targetIndex, item)); + OnVectorChanged(new VectorChangedEventArgs(CollectionChange.ItemInserted, targetIndex, typedItem)); } else { - view.Insert(targetIndex, item); + view.Insert(targetIndex, typedItem); } } else if (string.IsNullOrEmpty(e.PropertyName)) @@ -421,9 +430,12 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP return; } - foreach (INotifyPropertyChanged item in items.OfType()) + foreach (object item in items) { - item.PropertyChanged += ItemOnPropertyChanged; + if (item is INotifyPropertyChanged notifyPropertyChanged) + { + notifyPropertyChanged.PropertyChanged += ItemOnPropertyChanged; + } } } @@ -434,9 +446,12 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP return; } - foreach (INotifyPropertyChanged item in items.OfType()) + foreach (object item in items) { - item.PropertyChanged -= ItemOnPropertyChanged; + if (item is INotifyPropertyChanged notifyPropertyChanged) + { + notifyPropertyChanged.PropertyChanged -= ItemOnPropertyChanged; + } } } @@ -454,7 +469,7 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP { for (int index = 0; index < view.Count; index++) { - object item = view.ElementAt(index); + T item = view[index]; if (filter(item)) { continue; @@ -465,12 +480,11 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP } } - HashSet viewHash = new(view); + HashSet viewHash = new(view); int viewIndex = 0; for (int index = 0; index < source.Count; index++) { - object? item = source[index]; - ArgumentNullException.ThrowIfNull(item); + T item = source[index]; if (viewHash.Contains(item)) { viewIndex++; @@ -487,16 +501,16 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP private void HandleSourceChanged() { sortProperties.Clear(); - object? currentItem = CurrentItem; + T? currentItem = CurrentItem; view.Clear(); - foreach (object? item in Source) + foreach (T item in Source) { if (filter is not null && !filter(item)) { continue; } - if (sortDescriptions.Any()) + if (sortDescriptions.Count > 0) { int targetIndex = view.BinarySearch(item, this); if (targetIndex < 0) @@ -530,7 +544,7 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP { object? newItem = e.NewItems[0]; ArgumentNullException.ThrowIfNull(newItem); - HandleItemAdded(e.NewStartingIndex, newItem); + HandleItemAdded(e.NewStartingIndex, (T)newItem); } else { @@ -548,7 +562,7 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP { object? oldItem = e.OldItems[0]; ArgumentNullException.ThrowIfNull(oldItem); - HandleItemRemoved(e.OldStartingIndex, oldItem); + HandleItemRemoved(e.OldStartingIndex, (T)oldItem); } else { @@ -569,7 +583,7 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP } } - private bool HandleItemAdded(int newStartingIndex, object newItem, int? viewIndex = null) + private bool HandleItemAdded(int newStartingIndex, T newItem, int? viewIndex = null) { if (filter is not null && !filter(newItem)) { @@ -578,7 +592,7 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP int newViewIndex = view.Count; - if (sortDescriptions.Any()) + if (sortDescriptions.Count > 0) { sortProperties.Clear(); newViewIndex = view.BinarySearch(newItem, this); @@ -617,7 +631,7 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP break; } - if (view[j] == source[i]) + if (Equals(view[j], source[i])) { j++; } @@ -635,7 +649,7 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP return true; } - private void HandleItemRemoved(int oldStartingIndex, object oldItem) + private void HandleItemRemoved(int oldStartingIndex, T oldItem) { if (filter is not null && !filter(oldItem)) { @@ -655,7 +669,7 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP RemoveFromView(oldStartingIndex, oldItem); } - private void RemoveFromView(int itemIndex, object item) + private void RemoveFromView(int itemIndex, T item) { view.RemoveAt(itemIndex); if (itemIndex <= CurrentPosition) @@ -734,10 +748,10 @@ internal sealed class AdvancedCollectionView : IAdvancedCollectionView, INotifyP internal sealed class NotificationDeferrer : IDisposable { - private readonly AdvancedCollectionView advancedCollectionView; - private readonly object? currentItem; + private readonly AdvancedCollectionView advancedCollectionView; + private readonly T? currentItem; - public NotificationDeferrer(AdvancedCollectionView acvs) + public NotificationDeferrer(AdvancedCollectionView acvs) { advancedCollectionView = acvs; currentItem = advancedCollectionView.CurrentItem; diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Collection/AdvancedCollectionView/IAdvancedCollectionView.cs b/src/Snap.Hutao/Snap.Hutao/Control/Collection/AdvancedCollectionView/IAdvancedCollectionView.cs new file mode 100644 index 00000000..e8fd0810 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Control/Collection/AdvancedCollectionView/IAdvancedCollectionView.cs @@ -0,0 +1,105 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using CommunityToolkit.WinUI.Collections; +using Microsoft.UI.Xaml.Data; +using System.Collections; + +namespace Snap.Hutao.Control.Collection.AdvancedCollectionView; + +internal interface IAdvancedCollectionView : ICollectionView, IEnumerable + where T : class +{ + bool CanFilter { get; } + + bool CanSort { get; } + + object? ICollectionView.CurrentItem + { + get => CurrentItem; + } + + new T? CurrentItem { get; } + + Predicate? Filter { get; set; } + + IList SortDescriptions { get; } + + IEnumerable SourceCollection { get; } + + object IList.this[int index] + { + get => this[index]; + set => this[index] = (T)value; + } + + new T this[int index] { get; set; } + + void ICollection.Add(object item) + { + Add((T)item); + } + + void Add(T item); + + void ClearObservedFilterProperties(); + + bool ICollection.Contains(object item) + { + return Contains((T)item); + } + + bool Contains(T item); + + void ICollection.CopyTo(object[] array, int arrayIndex) + { + CopyTo((T[])array, arrayIndex); + } + + void CopyTo(T[] array, int arrayIndex); + + IDisposable DeferRefresh(); + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + new IEnumerator GetEnumerator(); + + int IList.IndexOf(object item) + { + return IndexOf((T)item); + } + + int IndexOf(T item); + + void IList.Insert(int index, object item) + { + Insert(index, (T)item); + } + + void Insert(int index, T item); + + bool ICollectionView.MoveCurrentTo(object item) + { + return MoveCurrentTo((T)item); + } + + bool MoveCurrentTo(T item); + + void ObserveFilterProperty(string propertyName); + + void Refresh(); + + void RefreshFilter(); + + void RefreshSorting(); + + bool ICollection.Remove(object item) + { + return Remove((T)item); + } + + bool Remove(T item); +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Achievement/AchievementViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Achievement/AchievementViewModel.cs index 7bffcb88..4c1891e4 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Achievement/AchievementViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Achievement/AchievementViewModel.cs @@ -43,7 +43,7 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav private readonly JsonSerializerOptions options; private readonly ITaskContext taskContext; - private AdvancedCollectionView? achievements; + private AdvancedCollectionView? achievements; private List? achievementGoals; private AchievementGoalView? selectedAchievementGoal; private ObservableCollection? archives; @@ -85,7 +85,7 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav /// /// 成就视图 /// - public AdvancedCollectionView? Achievements + public AdvancedCollectionView? Achievements { get => achievements; set => SetProperty(ref achievements, value); @@ -342,17 +342,19 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav [Command("SortUncompletedSwitchCommand")] private void UpdateAchievementsSort() { - if (Achievements is not null) + if (Achievements is null) { - if (IsUncompletedItemsFirst) - { - Achievements.SortDescriptions.Add(uncompletedItemsFirstSortDescription); - Achievements.SortDescriptions.Add(completionTimeSortDescription); - } - else - { - Achievements.SortDescriptions.Clear(); - } + return; + } + + if (IsUncompletedItemsFirst) + { + Achievements.SortDescriptions.Add(uncompletedItemsFirstSortDescription); + Achievements.SortDescriptions.Add(completionTimeSortDescription); + } + else + { + Achievements.SortDescriptions.Clear(); } } @@ -367,7 +369,7 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav else { Model.Primitive.AchievementGoalId goalId = goal.Id; - Achievements.Filter = (object o) => o is AchievementView view && view.Inner.Goal == goalId; + Achievements.Filter = (AchievementView view) => view.Inner.Goal == goalId; } } } @@ -383,19 +385,18 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav { if (uint.TryParse(search, out uint achievementId)) { - Achievements.Filter = obj => ((AchievementView)obj).Inner.Id == achievementId; + Achievements.Filter = view => view.Inner.Id == achievementId; return; } if (VersionRegex().IsMatch(search)) { - Achievements.Filter = obj => ((AchievementView)obj).Inner.Version == search; + Achievements.Filter = view => view.Inner.Version == search; return; } - Achievements.Filter = obj => + Achievements.Filter = view => { - AchievementView view = (AchievementView)obj; return view.Inner.Title.Contains(search, StringComparison.CurrentCultureIgnoreCase) || view.Inner.Description.Contains(search, StringComparison.CurrentCultureIgnoreCase); }; diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/GameAccountFilter.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/GameAccountFilter.cs index d3a52c75..07269a06 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/GameAccountFilter.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/GameAccountFilter.cs @@ -15,13 +15,13 @@ internal sealed class GameAccountFilter this.type = type; } - public bool Filter(object? item) + public bool Filter(GameAccount? item) { if (type is null) { return true; } - return item is GameAccount account && account.Type == type; + return item is not null && item.Type == type; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameViewModel.cs index db6c0190..6aeb6596 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameViewModel.cs @@ -50,7 +50,7 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel, IView private readonly AppOptions appOptions; private LaunchScheme? selectedScheme; - private AdvancedCollectionView? gameAccountsView; + private AdvancedCollectionView? gameAccountsView; private GameAccount? selectedGameAccount; private GameResource? gameResource; private bool gamePathSelectedAndValid; @@ -75,7 +75,7 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel, IView set => SetSelectedSchemeAsync(value).SafeForget(); } - public AdvancedCollectionView? GameAccountsView { get => gameAccountsView; set => SetProperty(ref gameAccountsView, value); } + public AdvancedCollectionView? GameAccountsView { get => gameAccountsView; set => SetProperty(ref gameAccountsView, value); } public GameAccount? SelectedGameAccount { get => selectedGameAccount; set => SetProperty(ref selectedGameAccount, value); } @@ -130,9 +130,9 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel, IView ArgumentNullException.ThrowIfNull(GameAccountsView); // Exists in the source collection - if (GameAccountsView.SourceCollection.Cast().FirstOrDefault(g => g.AttachUid == uid) is { } sourceAccount) + if (GameAccountsView.SourceCollection.FirstOrDefault(g => g.AttachUid == uid) is { } sourceAccount) { - SelectedGameAccount = GameAccountsView.Cast().FirstOrDefault(g => g.AttachUid == uid); + SelectedGameAccount = GameAccountsView.View.FirstOrDefault(g => g.AttachUid == uid); // But not exists in the view for current scheme if (SelectedGameAccount is null) diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameViewModelSlim.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameViewModelSlim.cs index 9fbb76c9..300a77c3 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameViewModelSlim.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameViewModelSlim.cs @@ -27,13 +27,13 @@ internal sealed partial class LaunchGameViewModelSlim : Abstraction.ViewModelSli private readonly IGameServiceFacade gameService; private readonly ITaskContext taskContext; - private AdvancedCollectionView? gameAccountsView; + private AdvancedCollectionView? gameAccountsView; private GameAccount? selectedGameAccount; private GameAccountFilter? gameAccountFilter; public LaunchStatusOptions LaunchStatusOptions { get => launchStatusOptions; } - public AdvancedCollectionView? GameAccountsView { get => gameAccountsView; set => SetProperty(ref gameAccountsView, value); } + public AdvancedCollectionView? GameAccountsView { get => gameAccountsView; set => SetProperty(ref gameAccountsView, value); } /// /// 选中的账号 diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/AvatarFilter.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/AvatarFilter.cs index 5c6ac72b..2d765c25 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/AvatarFilter.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/AvatarFilter.cs @@ -17,9 +17,9 @@ internal static class AvatarFilter /// /// 输入 /// 筛选操作 - public static Predicate Compile(string input) + public static Predicate Compile(string input) { - return (object o) => o is Avatar avatar && DoFilter(input, avatar); + return (Avatar avatar) => DoFilter(input, avatar); } private static bool DoFilter(string input, Avatar avatar) diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WeaponFilter.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WeaponFilter.cs index 0e1540f9..06731581 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WeaponFilter.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WeaponFilter.cs @@ -17,9 +17,9 @@ internal static class WeaponFilter /// /// 输入 /// 筛选操作 - public static Predicate Compile(string input) + public static Predicate Compile(string input) { - return (object o) => o is Weapon weapon && DoFilter(input, weapon); + return (Weapon weapon) => DoFilter(input, weapon); } private static bool DoFilter(string input, Weapon weapon) diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiAvatarViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiAvatarViewModel.cs index e50fba5c..250197cb 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiAvatarViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiAvatarViewModel.cs @@ -43,7 +43,7 @@ internal sealed partial class WikiAvatarViewModel : Abstraction.ViewModel private readonly CalculateClient calculateClient; private readonly IUserService userService; - private AdvancedCollectionView? avatars; + private AdvancedCollectionView? avatars; private Avatar? selected; private string? filterText; private BaseValueInfo? baseValueInfo; @@ -53,7 +53,7 @@ internal sealed partial class WikiAvatarViewModel : Abstraction.ViewModel /// /// 角色列表 /// - public AdvancedCollectionView? Avatars { get => avatars; set => SetProperty(ref avatars, value); } + public AdvancedCollectionView? Avatars { get => avatars; set => SetProperty(ref avatars, value); } /// /// 选中的角色 @@ -99,8 +99,8 @@ internal sealed partial class WikiAvatarViewModel : Abstraction.ViewModel await CombineComplexDataAsync(list, idMaterialMap).ConfigureAwait(false); await taskContext.SwitchToMainThreadAsync(); - Avatars = new AdvancedCollectionView(list, true); - Selected = Avatars.Cast().FirstOrDefault(); + Avatars = new(list, true); + Selected = Avatars.View.ElementAtOrDefault(0); return true; } diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiMonsterViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiMonsterViewModel.cs index ace8bf7f..69ee0bbd 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiMonsterViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiMonsterViewModel.cs @@ -20,7 +20,7 @@ internal sealed partial class WikiMonsterViewModel : Abstraction.ViewModel private readonly IMetadataService metadataService; private readonly ITaskContext taskContext; - private AdvancedCollectionView? monsters; + private AdvancedCollectionView? monsters; private Monster? selected; private BaseValueInfo? baseValueInfo; private Dictionary>? levelMonsterCurveMap; @@ -28,7 +28,7 @@ internal sealed partial class WikiMonsterViewModel : Abstraction.ViewModel /// /// 角色列表 /// - public AdvancedCollectionView? Monsters { get => monsters; set => SetProperty(ref monsters, value); } + public AdvancedCollectionView? Monsters { get => monsters; set => SetProperty(ref monsters, value); } /// /// 选中的角色 @@ -65,8 +65,8 @@ internal sealed partial class WikiMonsterViewModel : Abstraction.ViewModel List ordered = monsters.SortBy(m => m.RelationshipId.Value); await taskContext.SwitchToMainThreadAsync(); - Monsters = new AdvancedCollectionView(ordered, true); - Selected = Monsters.Cast().FirstOrDefault(); + Monsters = new(ordered, true); + Selected = Monsters.View.ElementAtOrDefault(0); return true; } diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiWeaponViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiWeaponViewModel.cs index 85608aec..37615619 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiWeaponViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiWeaponViewModel.cs @@ -40,7 +40,7 @@ internal sealed partial class WikiWeaponViewModel : Abstraction.ViewModel private readonly IInfoBarService infoBarService; private readonly IUserService userService; - private AdvancedCollectionView? weapons; + private AdvancedCollectionView? weapons; private Weapon? selected; private string? filterText; private BaseValueInfo? baseValueInfo; @@ -50,7 +50,7 @@ internal sealed partial class WikiWeaponViewModel : Abstraction.ViewModel /// /// 角色列表 /// - public AdvancedCollectionView? Weapons { get => weapons; set => SetProperty(ref weapons, value); } + public AdvancedCollectionView? Weapons { get => weapons; set => SetProperty(ref weapons, value); } /// /// 选中的角色 @@ -96,8 +96,8 @@ internal sealed partial class WikiWeaponViewModel : Abstraction.ViewModel await taskContext.SwitchToMainThreadAsync(); - Weapons = new AdvancedCollectionView(list, true); - Selected = Weapons.Cast().FirstOrDefault(); + Weapons = new(list, true); + Selected = Weapons.View.ElementAtOrDefault(0); } }