代码之家  ›  专栏  ›  技术社区  ›  erotavlas

为什么iprogress<t>report(t)方法阻塞了UI线程?

  •  4
  • erotavlas  · 技术社区  · 6 年前

    我在下面的代码中报告方法process2()中的进度时遇到问题。我想在每一行被读取之后增加进度条,但是这样做会阻塞UI,使其失去响应。如果我注释掉progress.report()行,它将不再阻塞UI线程。有人知道为什么会发生这种情况吗?我该如何解决?

    下面是可以粘贴到Starter WPF应用程序中的完全工作的代码。

    单击“运行”按钮(在开始生成文件时可能会有一个小的停顿,等待生成文件完成后),然后尝试移动窗口,它将保持冻结状态。

    警告:此代码将在bin\debug文件夹(或您的配置指向的任何内容)中生成一个文本文件。如果从网络路径运行此文件,它可能无法写入此文件,因此建议从本地磁盘运行。

    主窗口.xaml.cs

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Windows.Threading;
    
    namespace WpfApplication2
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            Queue<string> queue = new Queue<string>();
    
            List<string> stringsCollection = new List<string>() { "1_abc123_A_AA_zzz", "2_abc123_AAAA_zzz", "3_abc123_AAAAAA_zzz" };
    
            int linesCount = 0;
            int totalLines = 0;
    
            string ASSEMBLY_PATH;
            string file; 
            public MainWindow()
            {
                InitializeComponent();
    
                ASSEMBLY_PATH = ReturnThisAssemblyPath();
                file = ASSEMBLY_PATH + @"\test.txt";
                generateFile();
            }
    
            private async void Button_Click2(object sender, RoutedEventArgs e)
            {
                linesCount = 0;
    
                Progress<int> process2_progress;
    
                this.progress.Value = 0;
                this.status.Text = "";
    
                process2_progress = new Progress<int>();
                process2_progress.ProgressChanged += Process2_progress_ProgressChanged;
    
                this.status.Text += "Searching..." + Environment.NewLine;
                await Task.Run(() =>
                {
                    totalLines = System.IO.File.ReadLines(file).Count();
    
                    foreach (string s in stringsCollection)
                    {
                        Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() =>
                        {
                            this.status.Text += "Searching " + s + Environment.NewLine;
                        }));
                        List<string> strCollection = Process2(s, process2_progress);
    
                        foreach (string str in strCollection)
                            queue.Enqueue(str);
                    }
                });
    
                this.status.Text += "DONE!!" + Environment.NewLine;
            }
    
            private void Process2_progress_ProgressChanged(object sender, int e)
            {
                linesCount += e;
                this.progress.Value = linesCount * 100 / totalLines;
            }
    
            List<string> Process2(string inputString, IProgress<int> progress)
            {
                List<string> result = new List<string>();
    
                foreach (string line in System.IO.File.ReadLines(file, new UTF8Encoding()))
                {
                    progress.Report(1);
                }
    
                return result;
            }
    
        void generateFile()
        {
            this.status.Text += "Generating FIle..." + Environment.NewLine;
            int count = 0;
            using (StreamWriter sw = new StreamWriter(file, true))
            {
                do
                {
                    sw.WriteLine(Guid.NewGuid().ToString());
                    count++;
                } while (count < 51000);
    
            }
            this.status.Text += "Done Generating FIle!" + Environment.NewLine;
        }
    
            public string ReturnThisAssemblyPath()
            {
                string codeBase = Assembly.GetAssembly(typeof(MainWindow)).CodeBase;
                UriBuilder uri = new UriBuilder(codeBase);
                string path = Uri.UnescapeDataString(uri.Path);
                return System.IO.Path.GetDirectoryName(path);
            }
        }
    }
    

    主窗口.xaml

    <Window x:Class="WpfApplication2.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApplication2"
            mc:Ignorable="d"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
    
            <TextBox x:Name="status" Grid.Row="0"></TextBox>
    
            <Button Grid.Row="2" Height="50" Click="Button_Click2">Run2</Button>
            <ProgressBar x:Name="progress" Grid.Row="3" Height="20" ></ProgressBar>
        </Grid>
    </Window>
    
    1 回复  |  直到 6 年前
        1
  •  6
  •   Douglas    6 年前

    Report

    int i = 0;
    foreach (string line in System.IO.File.ReadLines(file, Encoding.UTF8))
    {
        if (++i % 1000 == 0)
            progress.Report(1000);
    }