From 6de59a7f5b7c5bde7823103b1ecda1f0627e445c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BE=99=E8=85=BE=E7=8C=AB=E8=B7=83?= <1043137532@qq.com> Date: Mon, 14 Oct 2024 03:51:13 +0800 Subject: [PATCH] Update MyImage.vb --- Plain Craft Launcher 2/Controls/MyImage.vb | 145 +++++++++++++-------- 1 file changed, 88 insertions(+), 57 deletions(-) diff --git a/Plain Craft Launcher 2/Controls/MyImage.vb b/Plain Craft Launcher 2/Controls/MyImage.vb index efe76bf..a5a7144 100644 --- a/Plain Craft Launcher 2/Controls/MyImage.vb +++ b/Plain Craft Launcher 2/Controls/MyImage.vb @@ -1,85 +1,116 @@ -Public Class MyImage +Public Class MyImage Inherits Image - Private FileCacheExpiredTime As TimeSpan = New TimeSpan(7, 0, 0, 0) ' 一个星期的缓存有效期 +#Region "辅助属性注册" ''' - ''' 是否使用缓存 + ''' 网络图片的缓存有效期。 + ''' 在这个时间后,才会重新尝试下载图片。 ''' - ''' - Public Property UseCache As Boolean + Public FileCacheExpiredTime As New TimeSpan(7, 0, 0, 0) '7 天 + + ''' + ''' 是否允许将网络图片存储到本地用作缓存。 + ''' + Public Property EnableCache As Boolean Get - Return GetValue(UseCacheProperty) + Return _EnableCache End Get Set(value As Boolean) - SetValue(UseCacheProperty, value) + _EnableCache = value End Set End Property - Public Shared ReadOnly UseCacheProperty As DependencyProperty = DependencyProperty.Register("UseCache", GetType(Boolean), GetType(MyImage), New PropertyMetadata(True)) + Private _EnableCache As Boolean = True - Private _SourceData As String = "" + '将 Source 属性映射到 XAML + Public Shared Shadows ReadOnly SourceProperty As DependencyProperty = DependencyProperty.Register( + "Source", GetType(String), GetType(MyImage), New PropertyMetadata(New PropertyChangedCallback( + Sub(sender, e) If sender IsNot Nothing Then CType(sender, MyImage).Source = e.NewValue.ToString()))) + +#End Region + + Private _Source As String = "" ''' - ''' 重写Image的Source属性 + ''' 与 Image 的 Source 类似。 + ''' 若输入以 http 开头的字符串,则会尝试下载图片然后显示,图片会保存为本地缓存。 + ''' 支持 WebP 格式的图片。 ''' - Public Shadows Property Source As String + Public Shadows Property Source As String '覆写 Image 的 Source 属性 Get - Return _SourceData + Return _Source End Get Set(value As String) - If String.IsNullOrEmpty(value) Then Exit Property - _SourceData = value + If value = "" Then value = Nothing + If _Source = value Then Exit Property + _Source = value + Dim TempPath As String = $"{PathTemp}MyImage\{GetHash(value)}.png" Try - If Not value.StartsWithF("http") Then ' 本地资源直接使用 - MyBase.Source = New MyBitmap(_SourceData) + '空 + If value Is Nothing Then + MyBase.Source = Nothing Exit Property End If - Dim NeedDownload As Boolean = True '是否需要下载/本地是否有有效缓存 - Dim TempFilePath As String = PathTemp & "Cache\MyImage\" & GetHash(_SourceData) & ".png" - If UseCache AndAlso File.Exists(TempFilePath) AndAlso (DateTime.Now - File.GetCreationTime(TempFilePath)) < FileCacheExpiredTime Then NeedDownload = False ' 缓存文件存在且未过期,不需要重下 - If Not NeedDownload Then - MyBase.Source = New MyBitmap(TempFilePath) + '本地图片 + If Not value.StartsWithF("http") Then + MyBase.Source = New MyBitmap(value) Exit Property End If - - If File.Exists(TempFilePath) Then '先显示着旧图片,下载新图片 - Rename(TempFilePath, TempFilePath & ".old") - MyBase.Source = New MyBitmap(TempFilePath & ".old") + '从缓存加载网络图片 + If EnableCache AndAlso File.Exists(TempPath) Then + MyBase.Source = New MyBitmap(TempPath) + If (Date.Now - File.GetCreationTime(TempPath)) < FileCacheExpiredTime Then + Exit Property '无需刷新缓存 + Else + File.Delete(TempPath) '需要刷新缓存 + End If + Else + MyBase.Source = Nothing '清空显示 End If - ' 开一个线程下载在线图片 - RunInNewThread(Sub() PicLoader(_SourceData, TempFilePath), "MyImage PicLoader " & GetUuid() & "#", ThreadPriority.BelowNormal) - + '下载网络图片 + RunInNewThread( + Sub() + Dim Url As String = value '重新捕获变量,以检测在下载过程中 Source 被修改的情况 + Dim Retried As Boolean = False +RetryStart: + Dim TempDownloadingPath As String = TempPath & RandomInteger(0, 10000000) + Try + Log("[MyImage] 正在下载图片:" & Url) + NetDownload(Url, TempDownloadingPath, True) + If Url <> Source Then + '若 Source 在下载时被修改,则不显示 + File.Delete(TempDownloadingPath) + ElseIf EnableCache Then + '保存缓存并显示 + Rename(TempDownloadingPath, TempPath) + RunInUi(Sub() MyBase.Source = New MyBitmap(TempPath)) + Else + '直接显示 + RunInUiWait(Sub() MyBase.Source = New MyBitmap(TempDownloadingPath)) + File.Delete(TempDownloadingPath) + End If + Catch ex As Exception + Try + File.Delete(TempDownloadingPath) + Catch + End Try + If Not Retried Then + Log(ex, $"下载图片可重试地失败({Url})", LogLevel.Developer) + Retried = True + Thread.Sleep(1000) + GoTo RetryStart + Else + Log(ex, $"下载图片失败({Url})", LogLevel.Hint) + End If + End Try + End Sub, "MyImage PicLoader " & GetUuid() & "#", ThreadPriority.BelowNormal) Catch ex As Exception - Log(ex, "加载图片失败") + Log(ex, $"加载图片失败({value})", LogLevel.Hint) + Try + File.Delete(TempPath) '删除缓存,以免缓存出现问题导致一直加载失败 + Catch + End Try End Try End Set End Property - Public Shared Shadows ReadOnly SourceProperty As DependencyProperty = DependencyProperty.Register("Source", GetType(String), GetType(MyImage), New PropertyMetadata(New PropertyChangedCallback( - Sub(sender As DependencyObject, e As DependencyPropertyChangedEventArgs) - If Not IsNothing(sender) Then - If String.IsNullOrEmpty(e.NewValue.ToString()) Then Exit Sub - CType(sender, MyImage).Source = e.NewValue.ToString() - End If - End Sub))) - - Private Sub PicLoader(FileUrl As String, TempFilePath As String) - Dim Retried As Boolean = False -RetryStart: - Try - Dim UnCompleteFile As String = TempFilePath & ".dl" '加一个下载中的后缀,防止中途关闭程序下载中断但是没下完,从而导致第二次显示的是损坏的图片…… - NetDownload(FileUrl, UnCompleteFile) - Rename(UnCompleteFile, TempFilePath) - RunInUi(Sub() - MyBase.Source = New MyBitmap(TempFilePath) - End Sub) - File.Delete(TempFilePath & ".old") - Catch ex As Exception - If Not Retried Then - Retried = True - GoTo RetryStart - Else - Log(ex, $"[MyImage] 下载图片失败") - End If - End Try - End Sub End Class