主页 > 国内 >

一触即发_New UWP Community Toolkit - ImageEx

概述

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<>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 的情况,实际应用中,在图片加载失败时我们应该有对应的显示方法;

wo men chuang jian le liang ge kong jian, ImageEx he RoundImageEx, ru xia tu yi shi jia zai zhong de guo du zhuang tai, tu er shi zheng chang xian shi de zhuang tai ru guo Source she zhi you wu, ze hui chu xian tu san zhi xian shi PlaceHolder de qing kuang, shi ji ying yong zhong, zai tu pian jia zai shi bai shi wo men ying gai you dui ying de xian shi fang fa

<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 控件的源代码实现过程和简单的调用示例讲解完成了,希望能对大家更好的理解和使用这个控件有所帮助。欢迎大家多多交流,谢谢!

最后,再跟大家安利一下 UWPCommunityToolkit 的官方微博:https://weibo.com/u/6506046490,?大家可以通过微博关注最新动态。

衷心感谢 UWPCommunityToolkit 的作者们杰出的工作,Thank you so much,?UWPCommunityToolkit authors!!!

?

当前文章:http://www.isa30day.com/29zwmq/58438-782834-41201.html

发布时间:00:00:00

天龙八部??559955静心阁??香港中特网站132232??香港铁铁算4887正版??www.388818.com??香港马会资枓大全2018??www.888pg.com??789990.com??管婆特马彩图??世外桃园图库118??

相关文章
推荐图文
最热文章