流氓赫 2021-06-06 09:48 采纳率: 100%
浏览 55
已采纳

WPF多线程创建Image控件求助,莫名其妙的报错

 这个方法是利用PDF控件将每页转成Image列表返回,本来是没用到Task线程操作的,

但是pdf.ConvertPageToPNGMemoryStream()这个方法每页转换耗时将近1秒,

页数少还好说,页数多了就会卡界面,所以想用线程提高速度,

然后遇到这个奇怪的现象,假设PDF只有1页,单步调试中会报错,

注释下面这句的 i = 2 ???就很奇怪明明循环只跑1次就结束了啊,

求助大神能否帮忙解答一下,或者这个方法正确的优化写法是怎样的,

多谢多谢

        private List<Image> PDFToImageList(Pdf.Document pdf)
        {
            List<Image> lst = new List<Image>();
            Task[] tasks = new Task[pdf.Pages.Count];
            for (int i = 1; i <= pdf.Pages.Count; i++)
            {
                Image img = new Image();
                tasks[i - 1] = Task.Factory.StartNew(() =>
                {
                    System.Windows.Media.Imaging.BitmapImage bitmapImage = new System.Windows.Media.Imaging.BitmapImage();
                    //调试报异常越界,i=2?
                    using (MemoryStream stream = pdf.ConvertPageToPNGMemoryStream(pdf.Pages[i]))
                    {
                        stream.Position = 0;
                        bitmapImage.BeginInit();
                        bitmapImage.CacheOption = System.Windows.Media.Imaging.BitmapCacheOption.OnLoad;
                        bitmapImage.StreamSource = stream;
                        bitmapImage.DecodePixelWidth = (int)(this.noticeWidth * 1.3);
                        bitmapImage.EndInit();
                        bitmapImage.Freeze();

                        container.Dispatcher.Invoke(() =>
                        {
                            img.Source = bitmapImage;
                            lst.Add(img);
                        });
                    }
                });
            }
            Task.WaitAll(tasks);
            return lst;
        }

展开全部

  • 写回答

2条回答 默认 最新

  • CSDN专家-showbo 2021-06-06 12:44
    关注

    有点像js的闭包问题,task是异步执行的,但是匿名函数中引用到了i,task没执行for就已经执行完毕了,这样执行线程的时候i已经是for循环后的值2越界了。

    怕界面假死,用一个线程来处理就行了吧,干嘛用多线程,多线程的话看你代码也会有bug,线程的执行完毕先后不一定是完全按照for中的先后,所以也会出现转为图片顺序和pdf不一致

    改成下面的单线程

    
    
            private List<Image> PDFToImageList(Pdf.Document pdf)
            {
                List<Image> lst = new List<Image>();
                var task = Task.Factory.StartNew(() =>
                {
                    for (int i = 1; i <= pdf.Pages.Count; i++)
                    {
                        Image img = new Image();
                        System.Windows.Media.Imaging.BitmapImage bitmapImage = new System.Windows.Media.Imaging.BitmapImage();
                        //调试报异常越界,i=2?
                        using (MemoryStream stream = pdf.ConvertPageToPNGMemoryStream(pdf.Pages[i]))
                        {
                            stream.Position = 0;
                            bitmapImage.BeginInit();
                            bitmapImage.CacheOption = System.Windows.Media.Imaging.BitmapCacheOption.OnLoad;
                            bitmapImage.StreamSource = stream;
                            bitmapImage.DecodePixelWidth = (int)(this.noticeWidth * 1.3);
                            bitmapImage.EndInit();
                            bitmapImage.Freeze();
                            container.Dispatcher.Invoke(() =>
                            {
                                img.Source = bitmapImage;
                                lst.Add(img);
                            });
                        }
    
                    }
                });
    
                Task.WaitAll(task);
                return lst;
            }

    一定要多线程可以用下面的,将i当做参数传入

    
            private List<Image> PDFToImageList(Pdf.Document pdf)
            {
                List<Image> lst = new List<Image>();
                Task[] tasks = new Task[pdf.Pages.Count];
                for (int i = 1; i <= pdf.Pages.Count; i++)
                {
                    tasks[i - 1] = Task.Factory.StartNew((objI) =>
                    {
                        int index = (int)objI;
                        lst[index]  = new Image();//使用下标来定位,防止生成顺序错误,而且放到task里面,而不是外面Image img=new Image然后引用img对象,这样没有越界,但是只有最后页面有图片,什么原因和i的问题一样
                    
                        System.Windows.Media.Imaging.BitmapImage bitmapImage = new System.Windows.Media.Imaging.BitmapImage();
                        //调试报异常越界,i=2?
                        using (MemoryStream stream = pdf.ConvertPageToPNGMemoryStream(pdf.Pages[index]))
                        {
                            stream.Position = 0;
                            bitmapImage.BeginInit();
                            bitmapImage.CacheOption = System.Windows.Media.Imaging.BitmapCacheOption.OnLoad;
                            bitmapImage.StreamSource = stream;
                            bitmapImage.DecodePixelWidth = (int)(this.noticeWidth * 1.3);
                            bitmapImage.EndInit();
                            bitmapImage.Freeze();
                            container.Dispatcher.Invoke(() =>
                            {
                                lst[index].Source = bitmapImage;//使用下标来定位,防止生成错落
                            });
                        }
                    }, i);
                }
                Task.WaitAll(tasks);
                return lst;
            }

    展开全部

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
    CSDN专家-showbo 2021-06-06 13:05

    帮你有帮助可以点击采纳支持下哦,谢谢~~

    回复
    流氓赫 2021-06-07 10:17

    第一段代码没调通,可能也是我改得不对,第二段代码可以用,稍微修改了一下,用的 Dispatcher.BeginInvoke,因为后面还有很多业务代码,只能Waitall阻塞线程走流程,虽然界面还是会被阻塞卡住,但是多线程还是提升了一倍效率,还要继续尝试优化,多谢多谢

    回复
查看更多回答(1条)
编辑
预览

报告相同问题?

手机看
程序员都在用的中文IT技术交流社区

程序员都在用的中文IT技术交流社区

专业的中文 IT 技术社区,与千万技术人共成长

专业的中文 IT 技术社区,与千万技术人共成长

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

客服 返回
顶部