使用 backgroundworker 更新进度条 + clipboard.getimage() - WPF C#

Update progressbar + clipboard.getimage() with backgroundworker - WPF C#

我的程序应该将某个文件夹中的某些 Excel 文件作为图像(SVG 格式)导出到另一个文件夹中。这可以通过方法 CopyAndSaveTo 和 ExportRangeAsImage 来完成,它们会完成自己的工作。 在 MainWindow 上我有一个按钮,当它被点击时执行这两个功能。我希望点击此按钮的用户被告知(进度条)这个过程有多远(复制+导出)。 我尝试使用 BackgroundWorker 来实现它,并且只有在我注释以下代码(在方法 ExportRangeAsImage 中)时它才有效:

Bitmap image = new Bitmap(System.Windows.Forms.Clipboard.GetImage());
image.Save(ImagePath + Path.GetFileNameWithoutExtension(file) + ".svg");

否则我会收到以下错误消息( 翻译自德语):

在 System.NullReferenceException 中发生了 "System.Drawing.dll" 类型的异常,但是用户代码中没有对此进行处理。 附加信息:未将对象引用设置为对象实例。 如果此异常有可用的处理程序,程序可能会继续 运行 安全。

完整代码如下:

private void UpdateDataOfLine1(object sender, ExecutedRoutedEventArgs e)
        {
            string[] files = Directory.GetFiles(RootPath);
 
            BackgroundWorker worker = new BackgroundWorker();
            worker.WorkerReportsProgress = true;
            worker.DoWork += worker_DoWork;
            worker.ProgressChanged += worker_ProgressChanged;
            worker.RunWorkerAsync();
        }
 

 
        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            string[] files = Directory.GetFiles(RootPath);
 
            for (int i = 0; i < files.Length; i++)
            {
                if (files[i].Contains("$") || files[i].Contains("~") || files[i].Contains("Thumb"))
                {
                    continue;
                }
 
                File.Copy(files[i], DestPath + Path.GetFileName(files[i]), true);
 
                string newFile = DestPath + Path.GetFileName(files[i]);
 
                ExPortRangeAsImage(newFile);
 
                (sender as BackgroundWorker).ReportProgress(i);
                Thread.Sleep(100);
            }
        }
 

 
        void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            Status.Value = e.ProgressPercentage;
        }
 

        public void ExPortRangeAsImage(string file)
        {
            var ExcelApp = new Microsoft.Office.Interop.Excel.Application();
 
            try
            {
                if (file.Contains("BeispielDatei"))
                {
                    Workbook wb = ExcelApp.Workbooks.Open(file);
                    Worksheet ws = (Worksheet)wb.Sheets[1];
                    Range range = ws.Range["A1:U35"];
                    range.CopyPicture(XlPictureAppearance.xlScreen, XlCopyPictureFormat.xlBitmap);
                    wb.Close(SaveChanges: false);
                    Marshal.ReleaseComObject(wb);
                }
 
                else
                {
                    Workbook wb = ExcelApp.Workbooks.Open(file);
                    Worksheet ws = (Worksheet)wb.Sheets[1];
                    Range range = ws.Range["A1:U35"];
                    range.CopyPicture(XlPictureAppearance.xlScreen, XlCopyPictureFormat.xlBitmap);
                    wb.Close(SaveChanges: false);
                    Marshal.ReleaseComObject(wb);
                }
            }
 
            finally
            {
                Bitmap image = new Bitmap(System.Windows.Forms.Clipboard.GetImage());
                image.Save(ImagePath + Path.GetFileNameWithoutExtension(file) + ".svg");
 
                Marshal.ReleaseComObject(ExcelApp);
            }
        }

你能告诉我我做错了什么或者我如何意识到它吗? 除了 BackgroundWorker 还有其他方法吗?

提前感谢您的帮助!

这是错误的屏幕截图

你应该查看堆栈跟踪,我认为你的内部异常很可能是由于跨线程访问冲突造成的。

空引用可能被触发是由于:System.Windows.Forms.Clipboard.GetImage() 可能返回空值。

您可以在 UI 调度程序线程中尝试 运行 这部分:

Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(()=>
{
   Bitmap image = new Bitmap(System.Windows.Forms.Clipboard.GetImage());
   image.Save(ImagePath + Path.GetFileNameWithoutExtension(file) + ".svg");
}

这也很可能会引入同步问题(复制和粘贴之间的竞争)。您可能必须重组代码以确保在将另一张图片复制到剪贴板之前完成图片写入。