【问题标题】:Invoke method doesn't work调用方法不起作用
【发布时间】:2018-12-07 05:20:51
【问题描述】:

我的 Winforms C# 程序有问题。我想在将文件从本地磁盘复制到网络磁盘时显示进度条,但它不起作用。我究竟做错了什么?

一旦我在 WPF 中遇到这个问题,然后我使用“调度程序”解决了它,但在 Winforms 中我想没有这样的东西。代码如下,谢谢帮助。

private void copyFiles(string SourcePath, string DestinationPath)
{
        string SourcePath, DestinationPath;
        int i = 0, idOperatDetail, udane = 0;
        OperatDetail operatDetail = null;

        if (circularProgressBar1.InvokeRequired)
        {
            circularProgressBar1.BeginInvoke((Action)(() => circularProgressBar1.Enabled = true));
            circularProgressBar1.BeginInvoke((Action)(() => circularProgressBar1.Visible = true));
            circularProgressBar1.BeginInvoke((Action)(() => circularProgressBar1.Style = ProgressBarStyle.Marquee));
        }
        else
        {
            circularProgressBar1.Enabled = true;
            circularProgressBar1.Visible = true;
        }

        foreach (string sourceFile in Directory.GetFiles(SourcePath, "*.*", SearchOption.AllDirectories).Where(s => s.EndsWith(".jpg") || s.EndsWith(".tif")))
        {
            i++;
        }

        if (i != 0)
        {
            // Jest urobek to utworz foldery
            foreach (string dirPath in Directory.GetDirectories(SourcePath, "*", SearchOption.AllDirectories))
            {
                if (!Directory.Exists(dirPath.Replace(SourcePath, DestinationPath)))
                {
                    Directory.CreateDirectory(dirPath.Replace(SourcePath, DestinationPath));                        
                }
            }

            foreach (string sourceFile in Directory.GetFiles(SourcePath, "*.*", SearchOption.AllDirectories).Where(s => s.EndsWith(".jpg") || s.EndsWith(".tif")))
            {
                string tempSchemat = sourceFile.Replace(SourcePath, "");
                var txt = tempSchemat.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
                string schemat = "digitalizacja_" + txt[0].ToLower();

                if (operatDetailsUtils.DidDatabaseExists(schemat) == 0)
                {
                    operatDetail = operatDetailsUtils.GetOperatDetailIdByPath(schemat, sourceFile); // Pobierz ten szczegół z bazy danych
                    if (operatDetail != null) //  If file have record in database then get its metadata
                    {
                        idOperatDetail = operatDetail.Id;
                        Image img = Image.FromFile(sourceFile);
                        long size = (new FileInfo(sourceFile).Length);
                        int width = img.Width;
                        int height = img.Height;
                        float horResolution = img.HorizontalResolution;
                        float verResolution = img.VerticalResolution;
                        img.Dispose();
                        string destinationFile = sourceFile.Replace(SourcePath, DestinationPath);
                      //  if (size < FreeSpace(DestinationPath)) // Walidacja rozmiaru pliku kopiowanego
                        {
                                File.Copy(sourceFile, destinationFile, true);
                                Image imgDest = Image.FromFile(destinationFile);
                                long sizeDest = (new FileInfo(destinationFile).Length);
                                int widthDest = imgDest.Width;
                                int heightDest = imgDest.Height;
                                float horResolutionDest = imgDest.HorizontalResolution;
                                float verResolutionDest = imgDest.VerticalResolution;
                                imgDest.Dispose(); // Porównanie metadanych
                                if ((size != sizeDest) || (width != widthDest) || (height != heightDest) || (horResolution != horResolutionDest) || (verResolution != verResolutionDest))
                                {
                                    File.Delete(destinationFile); // Metadane sie nie zgadzaja
                                    slog.Error($"Plik o scieżce {destinationFile} ma inne metadane niż {sourceFile}. Został on usunięty ze względu na to, że został źle skopiowany");
                                }
                                else
                                {
                                    udane++;
                                    operatDetailsUtils.UpdatePath(schemat, idOperatDetail, destinationFile);
                                    File.Delete(sourceFile);
                                    slog.Info($"Plik {sourceFile} został poprawnie skopiowany na dysk sieciowy, a więc został usunięty z dysku lokalnego.");
                                }
                        }
                    }
                    else
                    {
                        slog.Error($"W bazie danych {schemat} w tabeli OPERAT_SZCZEGOLY nie istnieje plik o ścieżce {sourceFile} i nie został on skopiowany");
                    }
                }
                else
                {
                    slog.Error($"Baza danych {schemat} nie istnieje!");
                }
            }

            circularProgressBar1.BeginInvoke((Action)(() => circularProgressBar1.Enabled = false));
            circularProgressBar1.BeginInvoke((Action)(() => circularProgressBar1.Visible = false));                      
    }

【问题讨论】:

  • 阅读How to Ask,创建minimal reproducible example(代码太多)并解释它是如何“不起作用”的。
  • 我们需要错误...不过一般来说...您不需要循环 3 次通过相同的文件...只需一次...您只需要一种通用方法即可切换启用/可见...并调用它..在该方法中它可以足够聪明地决定是否调用自身
  • 任何触及 UI 控件的东西都需要在另一个线程中被调用。所以circularProgressBar1.Visible 和类似的人可能是你的人
  • 您的代码应该可以工作并且应该显示进度条。您如何调用该方法?你在用Task name = Task( ()=&gt; copyFiles("",""););
  • 我只用你看到的这个。

标签: c# user-interface controls invoke


【解决方案1】:

我不明白您为什么问是否需要调用,如果您想从单独的线程访问 GUI,则需要它。

将每个 GUI 更改方法放在调用方法中,它应该可以工作。

像这样:

this.Invoke(new Action(() =>
            {
                ProgressBar1.Value = ProgressPercentage;
            }));

【讨论】:

  • 他很可能正在使用 async/task 并更改方法中的控件,这就是他调用的原因。
【解决方案2】:

尝试清理您的代码。此外,尝试调用该方法,例如在按钮事件中。用这个来调用它:

Task name = Task( ()=> copyFiles("Source File"," Destination File"););
name.Start();

更新 2: 否决?艰难的人群。无论如何,我认为只需删除您的 Image 类。这似乎消耗了整个任务。如果你只是用它来验证,我认为 FileInfo.Length 已经足够了。

更新 1:我已经尝试了您的代码,但数据库部分除外,并且进度条对我有用。

        private void copyFiles(string SourcePath, string DestinationPath)
        {
            List<string> ext = new List<string>() { ".JPG", ".JPEG", ".TIF", ".PNG" };
            DirectoryInfo di = new DirectoryInfo(SourcePath);

            Action shower = () =>
            {
                circularProgressBar1.Enabled = true;
                circularProgressBar1.Visible = true;
                circularProgressBar1.Style = ProgressBarStyle.Marquee;
            };
            BeginInvoke(shower);

            var sourceFiles = di.GetFiles("*.*",SearchOption.AllDirectories).Where(f => ext.Contains(f.Extension));
            int num = sourceFiles.Count();

            foreach(FileInfo fi in sourceFiles)
            {
                string newFilePath;
                if (!Directory.Exists(DestinationPath))
                {
                    Directory.CreateDirectory(DestinationPath);
                }
                newFilePath = Path.Combine(DestinationPath, fi.Name);

                File.Copy(fi.FullName, newFilePath, true);

                if(fi.Length != new FileInfo(newFilePath).Length)
                {
                    File.Delete(newFilePath);
                }
            }

            Action hider = () =>
            {
                circularProgressBar1.Enabled = false;
                circularProgressBar1.Visible = false;
                circularProgressBar1.Style = ProgressBarStyle.Continuous;
            };

            BeginInvoke(hider);
        }

【讨论】:

  • 只有在复制过程完成时才会显示进度条。我使用了 Task 和 Invoke,但我仍然不知道为什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-25
  • 2020-11-11
相关资源
最近更新 更多