概述

UWP Community Toolkit  中有一个图片的扩展控件 - ImageEx,本篇我们结合代码详细讲解  ImageEx 的实现。

ImageEx 是一个图片的扩展控件,包括 ImageEx 和 RoundImageEx,它可以在异步加载图片源时显示加载状态,也可以在加载前使用占位图片,在下载完成后可以在应用内缓存,避免了重复加载的过程。我们来看一下官方的介绍和官网示例中的展示:

Source: https://github.com/Microsoft/UWPCommunityToolkit/tree/master/Microsoft.Toolkit.Uwp.UI.Controls/ImageEx

Doc: https://docs.microsoft.com/zh-cn/windows/uwpcommunitytoolkit/controls/imageex

Namespace: Microsoft.Toolkit.Uwp.UI.Controls; Nuget: Microsoft.Toolkit.Uwp.UI.Controls;

开发过程

代码分析

我们来看一下 ImageEx 控件的结构:

  • ImageEx.Members.cs - ImageEx 控件部分类的成员变量类

  • ImageEx.cs - ImageEx 控件部分类的定义类

  • ImageEx.xaml - ImageEx 控件样式文件

  • ImageExBase.Members.cs - ImageEx 控件基类部分类的成员变量类

  • ImageExBase.Placeholder.cs - ImageEx 控件基类部分类的占位符类

  • ImageExBase.Source.cs - ImageEx 控件基类部分类的图片源类

  • ImageExBase.cs - ImageEx 控件基类部分类的定义类

  • ImageExFailedEventArgs.cs - ImageEx 控件的失败事件参数类

  • ImageExOpenedEventArgs.cs - ImageEx 控件的打开事件参数类

  • RoundImageEx.Members.cs - RoundImageEx 控件部分类的成员变量类

  • RoundImageEx.cs - RoundImageEx 控件部分类的定义类

  • RoundImageEx.xaml - RoundImageEx 控件样式文件

下面把几个重点的类详细分析一下:

1. ImageEx.xaml

ImageEx 控件的样式文件,来看一下 Template 部分,包含了三层的控件:PlaceHolderImage,Image 和 Progress,这样就可以完成加载中或失败时显示 PlaceHolder 和 Progress,加载成功后显示 Image;同时样式在 Failed,Loading,Loaded 和 Unloaded 状态时,也会切换不同层的显示来完成状态切换;

<Style TargetType="controls:ImageEx"><Setter Property="Background" Value="Transparent" /><Setter Property="Foreground" Value="{ThemeResource ApplicationForegroundThemeBrush}" /><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="controls:ImageEx"><Grid Background="{TemplateBinding Background}" CornerRadius="{TemplateBinding CornerRadius}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"><Image Name="PlaceholderImage" Opacity="1.0" .../><Image Name="Image" NineGrid="{TemplateBinding NineGrid}" Opacity="0.0" .../><ProgressRing Name="Progress" Margin="16" HorizontalAlignment="Center" VerticalAlignment="Center"Background="Transparent" Foreground="{TemplateBinding Foreground}" IsActive="False" Visibility="Collapsed" /><VisualStateManager.VisualStateGroups><VisualStateGroup x:Name="CommonStates"><VisualState x:Name="Failed"><Storyboard><ObjectAnimationUsingKeyFrames Storyboard.TargetName="Image"Storyboard.TargetProperty="Opacity"><DiscreteObjectKeyFrame KeyTime="0"Value="0" /></ObjectAnimationUsingKeyFrames><ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlaceholderImage"Storyboard.TargetProperty="Opacity"><DiscreteObjectKeyFrame KeyTime="0"Value="1" /></ObjectAnimationUsingKeyFrames></Storyboard></VisualState><VisualState x:Name="Loading" .../><VisualState x:Name="Loaded" .../><VisualState x:Name="Unloaded" .../></VisualStateGroup></VisualStateManager.VisualStateGroups></Grid></ControlTemplate></Setter.Value></Setter></Style>

