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;

                    }

                }

            }

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

  • 相关阅读:
    JavaScript二进制数据序列化和反序列化
    三维变换矩阵推导笔记
    如何制作一款“有毒”的游戏
    如何使用visual studio将你的程序打包成安装包
    游戏设计模式系列(三)—— 策划变心太快?也许可以使用组合
    使用LayaAir解析xml文件
    游戏设计模式系列(二)—— 适时使用观察者模式,解耦你的代码
    游戏设计模式系列(一)—— 单线逻辑&&数据驱动,搞定最容易卡死的结算界面
    vs2010 win32程序中 sqlserver 2008 express的简单使用 (C++)
    UVALive 6529
  • 原文地址:https://www.cnblogs.com/Aimeast/p/1963359.html
Copyright © 2011-2022 走看看