diff --git a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/Control/Image/CompositionImage.cs b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/Control/Image/CompositionImage.cs
index 6dda8189..5ac652f5 100644
--- a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/Control/Image/CompositionImage.cs
+++ b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/Control/Image/CompositionImage.cs
@@ -10,6 +10,7 @@ using Snap.Hutao.Core.Caching;
using Snap.Hutao.Core.Graphics;
using Snap.Hutao.Service.Notification;
using Snap.Hutao.UI.Xaml.Media.Animation;
+using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Runtime.InteropServices;
@@ -17,11 +18,6 @@ using Windows.Foundation;
namespace Snap.Hutao.UI.Xaml.Control.Image;
-///
-/// 合成图像控件
-/// 为其他图像类控件提供基类
-///
-[HighQuality]
[DependencyProperty("EnableShowHideAnimation", typeof(bool), true)]
[DependencyProperty("Source", typeof(Uri), default!, nameof(OnSourceChanged))]
internal abstract partial class CompositionImage : Microsoft.UI.Xaml.Controls.Control
@@ -30,48 +26,38 @@ internal abstract partial class CompositionImage : Microsoft.UI.Xaml.Controls.Co
private readonly IServiceProvider serviceProvider;
- private readonly SizeChangedEventHandler sizeChangedEventHandler;
- private readonly TypedEventHandler loadedImageSourceLoadCompletedEventHandler;
-
private TaskCompletionSource? surfaceLoadTaskCompletionSource;
private SpriteVisual? spriteVisual;
private bool isShow = true;
- ///
- /// 构造一个新的单色图像
- ///
protected CompositionImage()
{
serviceProvider = this.ServiceProvider();
this.DisableInteraction();
- sizeChangedEventHandler = OnSizeChanged;
- SizeChanged += sizeChangedEventHandler;
-
- loadedImageSourceLoadCompletedEventHandler = OnLoadImageSurfaceLoadCompleted;
+ SizeChanged += OnSizeChanged;
}
- ///
- /// 合成组合视觉
- ///
- /// 合成器
- /// 图像表面
- /// 拼合视觉
protected abstract SpriteVisual CompositeSpriteVisual(Compositor compositor, LoadedImageSurface imageSurface);
protected virtual void LoadImageSurfaceCompleted(LoadedImageSurface surface)
{
}
- ///
- /// 更新视觉对象
- ///
- /// 拼合视觉
protected virtual void UpdateVisual(SpriteVisual spriteVisual)
{
spriteVisual.Size = ActualSize;
}
+ protected override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+ if (!string.IsNullOrEmpty(Source.OriginalString))
+ {
+ OnSourceChangedCore(Source);
+ }
+ }
+
private static void OnSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs arg)
{
CompositionImage image = (CompositionImage)sender;
@@ -87,9 +73,7 @@ internal abstract partial class CompositionImage : Microsoft.UI.Xaml.Controls.Co
// value is different from old one
if (inner != (arg.OldValue as Uri))
{
- image
- .ApplyImageAsync(inner, token)
- .SafeForget(logger, ex => OnApplyImageFailed(serviceProvider, inner, ex));
+ image.OnSourceChangedCore(inner);
}
}
else
@@ -101,6 +85,7 @@ internal abstract partial class CompositionImage : Microsoft.UI.Xaml.Controls.Co
private static void OnApplyImageFailed(IServiceProvider serviceProvider, Uri? uri, Exception exception)
{
+ Debugger.Break();
IInfoBarService infoBarService = serviceProvider.GetRequiredService();
if (exception is HttpRequestException httpRequestException)
@@ -117,6 +102,13 @@ internal abstract partial class CompositionImage : Microsoft.UI.Xaml.Controls.Co
}
}
+ private void OnSourceChangedCore(Uri? uri)
+ {
+ CancellationToken token = loadingTokenSource.Register();
+ ILogger logger = serviceProvider.GetRequiredService>();
+ ApplyImageAsync(uri, token).SafeForget(logger, ex => OnApplyImageFailed(serviceProvider, uri, ex));
+ }
+
private async ValueTask ApplyImageAsync(Uri? uri, CancellationToken token)
{
await HideAsync(token).ConfigureAwait(true);
@@ -154,21 +146,28 @@ internal abstract partial class CompositionImage : Microsoft.UI.Xaml.Controls.Co
await ShowAsync(token).ConfigureAwait(true);
}
}
+ else
+ {
+ Debugger.Break();
+ }
}
}
private async ValueTask LoadImageSurfaceAsync(string file, CancellationToken token)
{
+ token.ThrowIfCancellationRequested();
+ TaskCompletionSource cancelTcs = new();
+ CancellationTokenRegistration registration = token.Register(() => cancelTcs.TrySetResult(), false);
+
surfaceLoadTaskCompletionSource = new();
LoadedImageSurface? surface = default;
try
{
surface = LoadedImageSurface.StartLoadFromUri(file.ToUri());
- surface.LoadCompleted += loadedImageSourceLoadCompletedEventHandler;
+ surface.LoadCompleted += OnLoadImageSurfaceLoadCompleted;
if (surface.DecodedPhysicalSize.Size() <= 0D)
{
- await Task.WhenAny(surfaceLoadTaskCompletionSource.Task, Task.Delay(5000, token)).ConfigureAwait(true);
- await Task.Delay(50, token).ConfigureAwait(true);
+ await Task.WhenAny(surfaceLoadTaskCompletionSource.Task, cancelTcs.Task).ConfigureAwait(true);
}
LoadImageSurfaceCompleted(surface);
@@ -178,8 +177,10 @@ internal abstract partial class CompositionImage : Microsoft.UI.Xaml.Controls.Co
{
if (surface is not null)
{
- surface.LoadCompleted -= loadedImageSourceLoadCompletedEventHandler;
+ surface.LoadCompleted -= OnLoadImageSurfaceLoadCompleted;
}
+
+ registration.Dispose();
}
}
diff --git a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/Control/Image/MonoChrome.cs b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/Control/Image/MonoChrome.cs
index 0c016816..747efbb4 100644
--- a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/Control/Image/MonoChrome.cs
+++ b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/Control/Image/MonoChrome.cs
@@ -12,26 +12,15 @@ using Windows.Foundation;
namespace Snap.Hutao.UI.Xaml.Control.Image;
-///
-/// 支持单色的图像
-///
-[HighQuality]
internal sealed class MonoChrome : CompositionImage
{
- private readonly TypedEventHandler actualThemeChangedEventHandler;
-
private CompositionColorBrush? backgroundBrush;
- ///
- /// 构造一个新的单色图像
- ///
public MonoChrome()
{
- actualThemeChangedEventHandler = OnActualThemeChanged;
- ActualThemeChanged += actualThemeChangedEventHandler;
+ ActualThemeChanged += OnActualThemeChanged;
}
- ///
protected override SpriteVisual CompositeSpriteVisual(Compositor compositor, LoadedImageSurface imageSurface)
{
CompositionColorBrush blackLayerBrush = compositor.CreateColorBrush(Colors.Black);
diff --git a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/Control/Layout/UniformStaggeredLayout.cs b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/Control/Layout/UniformStaggeredLayout.cs
index db8bc6ab..cf505acb 100644
--- a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/Control/Layout/UniformStaggeredLayout.cs
+++ b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/Control/Layout/UniformStaggeredLayout.cs
@@ -188,6 +188,7 @@ internal sealed partial class UniformStaggeredLayout : VirtualizingLayout
}
UniformStaggeredLayoutState state = (UniformStaggeredLayoutState)context.LayoutState;
+ int virtualColumnCount = (int)(finalSize.Width / state.ColumnWidth);
// Cycle through each column and arrange the items that are within the realization bounds
for (int columnIndex = 0; columnIndex < state.NumberOfColumns; columnIndex++)
@@ -204,9 +205,9 @@ internal sealed partial class UniformStaggeredLayout : VirtualizingLayout
// Partial or fully in the view
if (item.Top <= context.RealizationRect.Bottom)
{
- double itemHorizontalOffset = (state.ColumnWidth * columnIndex) + (MinColumnSpacing * columnIndex);
+ double itemHorizontalOffset = (state.ColumnWidth + MinColumnSpacing) * columnIndex;
- double width = columnIndex == state.NumberOfColumns - 1
+ double width = columnIndex == virtualColumnCount - 1
? finalSize.Width - itemHorizontalOffset
: state.ColumnWidth;
diff --git a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/Control/SizeRestrictedContentControl.cs b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/Control/SizeRestrictedContentControl.cs
index f9ca831d..ec9dd5a2 100644
--- a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/Control/SizeRestrictedContentControl.cs
+++ b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/Control/SizeRestrictedContentControl.cs
@@ -20,9 +20,20 @@ internal sealed partial class SizeRestrictedContentControl : ContentControl
{
element.Measure(availableSize);
Size contentDesiredSize = element.DesiredSize;
+
Size contentActualOrDesiredSize = new(
- Math.Min(Math.Max(element.ActualWidth, contentDesiredSize.Width), availableSize.Width),
- Math.Min(Math.Max(element.ActualHeight, contentDesiredSize.Height), availableSize.Height));
+ Math.Clamp(element.ActualWidth, contentDesiredSize.Width, availableSize.Width),
+ Math.Clamp(element.ActualHeight, contentDesiredSize.Height, availableSize.Height));
+
+ if (minContentWidth > availableSize.Width)
+ {
+ minContentWidth = 0;
+ }
+
+ if (minContentHeight > availableSize.Height)
+ {
+ minContentHeight = 0;
+ }
if (IsWidthRestricted)
{
diff --git a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Page/AnnouncementPage.xaml b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Page/AnnouncementPage.xaml
index 95fbb711..60c18100 100644
--- a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Page/AnnouncementPage.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Page/AnnouncementPage.xaml
@@ -154,7 +154,7 @@
ItemsSource="{Binding List}">
-
+
@@ -547,7 +550,7 @@
ItemsSource="{Binding DailyNoteEntries}">
-
+
+
+
+
@@ -524,19 +527,21 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Page/WikiWeaponPage.xaml b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Page/WikiWeaponPage.xaml
index 78e85aec..5d4a3fd3 100644
--- a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Page/WikiWeaponPage.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Page/WikiWeaponPage.xaml
@@ -91,7 +91,7 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+ HorizontalAlignment="Center"
+ VerticalAlignment="Stretch"
+ Source="{Binding Selected.Icon, Converter={StaticResource GachaEquipIconConverter}}"/>
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Bbs/User/UserInfo.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Bbs/User/UserInfo.cs
index 0f5d43a8..340ff1fc 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Bbs/User/UserInfo.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Bbs/User/UserInfo.cs
@@ -104,9 +104,10 @@ internal sealed class UserInfo
{
get
{
- string source = AvatarUrl.OriginalString;
+ string? source = AvatarUrl?.OriginalString;
if (!string.IsNullOrEmpty(source))
{
+ ArgumentNullException.ThrowIfNull(AvatarUrl);
return AvatarUrl;
}