2. ImageExBase.Members.cs

ImageEx 控件的定义和功能实现主要在 ImageExBase 类中,而  ImageExBase.Members.cs 主要定义了类的成员,具体如下:

  • Stretch - 获取或设置控件的拉伸属性

  • CornerRadius - 获取或设置控件的圆角半径,用于 Rounded 或 Circle 图片控件

  • DecodePixelHeight - 获取或设置控件的解码像素高度

  • DecodePixelType - 获取或设置控件的解码像素类型

  • DecodePixelWidth - 获取或设置控件的解码像素宽度

  • IsCacheEnabled - 获取或设置缓存是否可用

另外还定义了 ImageFailed、ImageOpened、ImageExInitialized 事件,以及 GetAlphaMask() 方法,用于获取 alpha 通道的蒙板;

3. ImageExBase.Placeholder.cs

主要定义了 ImageExBase 类的占位符成员,具体如下:

  • PlaceholderStretch - 获取或设置占位符的拉伸属性

  • PlaceholderSource - 获取或设置占位符的图像源,ImageSource 类型,改变时会触发 PlaceholderSourceChanged(d, e) 方法;

4. ImageExBase.Source.cs

主要定义了 ImageExBase 类的图像源,除了定义 Source 外,还实现了以下几个方法:

① SetSource(source)

初始化 token 后,如果 source 为空,则进入 Unloaded 状态;否则进入 Loading 状态;判断 source 是 ImageSource 类型且有效,则赋值,然后进入 Loaded 状态;如果 source 是 Uri 类型但无效,或 ImageSource 类型无效,则进入 Failed 状态;如果 Uri 有效,判断为 httpUri 则进入 LoadImageAsync(uri) 方法,否则直接拼接 ms-appx:/// 资源格式加载给控件;

private async void SetSource(object source)
{    if (!IsInitialized) { return;}    this._tokenSource?.Cancel();    this._tokenSource = new CancellationTokenSource();AttachSource(null);    if (source == null){VisualStateManager.GoToState(this, UnloadedState, true);        return;}VisualStateManager.GoToState(this, LoadingState, true);    var imageSource = source as ImageSource;    if (imageSource != null){AttachSource(imageSource);ImageExOpened?.Invoke(this, new ImageExOpenedEventArgs());VisualStateManager.GoToState(this, LoadedState, true);        return;}_uri = source as Uri;    if (_uri == null){        var url = source as string ?? source.ToString();        if (!Uri.TryCreate(url, UriKind.RelativeOrAbsolute, out _uri)){VisualStateManager.GoToState(this, FailedState, true);            return;}}_isHttpSource = IsHttpUri(_uri);    if (!_isHttpSource && !_uri.IsAbsoluteUri){_uri = new Uri("ms-appx:///" + _uri.OriginalString.TrimStart('/'));}    await LoadImageAsync(_uri);
}

② LoadImageAsync(imageUri)

异步加载图片方法,在缓存可用且是 httpUri 时,从缓存里加载图片资源,根据 token 加载;然后加载对应资源后,进入 Loaded 状态;如果遇到一场,则进入 Failed 状态;如果是本地资源,或 http 资源不允许缓存,则直接实例化,不做缓存操作;

