defer content load

This commit is contained in:
Lightczx
2024-05-30 16:40:42 +08:00
parent 1e38c43727
commit f5982f81c0
11 changed files with 49 additions and 99 deletions

View File

@@ -1,44 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.WinUI.Behaviors;
using Microsoft.UI.Xaml;
using System.Runtime.InteropServices;
namespace Snap.Hutao.Control.Behavior;
[DependencyProperty("ElementNames", typeof(DeferLoadCollection))]
internal sealed partial class DeferLoadBehavior : BehaviorBase<FrameworkElement>
{
protected override bool Initialize()
{
if (ElementNames.IsNullOrEmpty())
{
return true;
}
ThreadPool.UnsafeQueueUserWorkItem(LoadElements, this);
return true;
}
private static void LoadElements(object? state)
{
if (state is not DeferLoadBehavior behavior)
{
return;
}
List<string>? elementNames = null;
behavior.AssociatedObject.DispatcherQueue.Invoke(() => elementNames = [.. behavior.ElementNames]);
foreach (string name in CollectionsMarshal.AsSpan(elementNames))
{
Thread.Sleep(1000);
behavior.AssociatedObject.DispatcherQueue.TryEnqueue(() =>
{
behavior.AssociatedObject.FindName(name);
});
}
}
}

View File

@@ -1,25 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.Extensions.Primitives;
using Windows.Foundation.Metadata;
namespace Snap.Hutao.Control.Behavior;
[CreateFromString(MethodName = "Snap.Hutao.Control.Behavior.DeferLoadCollection.Parse")]
internal sealed class DeferLoadCollection : List<string>
{
public static DeferLoadCollection Parse(string text)
{
DeferLoadCollection collection = [];
foreach (StringSegment segment in new StringTokenizer(text, [',']))
{
if (segment.HasValue)
{
collection.Add(segment.Value);
}
}
return collection;
}
}

View File

@@ -5,6 +5,7 @@ using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Navigation;
using Snap.Hutao.Service.Navigation;
using Snap.Hutao.View.Helper;
using Snap.Hutao.ViewModel.Abstraction;
namespace Snap.Hutao.Control;
@@ -48,6 +49,7 @@ internal class ScopedPage : Page
{
IViewModel viewModel = pageScope.ServiceProvider.GetRequiredService<TViewModel>();
viewModel.CancellationToken = viewCancellationTokenSource.Token;
viewModel.DeferContentLoader = new DeferContentLoader(this);
DataContext = viewModel;
}
catch (Exception ex)

View File

@@ -0,0 +1,24 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Xaml;
namespace Snap.Hutao.View.Helper;
internal sealed class DeferContentLoader : IDeferContentLoader
{
private readonly WeakReference<FrameworkElement> reference = new(default!);
public DeferContentLoader(FrameworkElement element)
{
this.reference.SetTarget(element);
}
public void Load(string name)
{
if (reference.TryGetTarget(out FrameworkElement? element))
{
element.FindName(name);
}
}
}

View File

@@ -0,0 +1,9 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.View.Helper;
internal interface IDeferContentLoader
{
void Load(string name);
}

View File

@@ -1,15 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.Extensions.Primitives;
using Windows.Foundation.Metadata;
namespace Snap.Hutao.View.Helper;
internal sealed class LoadDeferral : ObservableObject
{
private bool canLoad;
public bool CanLoad { get => canLoad; set => SetProperty(ref canLoad, value); }
}

View File

@@ -23,7 +23,6 @@
mc:Ignorable="d">
<mxi:Interaction.Behaviors>
<shcb:InvokeCommandOnLoadedBehavior Command="{Binding OpenUICommand}"/>
<shcb:DeferLoadBehavior ElementNames="TopPanel,GameAnnouncementPivot"/>
</mxi:Interaction.Behaviors>
<shc:ScopedPage.Resources>
<shc:BindingProxy x:Key="BindingProxy" DataContext="{Binding}"/>
@@ -218,9 +217,12 @@
</Border>
<ItemsControl
x:Name="HutaoAnnouncementControl"
x:Load="False"
ItemTemplate="{StaticResource HutaoAnnouncementTemplate}"
ItemsPanel="{ThemeResource StackPanelSpacing8Template}"
ItemsSource="{Binding HutaoAnnouncements}"
Transitions="{ThemeResource EntranceThemeTransitions}"
Visibility="{Binding HutaoAnnouncements.Count, Converter={StaticResource Int32ToVisibilityConverter}}"/>
<!-- ItemsRepeater will behave abnormal if no direct scrollhost wrapping it -->

View File

@@ -20,4 +20,4 @@ internal sealed partial class AnnouncementPage : ScopedPage
InitializeWith<AnnouncementViewModel>();
InitializeComponent();
}
}
}

View File

@@ -1,26 +1,18 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.View.Helper;
namespace Snap.Hutao.ViewModel.Abstraction;
/// <summary>
/// 视图模型接口
/// </summary>
[HighQuality]
internal interface IViewModel : IPageScoped
{
/// <summary>
/// 用于通知页面卸载的取消令牌
/// </summary>
CancellationToken CancellationToken { get; set; }
/// <summary>
/// 释放操作锁
/// </summary>
SemaphoreSlim DisposeLock { get; set; }
/// <summary>
/// 对应的视图是否已经释放
/// </summary>
IDeferContentLoader DeferContentLoader { get; set; }
bool IsViewDisposed { get; set; }
}

View File

@@ -3,6 +3,7 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Snap.Hutao.Core.ExceptionService;
using Snap.Hutao.View.Helper;
using System.Runtime.CompilerServices;
namespace Snap.Hutao.ViewModel.Abstraction;
@@ -22,6 +23,8 @@ internal abstract partial class ViewModel : ObservableObject, IViewModel
public SemaphoreSlim DisposeLock { get; set; } = new(1);
public IDeferContentLoader DeferContentLoader { get; set; } = default!;
public bool IsViewDisposed { get; set; }
protected TaskCompletionSource<bool> Initialization { get; } = new();

View File

@@ -67,6 +67,7 @@ internal sealed partial class AnnouncementViewModel : Abstraction.ViewModel
AnnouncementWrapper announcementWrapper = await announcementService.GetAnnouncementWrapperAsync(cultureOptions.LanguageCode, appOptions.Region, CancellationToken).ConfigureAwait(false);
await taskContext.SwitchToMainThreadAsync();
Announcement = announcementWrapper;
DeferContentLoader.Load("GameAnnouncementPivot");
}
catch (OperationCanceledException)
{
@@ -80,6 +81,7 @@ internal sealed partial class AnnouncementViewModel : Abstraction.ViewModel
ObservableCollection<Web.Hutao.HutaoAsAService.Announcement> hutaoAnnouncements = await hutaoAsAService.GetHutaoAnnouncementCollectionAsync().ConfigureAwait(false);
await taskContext.SwitchToMainThreadAsync();
HutaoAnnouncements = hutaoAnnouncements;
DeferContentLoader.Load("HutaoAnnouncementControl");
}
catch (OperationCanceledException)
{
@@ -141,4 +143,4 @@ internal sealed partial class AnnouncementViewModel : Abstraction.ViewModel
Cards = result;
}
}
}