zoukankan      html  css  js  c++  java
  • 【WPF】请注意一个 异步绑定 的陷阱!

    WPF的异步绑定在很大程度上简化了延迟较大的绑定操作,大大提高了生产力。但在这个糖果里存在一个天大的陷阱。

    如果你不能发现这个陷阱,轻则导致延迟严重,重则导致程序崩溃。

     

    请看第一个案例: 

    <Image Source="http://images.cnblogs.com/adminlogo.gif" />

    这段代码贴入VS2010以后,第一反应就是VS会假死一段时间。然后在Design窗口才会显示出园子的logo。运行段代码,程序也要假死一段时间才能正常工作。原因就是通过网络加载这个图片的时间过长。在我这需要10+秒。

     

    看到这里,你一定会说,使用异步操作就可以了。

    请看第二个案例: 

    前台代码: 

    <Image Source="{Binding IsAsync=True}"/>

    后台代码: 

            public MainWindow()

            {

                InitializeComponent();

                this.DataContext = "http://images.cnblogs.com/adminlogo.gif";

            }

    看上去这段代码能够完美的工作,可实际上效果和案例一完全一样。除了不会让VS假死一段时间以外。

    原因是因为你给UI Thread传递的只是一个stringUI Thread调用Async Thread把它转化为Uri以后,继续用UI Thread去下载图片,自然还是会导致阻塞。

     

    那么自然就会想起第三种方案。

    请看第三个案例: 

    前台代码: 

    <Image Source="{Binding Image, IsAsync=True}"/>

    后台代码: 

           public MainWindow()

            {

                InitializeComponent();

                this.DataContext = new VM();

            }

     

            public class VM

            {

                public ImageSource Image

                {

                    get

                    {

                        return new BitmapImage(new Uri("http://images.cnblogs.com/adminlogo.gif"));

                    }

                }

            }

    这样的代码看上去绝对是完美了。

    运行,并没有发现阻塞了UI Thread,正等待图片异步下载完毕的时候,突然弹出异常:

     The calling thread cannot access this object because a different thread owns it.

    WPFUI Thread是不能使用非UI Thread创建的Image的。

     

    下面正式推出我们的终极解决方案: 

    前台代码不变,后台代码修改为

            public MainWindow()

            {

                InitializeComponent();

                this.DataContext = new VM(this.Dispatcher);

            }

     

            public class VM

            {

                Dispatcher _dispatcher = null;

     

                public VM(Dispatcher dispatcher)

                {

                    _dispatcher = dispatcher;

                }

     

                public ImageSource Image

                {

                    get

                    {

                        if (_dispatcher == null)

                            return null;

                        BitmapImage bi = null;

                        try

                        {

                            WebClient wc = new WebClient();

                            MemoryStream ms = new MemoryStream(wc.DownloadData("http://images.cnblogs.com/adminlogo.gif"));

                            _dispatcher.Invoke(new Action(() =>

                            {

                                bi = new BitmapImage();

                                bi.BeginInit();

                                bi.StreamSource = ms;

                                bi.EndInit();

                            }), null);

                        }

                        catch { }

                        return bi;

                    }

                }

            }

    现在你还会发现任何问题吗? 

  • 相关阅读:
    【Nginx】Nginx性能优化及配置文件
    【算法】常见算法分类和思想
    【PHP】php位运算及其高级应用
    【数据结构】数据结构-图的基本概念
    【Redis】Redis缓存穿透解决方案之布隆过滤器
    【Linux】Linux系统5种IO模型
    【linux】/dev/null作用和/dev/random
    【Linux】Linux查找功能
    【算法】算法复杂度
    Docker Hub公共镜像仓库的使用
  • 原文地址:https://www.cnblogs.com/Aimeast/p/1963359.html
Copyright © 2011-2022 走看看