| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- Public Class MyImage
- Inherits Image
- #Region "公开属性"
- ''' <summary>
- ''' 网络图片的缓存有效期。
- ''' 在这个时间后,才会重新尝试下载图片。
- ''' </summary>
- Public FileCacheExpiredTime As New TimeSpan(7, 0, 0, 0) '7 天
- ''' <summary>
- ''' 是否允许将网络图片存储到本地用作缓存。
- ''' </summary>
- Public Property EnableCache As Boolean
- Get
- Return GetValue(EnableCacheProperty)
- End Get
- Set(value As Boolean)
- SetValue(EnableCacheProperty, value)
- End Set
- End Property
- Public Shared Shadows ReadOnly EnableCacheProperty As DependencyProperty = DependencyProperty.Register(
- "EnableCache", GetType(Boolean), GetType(MyImage), New PropertyMetadata(True))
- ''' <summary>
- ''' 与 Image 的 Source 类似。
- ''' 若输入以 http 开头的字符串,则会尝试下载图片然后显示;若 EnableCache 设为 True,图片还会保存为本地缓存。
- ''' 支持 WebP 格式的图片。
- ''' </summary>
- Public Shadows Property Source As String '覆写 Image 的 Source 属性
- Get
- Return _Source
- End Get
- Set(value As String)
- If value = "" Then value = Nothing
- If _Source = value Then Return
- _Source = value
- If Not IsInitialized Then Return '属性读取顺序修正:在完成 XAML 属性读取后再触发图片加载(#4868)
- Load()
- End Set
- End Property
- Private _Source As String = ""
- 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())))
- ''' <summary>
- ''' 若 Source 是一个网络图片,该地址将作为第二图片源。
- ''' </summary>
- Public Property FallbackSource As String
- Get
- Return _FallbackSource
- End Get
- Set(value As String)
- _FallbackSource = value
- End Set
- End Property
- Private _FallbackSource As String = Nothing
- ''' <summary>
- ''' 正在下载网络图片时显示的本地图片。
- ''' </summary>
- Public Property LoadingSource As String
- Get
- Return _LoadingSource
- End Get
- Set(value As String)
- _LoadingSource = value
- End Set
- End Property
- Private _LoadingSource As String = "pack://application:,,,/images/Icons/NoIcon.png"
- #End Region
- ''' <summary>
- ''' 实际被呈现的图片地址。
- ''' </summary>
- Public Property ActualSource As String
- Get
- Return _ActualSource
- End Get
- Set(value As String)
- If value = "" Then value = Nothing
- If _ActualSource = value Then Return
- _ActualSource = value
- Try
- Dim Bitmap As ImageSource = If(value Is Nothing, Nothing, New MyBitmap(value)) '在这里先触发可能的文件读取,尽量避免在 UI 线程中读取文件
- RunInUi(Sub() MyBase.Source = Bitmap)
- Catch ex As Exception
- Logger.Warn(ex, $"加载图片失败({value})")
- Try
- If value.StartsWithF(PathTemp) Then FileUtils.Delete(value)
- Catch
- End Try
- End Try
- End Set
- End Property
- Private _ActualSource As String = Nothing
- Private Sub Load() _
- Handles Me.Initialized '属性读取顺序修正:在完成 XAML 属性读取后再触发图片加载(#4868)
- '空
- If Source Is Nothing Then
- ActualSource = Nothing
- Return
- End If
- '本地图片
- If Not Source.StartsWithF("http") Then
- ActualSource = Source
- Return
- End If
- '从缓存加载网络图片
- Dim EnableCache As Boolean = Me.EnableCache
- Dim TempPath As String = $"{PathTemp}MyImage\{GetHash(Source)}.png{If(EnableCache, "", GetUuid())}" '不启用缓存时在末尾加上随机字符串,避免冲突
- Dim TempFile = FileUtils.GetInfo(TempPath)
- If EnableCache AndAlso TempFile.Exists Then
- ActualSource = TempPath '显示缓存的图片
- If (Date.Now - TempFile.LastWriteTime) < FileCacheExpiredTime Then Return '无需刷新缓存
- Else
- ActualSource = LoadingSource '显示加载中图片
- End If
- RunInNewThread(
- Sub()
- Dim IsLocalFallback As Boolean = Not String.IsNullOrEmpty(FallbackSource) AndAlso Not FallbackSource.StartsWithF("http")
- Try
- '下载
- NetDownloadByLoader(
- If(FallbackSource IsNot Nothing AndAlso FallbackSource.StartsWithF("http") AndAlso Source <> FallbackSource,
- {Source, FallbackSource}, {Source}),
- TempPath, SimulateBrowserHeaders:=True)
- ActualSource = TempPath
- If Not EnableCache Then FileUtils.Delete(TempPath)
- Catch ex As Exception
- Try
- If TempPath IsNot Nothing Then FileUtils.Delete(TempPath)
- Catch
- End Try
- '加载本地备用图片
- If IsLocalFallback Then
- Try
- ActualSource = FallbackSource
- Logger.Warn(ex, $"下载图片失败,使用本地备用图片({Source})")
- Return
- Catch exx As Exception
- Logger.Error(ex, $"下载图片失败({Source})", LogBehavior.Toast)
- Logger.Error(exx, $"加载备用图片失败({FallbackSource})", LogBehavior.Toast)
- End Try
- Else
- Logger.Error(ex, $"下载图片失败({Source},备用:{FallbackSource})", LogBehavior.Toast)
- End If
- End Try
- End Sub, "MyImage PicLoader " & GetUuid() & "#", ThreadPriority.BelowNormal)
- End Sub
- End Class
|