private async Task LoadImageAsync(Uri imageUri)
{    if (_uri != null){        if (IsCacheEnabled && _isHttpSource){            try{                var propValues = new List<KeyValuePair<string, object>>();                // Add DecodePixelHeight, DecodePixelWidth, DecodePixelType into propValues                ...                var img = await ImageCache.Instance.GetFromCacheAsync(imageUri, true, _tokenSource.Token, propValues);                lock (LockObj){                    if (_uri == imageUri){AttachSource(img);ImageExOpened?.Invoke(this, new ImageExOpenedEventArgs());VisualStateManager.GoToState(this, LoadedState, true);}}}            catch (OperationCanceledException){                // nothing to do as cancellation has been requested.            }            catch (Exception e){                lock (LockObj){                    if (_uri == imageUri){ImageExFailed?.Invoke(this, new ImageExFailedEventArgs(e));VisualStateManager.GoToState(this, FailedState, true);}}}}        else{AttachSource(new BitmapImage(_uri));}}
}

5. ImageExBase.cs

类中定义了 ImageEx Template 定义字段对应的变量,包括 Image,Progress,CommonStates,Loading 等等;

此外在 AttachImageOpened,RemoveImageOpened 时设置附加对应的 handler;在 AttachImageFailed,RemoveImageFailed 时设置解除对应的 handler;分别触发对应的事件,并把 VisualState 设置为对应的状态;

6.  RoundImageEx.xaml

我们看到,PlaceHolder 和 Image 都是用矩形来实现的,定义了 RadiusX 和 RadiusY 来实现圆角,Fill 使用 ImageBrush 来加载图像;实现圆角或圆形的图片控件;

另外需要注意的是,从 16299 开始,CornerRadius 属性也能适用于 ImageEx 控件,实现圆角矩形图片;如果系统低于 16299,不会引发异常,但是设置会不生效;

<Setter Property="Template"><Setter.Value><ControlTemplate TargetType="controls:RoundImageEx"><Grid Width="{TemplateBinding Width}"Height="{TemplateBinding Height}"><Rectangle x:Name="PlaceholderRectangle" RadiusX="{TemplateBinding CornerRadius}" RadiusY="{TemplateBinding CornerRadius}"...><Rectangle.Fill><ImageBrush x:Name="PlaceholderImage"ImageSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=PlaceholderSource}"Stretch="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=PlaceholderStretch}" /></Rectangle.Fill></Rectangle><Rectangle x:Name="ImageRectangle" RadiusX="{TemplateBinding CornerRadius}" RadiusY="{TemplateBinding CornerRadius}"...><Rectangle.Fill><ImageBrush x:Name="Image"Stretch="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Stretch}" /></Rectangle.Fill></Rectangle><ProgressRing Name="Progress" ... /><VisualStateManager.VisualStateGroups>...                </VisualStateManager.VisualStateGroups></Grid></ControlTemplate></Setter.Value></Setter>

调用示例

我们创建了两个控件,ImageEx 和 RoundImageEx,如下图一是加载中的过渡状态,图二是正常显示的状态;如果 Source 设置有误,则会出现图三只显示 PlaceHolder 的情况,实际应用中,在图片加载失败时我们应该有对应的显示方法;

<controls:ImageEx Name="ImageExControl"IsCacheEnabled="True" Width="200" Height="200"PlaceholderSource="/assets/LockScreenLogo.scale-200.png"Source="/assets/01.jpg"/><controls:RoundImageEx Name="RoundImageExControl"IsCacheEnabled="True" Width="200" Height="200" Stretch="UniformToFill"PlaceholderSource="/assets/01.jpg"Source="/assets/02.jpg"CornerRadius="999"/>

总结

到这里我们就把 UWP Community Toolkit 中的 ImageEx 控件的源代码实现过程和简单的调用示例讲解完成了,希望能对大家更好的理解和使用这个控件有所帮助。欢迎大家多多交流,谢谢!

