diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Extension/FrameworkElementExtension.cs b/src/Snap.Hutao/Snap.Hutao/Control/Extension/FrameworkElementExtension.cs index 358294f7..a2ef684f 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Extension/FrameworkElementExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Extension/FrameworkElementExtension.cs @@ -28,4 +28,21 @@ internal static class FrameworkElementExtension frameworkElement.IsRightTapEnabled = false; frameworkElement.IsTabStop = false; } + + public static void InitializeDataContext(this FrameworkElement frameworkElement, IServiceProvider? serviceProvider = default) + where TDataContext : class + { + IServiceProvider service = serviceProvider ?? Ioc.Default; + try + { + frameworkElement.DataContext = service.GetRequiredService(); + } + catch (Exception ex) + { + + ILogger? logger = service.GetRequiredService(typeof(ILogger<>).MakeGenericType([frameworkElement.GetType()])) as ILogger; + logger?.LogError(ex, "Failed to initialize DataContext"); + throw; + } + } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Control/ScopedPage.cs b/src/Snap.Hutao/Snap.Hutao/Control/ScopedPage.cs index 226884c5..fab66976 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/ScopedPage.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/ScopedPage.cs @@ -15,7 +15,7 @@ internal class ScopedPage : Page { private readonly RoutedEventHandler unloadEventHandler; private readonly CancellationTokenSource viewCancellationTokenSource = new(); - private readonly IServiceScope currentScope; + private readonly IServiceScope pageScope; private bool inFrame = true; @@ -23,7 +23,7 @@ internal class ScopedPage : Page { unloadEventHandler = OnUnloaded; Unloaded += unloadEventHandler; - currentScope = Ioc.Default.GetRequiredService().CreateScope(); + pageScope = Ioc.Default.GetRequiredService().CreateScope(); } public async ValueTask NotifyRecipientAsync(INavigationData extra) @@ -44,9 +44,17 @@ internal class ScopedPage : Page protected void InitializeWith() where TViewModel : class, IViewModel { - IViewModel viewModel = currentScope.ServiceProvider.GetRequiredService(); - viewModel.CancellationToken = viewCancellationTokenSource.Token; - DataContext = viewModel; + try + { + IViewModel viewModel = pageScope.ServiceProvider.GetRequiredService(); + viewModel.CancellationToken = viewCancellationTokenSource.Token; + DataContext = viewModel; + } + catch (Exception ex) + { + pageScope.ServiceProvider.GetRequiredService>().LogError(ex, "Failed to initialize view model."); + throw; + } } /// @@ -95,7 +103,7 @@ internal class ScopedPage : Page viewModel.IsViewDisposed = true; // Dispose the scope - currentScope.Dispose(); + pageScope.Dispose(); } } } diff --git a/src/Snap.Hutao/Snap.Hutao/LaunchGameWindow.xaml.cs b/src/Snap.Hutao/Snap.Hutao/LaunchGameWindow.xaml.cs index 7143fa0e..ae9b83ff 100644 --- a/src/Snap.Hutao/Snap.Hutao/LaunchGameWindow.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/LaunchGameWindow.xaml.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using Microsoft.UI.Xaml; +using Snap.Hutao.Control.Extension; using Snap.Hutao.Core.Windowing; using Snap.Hutao.ViewModel.Game; using Snap.Hutao.Win32.UI.WindowsAndMessaging; @@ -35,7 +36,7 @@ internal sealed partial class LaunchGameWindow : Window, IDisposable, IWindowOpt scope = serviceProvider.CreateScope(); windowOptions = new(this, DragableGrid, new(MaxWidth, MaxHeight)); this.InitializeController(serviceProvider); - RootGrid.DataContext = scope.ServiceProvider.GetRequiredService(); + RootGrid.InitializeDataContext(scope.ServiceProvider); } /// diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Announcement/AnnouncementService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Announcement/AnnouncementService.cs index cfcc4cd3..b2d79bb1 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Announcement/AnnouncementService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Announcement/AnnouncementService.cs @@ -17,16 +17,15 @@ namespace Snap.Hutao.Service; /// [HighQuality] [ConstructorGenerated] -[Injection(InjectAs.Transient, typeof(IAnnouncementService))] +[Injection(InjectAs.Scoped, typeof(IAnnouncementService))] internal sealed partial class AnnouncementService : IAnnouncementService { private static readonly string CacheKey = $"{nameof(AnnouncementService)}.Cache.{nameof(AnnouncementWrapper)}"; - private readonly AnnouncementClient announcementClient; + private readonly IServiceScopeFactory serviceScopeFactory; private readonly ITaskContext taskContext; private readonly IMemoryCache memoryCache; - /// public async ValueTask GetAnnouncementWrapperAsync(string languageCode, Region region, CancellationToken cancellationToken = default) { // 缓存中存在记录,直接返回 @@ -36,29 +35,37 @@ internal sealed partial class AnnouncementService : IAnnouncementService } await taskContext.SwitchToBackgroundAsync(); - Response announcementWrapperResponse = await announcementClient - .GetAnnouncementsAsync(languageCode, region, cancellationToken) - .ConfigureAwait(false); - if (!announcementWrapperResponse.IsOk()) + List? contents; + AnnouncementWrapper wrapper; + using (IServiceScope scope = serviceScopeFactory.CreateScope()) { - return default!; + AnnouncementClient announcementClient = scope.ServiceProvider.GetRequiredService(); + + Response announcementWrapperResponse = await announcementClient + .GetAnnouncementsAsync(languageCode, region, cancellationToken) + .ConfigureAwait(false); + + if (!announcementWrapperResponse.IsOk()) + { + return default!; + } + + wrapper = announcementWrapperResponse.Data; + + Response> announcementContentResponse = await announcementClient + .GetAnnouncementContentsAsync(languageCode, region, cancellationToken) + .ConfigureAwait(false); + + if (!announcementContentResponse.IsOk()) + { + return default!; + } + + contents = announcementContentResponse.Data.List; } - AnnouncementWrapper wrapper = announcementWrapperResponse.Data; - Response> announcementContentResponse = await announcementClient - .GetAnnouncementContentsAsync(languageCode, region, cancellationToken) - .ConfigureAwait(false); - - if (!announcementContentResponse.IsOk()) - { - return default!; - } - - List contents = announcementContentResponse.Data.List; - - Dictionary contentMap = contents - .ToDictionary(id => id.AnnId, content => content.Content); + Dictionary contentMap = contents.ToDictionary(id => id.AnnId, content => content.Content); // 将活动公告置于前方 wrapper.List.Reverse(); @@ -75,8 +82,7 @@ internal sealed partial class AnnouncementService : IAnnouncementService { foreach (ref readonly WebAnnouncement item in CollectionsMarshal.AsSpan(listWrapper.List)) { - contentMap.TryGetValue(item.AnnId, out string? rawContent); - item.Content = rawContent ?? string.Empty; + item.Content = contentMap.GetValueOrDefault(item.AnnId, string.Empty); } } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/ISummaryFactory.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/ISummaryFactory.cs index 222ce266..a64b2b94 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/ISummaryFactory.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/ISummaryFactory.cs @@ -5,17 +5,8 @@ using Snap.Hutao.ViewModel.AvatarProperty; namespace Snap.Hutao.Service.AvatarInfo.Factory; -/// -/// 简述工厂 -/// [HighQuality] internal interface ISummaryFactory { - /// - /// 异步创建简述对象 - /// - /// 角色列表 - /// 取消令牌 - /// 简述对象 ValueTask CreateAsync(IEnumerable avatarInfos, CancellationToken token); } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryAvatarFactory.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryAvatarFactory.cs index c9bd0500..accfb2c2 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryAvatarFactory.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryAvatarFactory.cs @@ -17,9 +17,6 @@ using PropertyWeapon = Snap.Hutao.ViewModel.AvatarProperty.WeaponView; namespace Snap.Hutao.Service.AvatarInfo.Factory; -/// -/// 单个角色工厂 -/// [HighQuality] internal sealed class SummaryAvatarFactory { @@ -27,14 +24,9 @@ internal sealed class SummaryAvatarFactory private readonly DateTimeOffset showcaseRefreshTime; private readonly DateTimeOffset gameRecordRefreshTime; private readonly DateTimeOffset calculatorRefreshTime; - private readonly SummaryMetadataContext metadataContext; + private readonly SummaryFactoryMetadataContext metadataContext; - /// - /// 构造一个新的角色工厂 - /// - /// 元数据上下文 - /// 角色信息 - public SummaryAvatarFactory(SummaryMetadataContext metadataContext, EntityAvatarInfo avatarInfo) + public SummaryAvatarFactory(SummaryFactoryMetadataContext metadataContext, EntityAvatarInfo avatarInfo) { this.metadataContext = metadataContext; this.avatarInfo = avatarInfo.Info; diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryFactory.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryFactory.cs index afa03b4c..e4bd7462 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryFactory.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryFactory.cs @@ -20,12 +20,12 @@ internal sealed partial class SummaryFactory : ISummaryFactory /// public async ValueTask CreateAsync(IEnumerable avatarInfos, CancellationToken token) { - SummaryMetadataContext metadataContext = new() + SummaryFactoryMetadataContext metadataContext = new() { IdAvatarMap = await metadataService.GetIdToAvatarMapAsync(token).ConfigureAwait(false), IdWeaponMap = await metadataService.GetIdToWeaponMapAsync(token).ConfigureAwait(false), IdReliquaryAffixWeightMap = await metadataService.GetIdToReliquaryAffixWeightMapAsync(token).ConfigureAwait(false), - IdReliquaryMainAffixMap = await metadataService.GetIdToReliquaryMainPropertyMapAsync(token).ConfigureAwait(false), + IdReliquaryMainPropertyMap = await metadataService.GetIdToReliquaryMainPropertyMapAsync(token).ConfigureAwait(false), IdReliquarySubAffixMap = await metadataService.GetIdToReliquarySubAffixMapAsync(token).ConfigureAwait(false), ReliquaryLevels = await metadataService.GetReliquaryLevelListAsync(token).ConfigureAwait(false), Reliquaries = await metadataService.GetReliquaryListAsync(token).ConfigureAwait(false), diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryMetadataContext.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryFactoryMetadataContext.cs similarity index 63% rename from src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryMetadataContext.cs rename to src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryFactoryMetadataContext.cs index 33a3a544..c3505403 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryMetadataContext.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryFactoryMetadataContext.cs @@ -4,51 +4,32 @@ using Snap.Hutao.Model.Intrinsic; using Snap.Hutao.Model.Metadata.Reliquary; using Snap.Hutao.Model.Primitive; +using Snap.Hutao.Service.Metadata.ContextAbstraction; using MetadataAvatar = Snap.Hutao.Model.Metadata.Avatar.Avatar; using MetadataReliquary = Snap.Hutao.Model.Metadata.Reliquary.Reliquary; using MetadataWeapon = Snap.Hutao.Model.Metadata.Weapon.Weapon; namespace Snap.Hutao.Service.AvatarInfo.Factory; -/// -/// 简述元数据上下文 -/// 包含了所有制造简述需要的元数据 -/// [HighQuality] -internal sealed class SummaryMetadataContext +internal sealed class SummaryFactoryMetadataContext : IMetadataContext, + IMetadataDictionaryIdAvatarSource, + IMetadataDictionaryIdWeaponSource, + IMetadataDictionaryIdReliquaryAffixWeightSource, + IMetadataDictionaryIdReliquaryMainPropertySource, + IMetadataDictionaryIdReliquarySubAffixSource { - /// - /// 角色映射 - /// public Dictionary IdAvatarMap { get; set; } = default!; - /// - /// 武器映射 - /// public Dictionary IdWeaponMap { get; set; } = default!; - /// - /// 权重映射 - /// public Dictionary IdReliquaryAffixWeightMap { get; set; } = default!; - /// - /// 圣遗物主属性映射 - /// - public Dictionary IdReliquaryMainAffixMap { get; set; } = default!; + public Dictionary IdReliquaryMainPropertyMap { get; set; } = default!; - /// - /// 圣遗物副属性映射 - /// public Dictionary IdReliquarySubAffixMap { get; set; } = default!; - /// - /// 圣遗物等级 - /// public List ReliquaryLevels { get; set; } = default!; - /// - /// 圣遗物 - /// public List Reliquaries { get; set; } = default!; } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryReliquaryFactory.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryReliquaryFactory.cs index 90aa3565..d0d44769 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryReliquaryFactory.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryReliquaryFactory.cs @@ -19,7 +19,7 @@ namespace Snap.Hutao.Service.AvatarInfo.Factory; [HighQuality] internal sealed class SummaryReliquaryFactory { - private readonly SummaryMetadataContext metadataContext; + private readonly SummaryFactoryMetadataContext metadataContext; private readonly ModelAvatarInfo avatarInfo; private readonly Web.Enka.Model.Equip equip; @@ -29,7 +29,7 @@ internal sealed class SummaryReliquaryFactory /// 元数据上下文 /// 角色信息 /// 圣遗物 - public SummaryReliquaryFactory(SummaryMetadataContext metadataContext, ModelAvatarInfo avatarInfo, Web.Enka.Model.Equip equip) + public SummaryReliquaryFactory(SummaryFactoryMetadataContext metadataContext, ModelAvatarInfo avatarInfo, Web.Enka.Model.Equip equip) { this.metadataContext = metadataContext; this.avatarInfo = avatarInfo; @@ -70,7 +70,7 @@ internal sealed class SummaryReliquaryFactory result.ComposedSubProperties = CreateComposedSubProperties(equip.Reliquary.AppendPropIdList); ReliquaryMainAffixLevel relicLevel = metadataContext.ReliquaryLevels.Single(r => r.Level == equip.Reliquary.Level && r.Rank == reliquary.RankLevel); - FightProperty property = metadataContext.IdReliquaryMainAffixMap[equip.Reliquary.MainPropId]; + FightProperty property = metadataContext.IdReliquaryMainPropertyMap[equip.Reliquary.MainPropId]; result.MainProperty = FightPropertyFormat.ToNameValue(property, relicLevel.PropertyMap[property]); result.Score = ScoreReliquary(property, reliquary, relicLevel, subProperty); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/IMetadataDictionaryIdReliquaryAffixWeightSource.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/IMetadataDictionaryIdReliquaryAffixWeightSource.cs new file mode 100644 index 00000000..16dbdd17 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/IMetadataDictionaryIdReliquaryAffixWeightSource.cs @@ -0,0 +1,12 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Model.Metadata.Reliquary; +using Snap.Hutao.Model.Primitive; + +namespace Snap.Hutao.Service.Metadata.ContextAbstraction; + +internal interface IMetadataDictionaryIdReliquaryAffixWeightSource +{ + public Dictionary IdReliquaryAffixWeightMap { get; set; } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/IMetadataDictionaryIdReliquaryMainPropertySource.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/IMetadataDictionaryIdReliquaryMainPropertySource.cs new file mode 100644 index 00000000..9710db7e --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/IMetadataDictionaryIdReliquaryMainPropertySource.cs @@ -0,0 +1,12 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Model.Intrinsic; +using Snap.Hutao.Model.Primitive; + +namespace Snap.Hutao.Service.Metadata.ContextAbstraction; + +internal interface IMetadataDictionaryIdReliquaryMainPropertySource +{ + public Dictionary IdReliquaryMainPropertyMap { get; set; } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/IMetadataDictionaryIdReliquarySubAffixSource.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/IMetadataDictionaryIdReliquarySubAffixSource.cs new file mode 100644 index 00000000..6d12d722 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/IMetadataDictionaryIdReliquarySubAffixSource.cs @@ -0,0 +1,12 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Model.Metadata.Reliquary; +using Snap.Hutao.Model.Primitive; + +namespace Snap.Hutao.Service.Metadata.ContextAbstraction; + +internal interface IMetadataDictionaryIdReliquarySubAffixSource +{ + public Dictionary IdReliquarySubAffixMap { get; set; } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/MetadataServiceContextExtension.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/MetadataServiceContextExtension.cs index 4f1fb65e..6ddd8d78 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/MetadataServiceContextExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/MetadataServiceContextExtension.cs @@ -1,6 +1,7 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Microsoft.EntityFrameworkCore.Metadata.Internal; using Snap.Hutao.Model.Metadata.Avatar; using Snap.Hutao.Model.Metadata.Item; using Snap.Hutao.Model.Metadata.Weapon; @@ -51,6 +52,21 @@ internal static class MetadataServiceContextExtension dictionaryIdMaterialSource.IdMaterialMap = await metadataService.GetIdToMaterialMapAsync(token).ConfigureAwait(false); } + if (context is IMetadataDictionaryIdReliquaryAffixWeightSource dictionaryIdReliquaryAffixWeightSource) + { + dictionaryIdReliquaryAffixWeightSource.IdReliquaryAffixWeightMap = await metadataService.GetIdToReliquaryAffixWeightMapAsync(token).ConfigureAwait(false); + } + + if (context is IMetadataDictionaryIdReliquaryMainPropertySource dictionaryIdReliquaryMainPropertySource) + { + dictionaryIdReliquaryMainPropertySource.IdReliquaryMainPropertyMap = await metadataService.GetIdToReliquaryMainPropertyMapAsync(token).ConfigureAwait(false); + } + + if (context is IMetadataDictionaryIdReliquarySubAffixSource dictionaryIdReliquarySubAffixSource) + { + dictionaryIdReliquarySubAffixSource.IdReliquarySubAffixMap = await metadataService.GetIdToReliquarySubAffixMapAsync(token).ConfigureAwait(false); + } + if (context is IMetadataDictionaryIdWeaponSource dictionaryIdWeaponSource) { dictionaryIdWeaponSource.IdWeaponMap = await metadataService.GetIdToWeaponMapAsync(token).ConfigureAwait(false); diff --git a/src/Snap.Hutao/Snap.Hutao/View/Card/AchievementCard.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Card/AchievementCard.xaml.cs index 2cef88dc..cfdf65ee 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Card/AchievementCard.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Card/AchievementCard.xaml.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using Microsoft.UI.Xaml.Controls; +using Snap.Hutao.Control.Extension; namespace Snap.Hutao.View.Card; @@ -15,7 +16,7 @@ internal sealed partial class AchievementCard : Button /// public AchievementCard() { - DataContext = Ioc.Default.GetRequiredService(); + this.InitializeDataContext(); InitializeComponent(); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/View/Card/DailyNoteCard.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Card/DailyNoteCard.xaml.cs index 62f7311c..c73dd9f1 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Card/DailyNoteCard.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Card/DailyNoteCard.xaml.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using Microsoft.UI.Xaml.Controls; +using Snap.Hutao.Control.Extension; namespace Snap.Hutao.View.Card; @@ -15,7 +16,7 @@ internal sealed partial class DailyNoteCard : Button /// public DailyNoteCard() { - DataContext = Ioc.Default.GetRequiredService(); + this.InitializeDataContext(); InitializeComponent(); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/View/Card/GachaStatisticsCard.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Card/GachaStatisticsCard.xaml.cs index 966f9998..190fcc8c 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Card/GachaStatisticsCard.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Card/GachaStatisticsCard.xaml.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using Microsoft.UI.Xaml.Controls; +using Snap.Hutao.Control.Extension; namespace Snap.Hutao.View.Card; @@ -15,7 +16,7 @@ internal sealed partial class GachaStatisticsCard : Button /// public GachaStatisticsCard() { - DataContext = Ioc.Default.GetRequiredService(); + this.InitializeDataContext(); InitializeComponent(); } } diff --git a/src/Snap.Hutao/Snap.Hutao/View/Card/LaunchGameCard.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Card/LaunchGameCard.xaml.cs index 832d6f1f..d2fc5cc4 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Card/LaunchGameCard.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Card/LaunchGameCard.xaml.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using Microsoft.UI.Xaml.Controls; +using Snap.Hutao.Control.Extension; namespace Snap.Hutao.View.Card; @@ -15,7 +16,7 @@ internal sealed partial class LaunchGameCard : Button /// public LaunchGameCard() { - DataContext = Ioc.Default.GetRequiredService(); + this.InitializeDataContext(); InitializeComponent(); } } diff --git a/src/Snap.Hutao/Snap.Hutao/View/Guide/GuideView.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Guide/GuideView.xaml.cs index e0ccc278..0296865f 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Guide/GuideView.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Guide/GuideView.xaml.cs @@ -14,7 +14,7 @@ internal sealed partial class GuideView : UserControl { public GuideView() { + this.InitializeDataContext(); InitializeComponent(); - DataContext = this.ServiceProvider().GetRequiredService(); } } diff --git a/src/Snap.Hutao/Snap.Hutao/View/MainView.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/MainView.xaml.cs index f13fc255..a9eb72e9 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/MainView.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/MainView.xaml.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using Microsoft.UI.Xaml.Controls; +using Snap.Hutao.Control.Extension; using Snap.Hutao.Service.Navigation; using Snap.Hutao.View.Page; using Snap.Hutao.ViewModel; @@ -23,12 +24,11 @@ internal sealed partial class MainView : UserControl { IServiceProvider serviceProvider = Ioc.Default; - MainViewModel mainViewModel = serviceProvider.GetRequiredService(); + this.InitializeDataContext(serviceProvider); - DataContext = mainViewModel; InitializeComponent(); - mainViewModel.Initialize(new BackgroundImagePresenterAccessor(BackgroundImagePresenter)); + (DataContext as MainViewModel)?.Initialize(new BackgroundImagePresenterAccessor(BackgroundImagePresenter)); navigationService = serviceProvider.GetRequiredService(); if (navigationService is INavigationInitialization navigationInitialization) diff --git a/src/Snap.Hutao/Snap.Hutao/View/TitleView.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/TitleView.xaml.cs index e8c1b830..3ba335c1 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/TitleView.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/TitleView.xaml.cs @@ -3,6 +3,7 @@ using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; +using Snap.Hutao.Control.Extension; using Snap.Hutao.ViewModel; namespace Snap.Hutao.View; @@ -15,7 +16,7 @@ internal sealed partial class TitleView : UserControl { public TitleView() { - DataContext = Ioc.Default.GetRequiredService(); + this.InitializeDataContext(); InitializeComponent(); } diff --git a/src/Snap.Hutao/Snap.Hutao/View/UserView.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/UserView.xaml.cs index ad79147a..514addd7 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/UserView.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/UserView.xaml.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using Microsoft.UI.Xaml.Controls; +using Snap.Hutao.Control.Extension; using Snap.Hutao.ViewModel.User; namespace Snap.Hutao.View; @@ -17,7 +18,7 @@ internal sealed partial class UserView : UserControl /// public UserView() { + this.InitializeDataContext(); InitializeComponent(); - DataContext = Ioc.Default.GetRequiredService(); } } diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Abstraction/IPageScoped.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Abstraction/IPageScoped.cs new file mode 100644 index 00000000..a44c8321 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Abstraction/IPageScoped.cs @@ -0,0 +1,6 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.ViewModel.Abstraction; + +internal interface IPageScoped; \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Abstraction/IViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Abstraction/IViewModel.cs index 6708e673..54014fbe 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Abstraction/IViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Abstraction/IViewModel.cs @@ -7,7 +7,7 @@ namespace Snap.Hutao.ViewModel.Abstraction; /// 视图模型接口 /// [HighQuality] -internal interface IViewModel +internal interface IViewModel : IPageScoped { /// /// 用于通知页面卸载的取消令牌 diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Abstraction/ViewModelSlim.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Abstraction/ViewModelSlim.cs index 119023c8..91882189 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Abstraction/ViewModelSlim.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Abstraction/ViewModelSlim.cs @@ -7,29 +7,16 @@ using Snap.Hutao.Service.Navigation; namespace Snap.Hutao.ViewModel.Abstraction; -/// -/// 简化的视图模型抽象类 -/// [ConstructorGenerated] internal abstract partial class ViewModelSlim : ObservableObject { private readonly IServiceProvider serviceProvider; private bool isInitialized; - /// - /// 是否初始化完成 - /// public bool IsInitialized { get => isInitialized; set => SetProperty(ref isInitialized, value); } - /// - /// 服务提供器 - /// protected IServiceProvider ServiceProvider { get => serviceProvider; } - /// - /// 打开界面执行 - /// - /// 任务 [Command("OpenUICommand")] protected virtual Task OpenUIAsync() { @@ -37,18 +24,10 @@ internal abstract partial class ViewModelSlim : ObservableObject } } -/// -/// 简化的视图模型抽象类 -/// 可导航 -/// -/// 要导航到的页面类型 [ConstructorGenerated(CallBaseConstructor = true)] internal abstract partial class ViewModelSlim : ViewModelSlim where TPage : Page { - /// - /// 导航到指定的页面类型 - /// [Command("NavigateCommand")] protected virtual void Navigate() { diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Achievement/AchievementFinishPercent.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Achievement/AchievementFinishPercent.cs index 4638ba82..a590b01d 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Achievement/AchievementFinishPercent.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Achievement/AchievementFinishPercent.cs @@ -7,16 +7,9 @@ using System.Runtime.InteropServices; namespace Snap.Hutao.ViewModel.Achievement; -/// -/// 成就完成进度 -/// [HighQuality] internal static class AchievementFinishPercent { - /// - /// 更新完成进度 - /// - /// 视图模型 public static void Update(AchievementViewModel viewModel) { int totalFinished = 0;