Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/292.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typo3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用MVVM/ICommand模式在WPF中正确实现BackgroundWorker_C#_Wpf_Mvvm_Backgroundworker_Icommand - Fatal编程技术网

C# 如何使用MVVM/ICommand模式在WPF中正确实现BackgroundWorker

C# 如何使用MVVM/ICommand模式在WPF中正确实现BackgroundWorker,c#,wpf,mvvm,backgroundworker,icommand,C#,Wpf,Mvvm,Backgroundworker,Icommand,我有一个主要按照MVVM模式编写的小WPF应用程序。程序的要点是读取文本文件的行,解析其中的数据,将数据写入对象列表,然后将这些对象中的数据写入特定格式的.CSV文件 尽管我以与其他应用程序相同的方式实现了BackgroundWorker类本身,但这次我从ICommand的Execute()方法中调用了RunWorkAsync()方法。虽然最终的输出是正确的,并且应用程序实际提供了所需的结果,但是当BackgroundWorker运行时,UI仍然会锁定 我已经将BackgroundWorker成

我有一个主要按照MVVM模式编写的小WPF应用程序。程序的要点是读取文本文件的行,解析其中的数据,将数据写入对象列表,然后将这些对象中的数据写入特定格式的.CSV文件

尽管我以与其他应用程序相同的方式实现了BackgroundWorker类本身,但这次我从ICommand的Execute()方法中调用了RunWorkAsync()方法。虽然最终的输出是正确的,并且应用程序实际提供了所需的结果,但是当BackgroundWorker运行时,UI仍然会锁定

我已经将BackgroundWorker成员和所有逻辑包装在一个名为“ReaderWriter”的类中,并使用一个以ViewModel为参数的构造函数

通过调用我的ReaderWriter实例的“StartProcess”方法,BackgroundWorker的RunWorkerAsync()被调用——这就是我希望它接管另一个线程并执行读取源文件、解析数据和编写新文件的长期运行过程的地方;同时定期执行ReportProgress()以更新ProgressBar

以下是我的ReaderWriter类的代码:

class ReaderWriter
{
    private LogDataViewModel vm { get; set; }
    private BackgroundWorker bw { get; set; }

    public ReaderWriter(LogDataViewModel viewModel)
    {
        vm = viewModel;
    }

    public void StartProcess()
    {
        bw = new BackgroundWorker();

        bw.WorkerReportsProgress = true;
        bw.WorkerSupportsCancellation = true;
        bw.DoWork += new DoWorkEventHandler(ReadFromSource);
        bw.ProgressChanged += new ProgressChangedEventHandler(UpdateProgress_Read);
        bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Completed_Read);

        bw.RunWorkerAsync();
    }

    private void ReadFromSource(object sender, DoWorkEventArgs e)
    {
        double records = 0;
        string[] lines = File.ReadAllLines(vm.SourcePath);
        int lineCount = lines.Length;
        double currentLine = 0;

        bw.ReportProgress(0, lineCount);

        foreach (var line in lines)
        {
            if (line.Length > 0)
            {
                string syntax = line.Substring(17, 6);

                switch (syntax)
                {
                    case "$WIMDA":
                        string[] segments = line.Replace(": <- ", ",").Split(',');
                        vm.LineItems.Add(new LineItem()
                        {
                            Time = segments[0],
                            HgPressure = segments[2],
                            BarPressure = segments[4],
                            AirTemp = segments[6],
                            RelHumidity = segments[10],
                            TrueWindDir = segments[14],
                            KnotsWindSpeed = segments[18],
                            MpsWindSpeed = segments[20]
                        });
                        break;

                    case "$GPGGA":
                        break;

                    default:
                        break;
                }
            }
            currentLine++;
            bw.ReportProgress(1, currentLine);
        }
        using (StreamWriter writer = new StreamWriter(vm.OutputPath))
        {
            writer.WriteLine($"Time,Pressure(Bar),Pressure(Hg),AirTemp({((vm.ConvertTempSetting) ? "F" : "C")}),RelativeHumidity,TrueWindDirection,WindSpeed(Knots),WindSpeed(M/s)");
            foreach (var lineItem in vm.LineItems)
            {
                writer.WriteLine($"{lineItem.Time},{lineItem.BarPressure},{lineItem.HgPressure},{((vm.ConvertTempSetting) ? Converters.ConvertFromCelcius(Convert.ToDouble(lineItem.AirTemp)).ToString() : lineItem.AirTemp)},{lineItem.RelHumidity},{lineItem.TrueWindDir},{lineItem.KnotsWindSpeed},{lineItem.MpsWindSpeed}");
                records++;
            }
        }
        e.Result = records;
    }

    private void UpdateProgress_Read(object sender, ProgressChangedEventArgs e)
    {
        vm.IncrementProgress();
        switch (Type.GetTypeCode(e.UserState.GetType()))
        {
            case TypeCode.Double:
                vm.IncrementProgress();
                break;

            case TypeCode.String:
                break;

            case TypeCode.Int32:
                vm.AppendStatus(DateTime.Now, $"{(int)e.UserState} lines parsed from log file");
                break;

            default:
                break;
        }
        if (vm.IsFirst)
        {
            vm.ProgressIsVisible = true;
            vm.IncrementProgress();
            vm.SetMaximum((int)e.UserState);
            vm.IsFirst = false;
        }
    }
    private void Completed_Read(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Cancelled)
        {
            vm.AppendStatus(DateTime.Now, $"Conversion was cancelled by user");
        }
        else
        {
            vm.AppendStatus(DateTime.Now, $"{(double)e.Result} records written to {vm.OutputPath}");
        }
        vm.LineItems.Clear();
    }
}
在这一点上的任何帮助都是非常感谢的,因为我已经为此奋斗了一段时间,任何试图研究解决方案的尝试都不会对我的特殊情况产生任何帮助。这似乎是一个相当独特的场景,但我希望我们能让它发挥作用


谢谢大家!

您使用ReportProgress不正确且过于频繁(在文件的每一行上)。它将受到重击,每次调用都会导致UI中出现某种更新,从而将其锁定

通过将百分比传递给它可能是最容易使用的。我真的不确定你在UpdateProgress\u Read中用开关做什么。最好只在通过总行数的100%时更新

将progressBar最大值设置为100

ProgressMaximum = 100;
计算总行数的1%

var x = lineCount / 100;
var y = 0;
并且只在通过每1%时报告进度

currentLine++;
if((currentLine % x) == 0)
{
    y++;
    bw.ReportProgress(y);
}
并更改UpdateProgress_Read,使其仅递增

private void UpdateProgress_Read(object sender, ProgressChangedEventArgs e)
{
    vm.IncrementProgress();
}

你需要想出比x和y更好的变量名!如果文件中的行数少于100行,还要计算出该怎么办

这是因为你正在用更新重击用户界面。尝试每100行只报告一次进度。如果你有很多线,而且线圈旋转得很快,那就增加这个数字。谢谢你,威尔。我照你的建议做了,效果很好!非常感谢您的详细回答,ajg!您的深入解释帮助我更好地理解了ReportProgress()的用途。我在foreach迭代中修改了一小段代码,现在它工作得很好。我很高兴这是一个我最初怀疑的简单得多的问题!=)
currentLine++;
if((currentLine % x) == 0)
{
    y++;
    bw.ReportProgress(y);
}
private void UpdateProgress_Read(object sender, ProgressChangedEventArgs e)
{
    vm.IncrementProgress();
}