zoukankan      html  css  js  c++  java
  • 【Win 10应用开发】延迟加载图片的另一种方法

    上一篇文章中老周给大伙介绍了x:Phase和x:Bind的用法,并演示了一个延迟加载的示例。不过,那个例子会遗留一个问题,就是UI线程被阻塞,所以启动应用较慢。

    如果希望图片可以延迟加载,或许我们可以动动其他想法,对了,INotifyPropertyChanged接口可以成为突破口。

    大伙伴们都知道,实现这个接口可以让类型支持属性更改通知,当属性的值被更新后,会及时更新用户界面上的显示内容。我的思路就是:在数据对象实例化时,先让其显示一张“占位”图片,即未有图片数据时显示的一张临时图片,然后再去拉取图片资源,当真正的图片资源拿到后再修改相应的属性,这样一来,UI会自动更新,用真正需要的图片替代前面显示的临时图片。

    唉,看老周上面说得很神秘的样子,没事,咱们实战一下。

    为了好演示,我就定义一个简单的类型,一个字符串类型的Name属性,和一个BitmapImage类型的Image属性,并实现INotifyPropertyChanged接口。

        public class ItemInfo : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected void OnPropertyChanged([CallerMemberName]string propName = "")
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
            }
    
            #region 私有字段
            private string m_name;
            private BitmapImage m_image;
            private static Random rand =new Random();
            #endregion
    
            public ItemInfo(string _name, Uri _imageUri)
            {
                Name = _name;
                // 初始图像
                Image = new BitmapImage(new Uri("ms-appx:///images/0.png"));
    
                Task t = LoadImageAsync(_imageUri);
            }
    
            public string Name
            {
                get { return m_name; }
                set
                {
                    if (value != m_name)
                    {
                        m_name = value;
                        OnPropertyChanged();
                    }
                }
            }
    
            public BitmapImage Image
            {
                get { return m_image; }
                set
                {
                    if (m_image != value)
                    {
                        m_image = value;
                        OnPropertyChanged();
                    }
                }
            }
    
            async Task LoadImageAsync(Uri uri)
            {
                // 模拟延迟
                await Task.Delay(rand.Next(1000,5000));
                // 更改图像
                Image = new BitmapImage(uri);
            }
        }

    在类型的构造函数中,调用LoadImageAsync方法去异步读取图片,读取成功后修改Image属性,这样也会使UI同步更新。

    如果在UI上使用Image控件来显示图片,在图片更换一瞬间,由于要重新呈现,Image会发生一次闪烁。为了让这个闪烁能变得友好一些,我就想到把Image控件封装到一个用户控件里,当图片要更改时播放一个短暂的动画,这样一来,使得这个切换过程不那么刺眼。这个用户控件的XAML如下:

        <Grid>
            <Image x:Name="img" />
            <Rectangle x:Name="r" Opacity="0" Fill="LightGray"/>
        </Grid>

    Rectangle默认把它透明,不会挡住后面的图像,当要切换图像时,用动画让这个Rectangle挡一下后面的图片,这样会有一个瞬间的过度效果。

    在代码中为这个用户控件声明一个依赖项属性,并且当属性更新时也更新控件里面的Image对象。

            static DependencyProperty ImageSourceProperty = DependencyProperty.Register("ImageSource", typeof(ImageSource), typeof(UcIamgeShow), new PropertyMetadata(null, new PropertyChangedCallback(OnImageSourcePropertyChanged)));
    
            private static void OnImageSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                UcIamgeShow obj = d as UcIamgeShow;
                obj.std?.Begin();
                // 切换图片
                obj.img.Source = e.NewValue as ImageSource;
            }
    
            public ImageSource ImageSource
            {
                get { return (ImageSource)GetValue(ImageSourceProperty); }
                set { SetValue(ImageSourceProperty, value); }
            }

    使用这个用户控件时,将ImageSource属性和数据源对象进行绑定即可。比如:

       <local:UcIamgeShow Width="150" Height="150" Margin="5" ImageSource="{Binding Image,Mode=OneWay}" />

    大概原理就这样,大伙伴们可以下载示例源码自己玩耍。

    看看最终的效果,可否满意。

    示例源代码下载

  • 相关阅读:
    数据库表结构变动发邮件脚本
    .net程序打包部署
    无法登陆GitHub解决方法
    netbeans 打包生成 jar
    第一次值班
    RHEL6 纯命令行文本界面下安装桌面
    C语言中格式化输出,四舍五入类型问题
    I'm up to my ears
    How to boot ubuntu in text mode instead of graphical(X) mode
    the IP routing table under linux@school
  • 原文地址:https://www.cnblogs.com/tcjiaan/p/4981072.html
Copyright © 2011-2022 走看看