New UWP Community Toolkit - ImageEx相关推荐

  1. Extensions in UWP Community Toolkit - ViewExtensions

    概述 UWP Community Toolkit Extensions 中有一个为 View 提供的扩展 - View Extensions,本篇我们结合代码详细讲解 View Extensions  ...

  2. New UWP Community Toolkit - DeveloperTools

    概述 UWP Community Toolkit  中有一个开发者工具集 DeveloperTools,可以帮助开发者在开发过程中进行 UI 和功能的调试,本篇我们结合代码详细讲解  Develope ...

  3. Extensions in UWP Community Toolkit - ListViewExtensions

    概述 UWP Community Toolkit Extensions 中有一个为 ListView 提供的扩展 - ListViewExtensions,本篇我们结合代码详细讲解 ListView  ...

  4. New UWP Community Toolkit - Staggered panel

    概述 前面 New UWP Community Toolkit 文章中,我们对 2.2.0 版本的重要更新做了简单回顾,其中简单介绍了 Staggered panel,本篇我们结合代码详细讲解  St ...

  5. 用于Fluent Design的UWP社区工具包蓄势待发

    Microsoft继续为即将推出Windows 10"秋季创作者更新"(FCU,Fall Creators Update)在做着准备工作,其中部分工作是目前正在开展的开发者工具和资 ...

  6. [UWP]了解IValueConverter

    [UWP]了解IValueConverter 原文:[UWP]了解IValueConverter 1. 前言 IValueConverter是用于数据绑定的强大的武器,它用于Value在Binding ...

  7. UWP 使用OneDrive云存储2.x api(二)【全网首发】

    上一篇提到为了给用户打造一个完全无缝衔接的最佳体验,UWP开发者最好也要实现App设置和数据的跨平台 分析了数据漫游和OneDrive的优缺点,结合自己App实际需要,我选择了OneDrive. 毕竟 ...

  8. [UWP]创建一个ProgressControl

    原文:[UWP]创建一个ProgressControl 1. 前言 博客园终于新增了UWP的分类,我来为这个分类贡献第一篇博客吧. UWP有很多问题,先不说生态的事情,表单.验证.输入.设计等等一堆基 ...

  9. UWP 记一次WTS 和 UCT翻车经历

    这次翻车,真的,在网上绝对找不到回答的. 只有在WTS的Issues讨论中才找到,哈哈 不过这个应该比较少遇到吧,据我所知,提出Issue那个大胸弟和我都遇到了... 翻车具备的条件如下: 1. 使用 ...

最新文章

  1. 李德毅院士:希望智能驾驶成为我国继高铁之后又一张新名片
  2. 『笔记』windows与CentOS间文件传输(win下实行)
  3. 结构性约束事件聚合下的在线多目标跟踪方法
  4. sqlmap 用户手册(续)
  5. Python使用递归法对整数进行因数分解
  6. boost.asio异步并发Tcp服务器
  7. Leetcode 15.三数之和
  8. 【算法与数据结构】二叉堆和优先队列 Priority Queue
  9. redis_学习_02_redis 可视化工具 Redis Desktop Manager
  10. 宝塔面板 python管理器2.0安装Mrdoc
  11. 2021年道路运输企业主要负责人和安全生产管理人员安全考核题型[安考星]
  12. 微信小程序中组件传值
  13. 根据银行卡号获取logo,并提取图片主题色(小程序版)
  14. ArcGIS 读写lyr层文件
  15. 郑州大学现代远程教育《商务礼仪》课程考核作业要求院校通智慧校园
  16. python绘制相频特性曲线_数据分析之Matplotlib和机器学习基础
  17. 解决Mac苹果笔记本键盘背光灯不亮的问题
  18. 九龙证券|AI重塑半导体基础设施,人工智能发展持续加速
  19. 「会员卡管理系统」 · Java Swing + MySQL JDBC开发
  20. 异步FIFO设计原理及Verliog源代码

热门文章

  1. 视觉SLAM笔记(60) 建图
  2. python简单命令语句_Python语言----linux常用命令(13)
  3. python3项目源代码下载_python3中文版下载
  4. Ionic4.x 中自定义公共模块
  5. 高级软件工程第七次作业:东理三剑客团队作业-随笔2
  6. css中IE判断语句 if !IE
  7. Nhibernate 3.0 Cookbook学习笔记 利用XML映射类
  8. java简单多线程_java中实现多线程的几种方式(简单实现)
  9. C语言课后习题(50)
  10. 安川e7变频器接线_台达变频器C2000系列在铝箔纸压花机上的应用