我点击拍照按钮,会把相机当前的画面保存为BitmapImage并展示到Image中,然后点击打印按钮将多张照片合并为一张并传送给打印机打印。我想把打印操作在Task中执行,这样界面不会卡顿,但是拍照保存的BitmapImage不是在Task中创建的,这导致跨线程异常。
请问,有什么好的解决方式吗?
处理一下就好了,上代码。
我现在先调用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;
}
}
在跨线程使用 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 线程上访问和更新它,避免跨线程异常。
我用dispatcher不会报错,但是会导致界面卡顿。不知道怎么优化了
@panda_go: 没有BeginInvoke?