在对 Source 属性进行绑定的时候

时间:2022-01-18 03:22:03

标签:

原文:【WPF】【UWP】借鉴 asp.net core 管道措置惩罚惩罚模型打造图片缓存控件 ImageEx

在 Web 开发中,img 标签用来泛起图片,而且一般来说,浏览器是会对这些图片进行缓存的。

在对 Source 属性进行绑定的时候

好比访谒百度,我们可以发明,图片、脚本这种都是从缓存(内存缓存/磁盘缓存)中加载的,而不是再去访谒一次百度的处事器,这样一方面改进了响应速度,另一方面也减轻了处事真个压力。

但是,对付 WPF 和 UWP 开发来说,原生的 Image 控件是只有内存缓存的,并没有磁盘缓存的,所以一旦措施退出了,下次再从头启动措施的话,那还是得从处事器上面取图片的。因此,打造一个具备缓存(尤其是磁盘缓存)的 Image 控件还是有须要的。

在 WPF 和 UWP 中,我们都知道 Image 控件 Source 属性的类型是 ImageSource,但是,如果我们使用数据绑定的话,是可以绑定一个字符串的,在运行的时候,我们会发明 Source 属性酿成了一个 BitmapImage 类型的东西。那么可以推论出,是框架给我们做了一些转换。颠末查阅 WPF 的相关资料,发明是 ImageSource 这个类型上有一个 TypeConverterAttribute:

在对 Source 属性进行绑定的时候

检察 ImageSourceConverter 的源码(),我们可以看到这么一段

在对 Source 属性进行绑定的时候

因此,在对 Source 属性进行绑定的时候,我们的数据源是可以使用:string、Stream、Uri、byte[] 这些类型的,固然还有它自身 ImageSource(BitmapImage 是 ImageSource 的子类)。

虽然有 5 种这么多,然而最终我们需要的是 ImageSource。此外 Uri 就相当于 string 的转换。再仔细分析的话,我们概略可以得出下面的结论:

string –> Uri –> byte[] –> Stream –> ImageSource

此中 Uri 到 byte[] 就是相当于从 Uri 对应的处所加载图片数据,常见的就是 web、磁盘和措施内嵌资源。

在某些节点我们是可以加上缓存的,如碰到一个 http/https 的地点,,那可以先查抄本地是否有缓存文件,有就直接加载不去访谒处事器了。

颠末整理,根基可以得出如下的流程图。

在对 Source 属性进行绑定的时候

可以看出,流程是一个自上而下,再自下而上的流程。这里就相当于是一个管道措置惩罚惩罚模型。每一行等价于一个管道,然后整个流程相当于整个管道串联起来。

在代码的实现过程中,我借鉴了 asp.net core 中的 middleware 的措置惩罚惩罚过程。https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/middleware/?view=aspnetcore-2.1&tabs=aspnetcore2x

在对 Source 属性进行绑定的时候

在 asp.net core 中,middleware 的此中一种写法如下:

public class AspNetCoreMiddleware { public async Task InvokeAsync(HttpContext context, RequestDelegate next) { // before await next(context); // after } }

先成立一个类似 HttpContext 的上下文,用于在这个管道模型中措置惩罚惩罚,我就叫 LoadingContext:

public class LoadingContext<TResult> where TResult : class { private byte[] _httpResponseBytes; private TResult _result; public LoadingContext(object source) { if (source == null) { throw new ArgumentNullException(nameof(source)); } OriginSource = source; Current = source; } public object Current { get; set; } public byte[] HttpResponseBytes { get => _httpResponseBytes; set { if (_httpResponseBytes != null) { throw new InvalidOperationException("value has been set."); } _httpResponseBytes = value; } } public object OriginSource { get; } public TResult Result { get => _result; set { if (_result != null) { throw new InvalidOperationException("value has been set."); } _result = value; } } }