首页 新闻 搜索 赞助

请问其他线程创建的BitmapImage如何在Task中使用?

0
悬赏园豆:5 [待解决问题]

我点击拍照按钮,会把相机当前的画面保存为BitmapImage并展示到Image中,然后点击打印按钮将多张照片合并为一张并传送给打印机打印。我想把打印操作在Task中执行,这样界面不会卡顿,但是拍照保存的BitmapImage不是在Task中创建的,这导致跨线程异常。
请问,有什么好的解决方式吗?

panda_go的主页 panda_go | 初学一级 | 园豆:104
提问于:2023-05-22 10:23
< >
分享
所有回答(2)
0

处理一下就好了,上代码。

LiveCoding | 园豆:487 (菜鸟二级) | 2023-05-22 10:37

我现在先调用Freeze(),访问ImageList没报错,但是调用PrintVisual还是会报跨线程错误

        [RelayCommand]
        private void CombineImages()
        {
            ImageList.ForEach(x => x.Freeze());

            try
            {
                Task.Run(() =>
                {
                        printerHelper.PrintImages(ImageList);
                });
            }
            catch (Exception)
            {

            }
        }
        // PrinterHelper.PrintImages
        public void PrintImages(List<BitmapImage> bitmapImages)
        {
            DrawingVisual combinedDrawingVisual = new DrawingVisual();

            using (var drawingContext = combinedDrawingVisual.RenderOpen())
            {
                // 拼接图片
                for (int i = 0; i < bitmapImages.Count; i++)
                {
                    drawingContext.DrawImage(bitmapImages[i], GetCorrectRect(bitmapImages[i], i, _pageSize, _imageMaxSize, _pageMargin, _imageMargin));
                }

                // 田字格划线
                var penThickness = 1;
                var pen = new Pen(Brushes.Black, penThickness);
                drawingContext.DrawLine(pen, new Point(_pageMargin.Width, _pageMargin.Height), new Point(_pageMargin.Width + _pageSize.Width, _pageMargin.Height));
                drawingContext.DrawLine(pen, new Point(_pageMargin.Width + _pageSize.Width / 2, _pageMargin.Height), new Point(_pageMargin.Width + _pageSize.Width / 2, _pageMargin.Height + _pageSize.Height));
                drawingContext.DrawLine(pen, new Point(_pageMargin.Width + _pageSize.Width, _pageMargin.Height), new Point(_pageMargin.Width + _pageSize.Width, _pageMargin.Height + _pageSize.Height));
                drawingContext.DrawLine(pen, new Point(_pageMargin.Width, _pageMargin.Height), new Point(_pageMargin.Width, _pageMargin.Height + _pageSize.Height));
                drawingContext.DrawLine(pen, new Point(_pageMargin.Width, _pageMargin.Height + _pageSize.Height / 2), new Point(_pageMargin.Width + _pageSize.Width, _pageMargin.Height + _pageSize.Height / 2));
                drawingContext.DrawLine(pen, new Point(_pageMargin.Width, _pageMargin.Height + _pageSize.Height), new Point(_pageMargin.Width + _pageSize.Width, _pageMargin.Height + _pageSize.Height));
            }

            var renderTargetBitmap = new RenderTargetBitmap(
                (int)(combinedDrawingVisual.ContentBounds.Width),
                (int)(combinedDrawingVisual.ContentBounds.Height),
                96, 96, PixelFormats.Pbgra32);
            renderTargetBitmap.Render(combinedDrawingVisual);
            var pngEncoder = new PngBitmapEncoder();
            pngEncoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
            using (var stream = File.Create($"D:\\Images\\{DateTime.Now:yyyymmddHHmmss}.png"))
            {
                pngEncoder.Save(stream);
            }

            Print(combinedDrawingVisual);
        }

        private void Print(DrawingVisual drawingVisual)
        {
            List<string> printers = new LocalPrintServer().GetPrintQueues().Select(x => x.Name).ToList();
            var selectedPrinter = printers.Where(x => x == Name).FirstOrDefault();
            if (string.IsNullOrEmpty(selectedPrinter))
            {
                MessageBox.Show("未找到打印机.");
                return;
            }
            // 检查打印机是否可用
            var printServer = new LocalPrintServer();
            var printQueueCollection = printServer.GetPrintQueues();
            if (printQueue == null)
            {
                MessageBox.Show("未找到打印机.");
                return;
            }

            var printDialog = new PrintDialog
            {
                PrintQueue = printQueue,
                PrintTicket = new PrintTicket()
                {
                    PageMediaSize = new PageMediaSize(PageMediaSizeName.ISOA4),

                },
                PageRangeSelection = PageRangeSelection.AllPages,
                PageRange = new PageRange(1, 1),
                MinPage = 1,
                MaxPage = 1,

            };
            try
            {
                printDialog.PrintVisual(drawingVisual, JobName);
            }
            catch (System.Exception e)
            {

                //throw e;
            }
        }
支持(0) 反对(0) panda_go | 园豆:104 (初学一级) | 2023-05-24 12:24
0

在跨线程使用 BitmapImage 时,你可以使用 Dispatcher 来确保在 UI 线程上访问和更新 BitmapImage。下面是一个示例,展示了如何在 Task 中使用由其他线程创建的 BitmapImage:

csharp
Copy code
private async void PrintButton_Click(object sender, RoutedEventArgs e)
{
await Task.Run(() =>
{
// 在 Task 中执行打印操作
Dispatcher.Invoke(() =>
{
// 在 UI 线程上访问和使用 BitmapImage
BitmapImage bitmapImage = GetBitmapImageFromCamera();
PrintImage(bitmapImage);
});
});
}

private BitmapImage GetBitmapImageFromCamera()
{
// 从相机获取 BitmapImage
// ...

return bitmapImage;

}

private void PrintImage(BitmapImage bitmapImage)
{
// 打印 BitmapImage
// ...
}
在上面的示例中,当点击打印按钮时,会在 Task.Run 中执行打印操作。在 Task 中的代码通过 Dispatcher.Invoke 方法将 UI 操作调度到 UI 线程上执行。在 Dispatcher.Invoke 中,你可以访问和使用由其他线程创建的 BitmapImage,执行打印操作或其他需要在 UI 线程上进行的操作。

通过使用 Dispatcher.Invoke,你可以在 Task 中使用由其他线程创建的 BitmapImage,并确保在 UI 线程上访问和更新它,避免跨线程异常。

Technologyforgood | 园豆:1292 (小虾三级) | 2023-05-22 23:33

我用dispatcher不会报错,但是会导致界面卡顿。不知道怎么优化了

支持(0) 反对(0) panda_go | 园豆:104 (初学一级) | 2023-05-24 12:15

@panda_go: 没有BeginInvoke?

支持(0) 反对(0) LiveCoding | 园豆:487 (菜鸟二级) | 2023-05-24 13:17
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册