【问题标题】:Using background Worker to insert Text file into a listBox WPF使用后台 Worker 将文本文件插入 listBox WPF
【发布时间】:2018-06-24 00:55:35
【问题描述】:

当我在循环中添加这行代码时

myCollection.Add(new FetchData(line)); 

它抛出

这种类型的 CollectionView 不支持从不同于 Dispatcher 线程的线程更改其 SourceCollection

我也试过用这个,但没用:

mqttUpload.ItemsSource = MyList;

进度条更新,我也可以打印行,唯一的问题是我无法将数据添加到 ListBox。

这就是我的数据在 txt 文件中的样子,这个文件包含 3500 行。

这是我尝试过的。

public partial class UserControl2 : UserControl
{

    public static List<string> Mylist = new List<string>();
    ObservableCollection<FetchData> myCollection = new  ObservableCollection<FetchData>();

    public UserControl2()
    {
        InitializeComponent();
        mqttUpload.ItemsSource = myCollection;

        backgroundWorker1.DoWork += backgroundWorker1_DoWork;
        backgroundWorker1.ProgressChanged +=backgroundWorker1_ProgressChanged;
        backgroundWorker1.WorkerReportsProgress = true;
        backgroundWorker1.RunWorkerCompleted += jobfinish;

    }

    public static UserControl2 uploadData;

    BackgroundWorker backgroundWorker1 = new BackgroundWorker();
    public static string FilePath = "";

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        var files = File.ReadAllLines(FilePath);
        for (int i = 0; i < files.Length; i++)
        {
            var line = files[i];
            Mylist.Add(line);
            int percentage = (int)((i / (double)files.Length) * 100.0);
            backgroundWorker1.ReportProgress(percentage);
            Console.WriteLine(line);
        }
    }

    public void jobfinish(object sender, RunWorkerCompletedEventArgs e)
    {
        Console.WriteLine(  "finish");

    }

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)// progress change
    {
        progressBar1.Value = e.ProgressPercentage;
    }
}

获取类

public class FetchData
{
    public string fetchData { get; set; }

    public FetchData(string fetchData)
    {
        this.fetchData = fetchData;
    }
}

这是 XAML 代码

<ListBox Margin="10,64,0,-434" Grid.Column="2" Name="mqttUpload" 
         Padding="20,0,0,0" Background="#18191A"  Foreground="#F5980C" Grid.Row="2" />

我的目标是在显示进度条的同时逐行读取数据,最后在 ListBox 中显示数据。

这就是数据在列表框中的显示方式。在这张图片中,我正在从数据库中读取数据。我想实现相同但从 txt 文件中读取。

【问题讨论】:

  • 这听起来像是一个 XY 问题。您真正的问题是 99.9% 的实际 CPU 工作需要完成,必须发生在 UI 线程上:即渲染所有在列表视图中显示行的控件。您无法真正显示 UI 渲染工作的进度条。你最好的选择是虚拟化。您应该简单地避免进行所有不必要的渲染,然后就不需要进度条了,因为您的 UI 会立即加载

标签: c# wpf data-binding


【解决方案1】:

最重要的规则:您只能从 GUI(主)线程触摸 GUI。

您的Mylist.Add(line); 违反了该规则。

您也可以使用 Progress 事件:

  backgroundWorker1.ReportProgress(percentage, line);

然后

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)// progress change
{
   progressBar1.Value = e.ProgressPercentage;
   string line = (string) e.State;
   Mylist.Add(line);  // ok, this runs on the main thread
}

【讨论】:

  • 好吧,我之前也能够将数据放入 MyList,唯一的问题是我无法将数据添加到 ListBox。我相信这将通过使用 ObservableCollection 来完成,我替换了 Mylist.Add(line);到 myCollection.Add(new FetchData(line));使用您的代码我的 gui 冻结。也没有用。
  • FetchData 不可能改变任何东西。我的代码不应该冻结,肯定还有你没有发布的其他内容。
  • 但是最好的办法是避免这种情况:没有用户可以或想要阅读 3500 行。您的 GUI 不是您的数据层。
【解决方案2】:

为什么不等到工作完成呢?

您可以通过 ReportsProgress 发送数据。

BackgroundWorker.ReportProgress Method (Int32, Object)

一次更新 UI 是很多开销。我会使用异步文件 IO 并读取前 100 行,然后读取整个文件。

【讨论】:

  • 我不介意等到工作完成,但最后它应该在我的 gui 列表框中显示数据。
  • 然后在jobFinished中进行。
猜你喜欢
  • 2011-12-31
  • 2011-01-08
  • 2023-02-10
  • 2011-11-28
  • 1970-01-01
  • 1970-01-01
  • 2022-10-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多