diff --git a/src/Snap.Hutao/Snap.Hutao/Control/ScopedPage.cs b/src/Snap.Hutao/Snap.Hutao/Control/ScopedPage.cs
index 06db70e8..d3eac6c9 100644
--- a/src/Snap.Hutao/Snap.Hutao/Control/ScopedPage.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Control/ScopedPage.cs
@@ -41,12 +41,14 @@ internal class ScopedPage : Page
/// 应当在 InitializeComponent() 前调用
///
/// 视图模型类型
- protected void InitializeWith()
+ protected TViewModel InitializeWith()
where TViewModel : class, IViewModel
{
IViewModel viewModel = currentScope.ServiceProvider.GetRequiredService();
viewModel.CancellationToken = viewCancellationTokenSource.Token;
DataContext = viewModel;
+
+ return (TViewModel)viewModel;
}
///
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/WikiAvatarPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/WikiAvatarPage.xaml
index 1bcfbd91..8be405da 100644
--- a/src/Snap.Hutao/Snap.Hutao/View/Page/WikiAvatarPage.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/View/Page/WikiAvatarPage.xaml
@@ -73,6 +73,13 @@
+
+
+
+
@@ -266,21 +273,17 @@
-
-
-
-
-
-
+ Text="{Binding FilterText, Mode=TwoWay}"/>
public WikiAvatarPage()
{
- InitializeWith();
+ WikiAvatarViewModel viewModel = InitializeWith();
InitializeComponent();
+
+ viewModel.Initialize(new AutoSuggestBoxAccessor(AvatarSuggestBox));
+ }
+
+ private class AutoSuggestBoxAccessor : IAutoSuggestBoxAccessor
+ {
+ public AutoSuggestBoxAccessor(AutoSuggestBox autoSuggestBox)
+ {
+ AutoSuggestBox = autoSuggestBox;
+ }
+
+ public AutoSuggestBox AutoSuggestBox { get; private set; }
}
}
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/WikiWeaponPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/WikiWeaponPage.xaml
index cef3bfa2..5358afed 100644
--- a/src/Snap.Hutao/Snap.Hutao/View/Page/WikiWeaponPage.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/View/Page/WikiWeaponPage.xaml
@@ -32,6 +32,13 @@
Source="{Binding Converter={StaticResource PropertyDescriptor}}"/>
+
+
+
+
@@ -132,20 +139,16 @@
-
-
-
-
-
-
+ Text="{Binding FilterText, Mode=TwoWay}"/>
public WikiWeaponPage()
{
- InitializeWith();
+ WikiWeaponViewModel viewModel = InitializeWith();
InitializeComponent();
+
+ viewModel.Initialize(new AutoSuggestBoxAccessor(WeaponSuggestBox));
+ }
+
+ private class AutoSuggestBoxAccessor : IAutoSuggestBoxAccessor
+ {
+ public AutoSuggestBoxAccessor(AutoSuggestBox autoSuggestBox)
+ {
+ AutoSuggestBox = autoSuggestBox;
+ }
+
+ public AutoSuggestBox AutoSuggestBox { get; private set; }
}
}
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/IAutoSuggestBoxAccessor.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/IAutoSuggestBoxAccessor.cs
new file mode 100644
index 00000000..2f5233ca
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/IAutoSuggestBoxAccessor.cs
@@ -0,0 +1,12 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+using Microsoft.UI.Xaml.Controls;
+using Snap.Hutao.Control;
+
+namespace Snap.Hutao.ViewModel.Wiki;
+
+internal interface IAutoSuggestBoxAccessor : IXamlElementAccessor
+{
+ AutoSuggestBox AutoSuggestBox { get; }
+}
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/IWikiViewModelInitialization.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/IWikiViewModelInitialization.cs
new file mode 100644
index 00000000..45335020
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/IWikiViewModelInitialization.cs
@@ -0,0 +1,9 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+namespace Snap.Hutao.ViewModel.Wiki;
+
+internal interface IWikiViewModelInitialization
+{
+ void Initialize(IAutoSuggestBoxAccessor accessor);
+}
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiAvatarViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiAvatarViewModel.cs
index 250197cb..2c2283cc 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiAvatarViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiAvatarViewModel.cs
@@ -1,11 +1,13 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
+using Microsoft.UI.Xaml.Controls;
using Snap.Hutao.Control.Collection.AdvancedCollectionView;
using Snap.Hutao.Factory.ContentDialog;
using Snap.Hutao.Model.Calculable;
using Snap.Hutao.Model.Entity.Primitive;
using Snap.Hutao.Model.Intrinsic;
+using Snap.Hutao.Model.Intrinsic.Frozen;
using Snap.Hutao.Model.Metadata;
using Snap.Hutao.Model.Metadata.Avatar;
using Snap.Hutao.Model.Metadata.Item;
@@ -17,6 +19,7 @@ using Snap.Hutao.Service.Notification;
using Snap.Hutao.Service.User;
using Snap.Hutao.View.Dialog;
using Snap.Hutao.Web.Response;
+using System.Collections.Frozen;
using System.Runtime.InteropServices;
using CalculateAvatarPromotionDelta = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.AvatarPromotionDelta;
using CalculateClient = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.CalculateClient;
@@ -32,7 +35,7 @@ namespace Snap.Hutao.ViewModel.Wiki;
[HighQuality]
[ConstructorGenerated]
[Injection(InjectAs.Scoped)]
-internal sealed partial class WikiAvatarViewModel : Abstraction.ViewModel
+internal sealed partial class WikiAvatarViewModel : Abstraction.ViewModel, IWikiViewModelInitialization
{
private readonly IContentDialogFactory contentDialogFactory;
private readonly ICultivationService cultivationService;
@@ -49,6 +52,7 @@ internal sealed partial class WikiAvatarViewModel : Abstraction.ViewModel
private BaseValueInfo? baseValueInfo;
private Dictionary>? levelAvatarCurveMap;
private List? promotes;
+ private FrozenSet availableQueries;
///
/// 角色列表
@@ -79,6 +83,13 @@ internal sealed partial class WikiAvatarViewModel : Abstraction.ViewModel
///
public string? FilterText { get => filterText; set => SetProperty(ref filterText, value); }
+ public void Initialize(IAutoSuggestBoxAccessor accessor)
+ {
+ accessor.AutoSuggestBox.TextChanged += OnFilterSuggestionRequested;
+ accessor.AutoSuggestBox.SuggestionChosen += OnFilterSuggestionChosen;
+ accessor.AutoSuggestBox.QuerySubmitted += ApplyFilter;
+ }
+
protected override async ValueTask InitializeUIAsync()
{
if (!await metadataService.InitializeAsync().ConfigureAwait(false))
@@ -101,6 +112,17 @@ internal sealed partial class WikiAvatarViewModel : Abstraction.ViewModel
await taskContext.SwitchToMainThreadAsync();
Avatars = new(list, true);
Selected = Avatars.View.ElementAtOrDefault(0);
+
+ availableQueries = FrozenSet.ToFrozenSet(
+ [
+ .. avatars.Select(a => a.Name),
+ .. IntrinsicFrozen.AssociationTypes,
+ .. IntrinsicFrozen.BodyTypes,
+ .. IntrinsicFrozen.ElementNames,
+ .. IntrinsicFrozen.ItemQualities,
+ .. IntrinsicFrozen.WeaponTypes,
+ ]);
+
return true;
}
@@ -202,21 +224,43 @@ internal sealed partial class WikiAvatarViewModel : Abstraction.ViewModel
BaseValueInfo = new(avatar.MaxLevel, propertyCurveValues, levelAvatarCurveMap, avatarPromoteMap);
}
- [Command("FilterCommand")]
- private void ApplyFilter(string? input)
+ private void OnFilterSuggestionRequested(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
{
if (Avatars is null)
{
return;
}
- if (string.IsNullOrWhiteSpace(input))
+ if (string.IsNullOrWhiteSpace(FilterText))
+ {
+ return;
+ }
+
+ if (args.Reason == AutoSuggestionBoxTextChangeReason.UserInput)
+ {
+ sender.ItemsSource = availableQueries.Where(q => q.Contains(FilterText, StringComparison.OrdinalIgnoreCase));
+ }
+ }
+
+ private void OnFilterSuggestionChosen(AutoSuggestBox sender, AutoSuggestBoxSuggestionChosenEventArgs args)
+ {
+ sender.Text = args.SelectedItem.ToString();
+ }
+
+ private void ApplyFilter(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
+ {
+ if (Avatars is null)
+ {
+ return;
+ }
+
+ if (string.IsNullOrWhiteSpace(FilterText))
{
Avatars.Filter = default!;
return;
}
- Avatars.Filter = AvatarFilter.Compile(input);
+ Avatars.Filter = AvatarFilter.Compile(FilterText);
if (Selected is not null && Avatars.Contains(Selected))
{
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiWeaponViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiWeaponViewModel.cs
index 37615619..2cc99cbb 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiWeaponViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiWeaponViewModel.cs
@@ -1,11 +1,13 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
+using Microsoft.UI.Xaml.Controls;
using Snap.Hutao.Control.Collection.AdvancedCollectionView;
using Snap.Hutao.Factory.ContentDialog;
using Snap.Hutao.Model.Calculable;
using Snap.Hutao.Model.Entity.Primitive;
using Snap.Hutao.Model.Intrinsic;
+using Snap.Hutao.Model.Intrinsic.Frozen;
using Snap.Hutao.Model.Metadata;
using Snap.Hutao.Model.Metadata.Item;
using Snap.Hutao.Model.Metadata.Weapon;
@@ -17,6 +19,7 @@ using Snap.Hutao.Service.Notification;
using Snap.Hutao.Service.User;
using Snap.Hutao.View.Dialog;
using Snap.Hutao.Web.Response;
+using System.Collections.Frozen;
using System.Runtime.InteropServices;
using CalculateAvatarPromotionDelta = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.AvatarPromotionDelta;
using CalculateClient = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.CalculateClient;
@@ -29,7 +32,7 @@ namespace Snap.Hutao.ViewModel.Wiki;
///
[ConstructorGenerated]
[Injection(InjectAs.Scoped)]
-internal sealed partial class WikiWeaponViewModel : Abstraction.ViewModel
+internal sealed partial class WikiWeaponViewModel : Abstraction.ViewModel, IWikiViewModelInitialization
{
private readonly IContentDialogFactory contentDialogFactory;
private readonly CalculateClient calculateClient;
@@ -46,6 +49,7 @@ internal sealed partial class WikiWeaponViewModel : Abstraction.ViewModel
private BaseValueInfo? baseValueInfo;
private Dictionary>? levelWeaponCurveMap;
private List? promotes;
+ private FrozenSet availableQueries;
///
/// 角色列表
@@ -76,6 +80,13 @@ internal sealed partial class WikiWeaponViewModel : Abstraction.ViewModel
///
public string? FilterText { get => filterText; set => SetProperty(ref filterText, value); }
+ public void Initialize(IAutoSuggestBoxAccessor accessor)
+ {
+ accessor.AutoSuggestBox.TextChanged += OnFilterSuggestionRequested;
+ accessor.AutoSuggestBox.SuggestionChosen += OnFilterSuggestionChosen;
+ accessor.AutoSuggestBox.QuerySubmitted += ApplyFilter;
+ }
+
///
protected override async Task OpenUIAsync()
{
@@ -98,6 +109,14 @@ internal sealed partial class WikiWeaponViewModel : Abstraction.ViewModel
Weapons = new(list, true);
Selected = Weapons.View.ElementAtOrDefault(0);
+
+ availableQueries = FrozenSet.ToFrozenSet(
+ [
+ .. weapons.Select(w => w.Name),
+ .. IntrinsicFrozen.ItemQualities,
+ .. IntrinsicFrozen.FightProperties,
+ .. IntrinsicFrozen.WeaponTypes,
+ ]);
}
}
@@ -187,21 +206,43 @@ internal sealed partial class WikiWeaponViewModel : Abstraction.ViewModel
BaseValueInfo = new(weapon.MaxLevel, propertyCurveValues, levelWeaponCurveMap, weaponPromoteMap);
}
- [Command("FilterCommand")]
- private void ApplyFilter(string? input)
+ private void OnFilterSuggestionRequested(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
{
if (Weapons is null)
{
return;
}
- if (string.IsNullOrWhiteSpace(input))
+ if (string.IsNullOrWhiteSpace(FilterText))
+ {
+ return;
+ }
+
+ if (args.Reason == AutoSuggestionBoxTextChangeReason.UserInput)
+ {
+ sender.ItemsSource = availableQueries.Where(q => q.Contains(FilterText, StringComparison.OrdinalIgnoreCase));
+ }
+ }
+
+ private void OnFilterSuggestionChosen(AutoSuggestBox sender, AutoSuggestBoxSuggestionChosenEventArgs args)
+ {
+ sender.Text = args.SelectedItem.ToString();
+ }
+
+ private void ApplyFilter(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
+ {
+ if (Weapons is null)
+ {
+ return;
+ }
+
+ if (string.IsNullOrWhiteSpace(FilterText))
{
Weapons.Filter = default!;
return;
}
- Weapons.Filter = WeaponFilter.Compile(input);
+ Weapons.Filter = WeaponFilter.Compile(FilterText);
if (Selected is not null && Weapons.Contains(Selected))
{