后台工作人员仍然冻结 ui
Posted
技术标签:
【中文标题】后台工作人员仍然冻结 ui【英文标题】:Background worker still freezing ui 【发布时间】:2019-09-28 12:14:47 【问题描述】:即使我设置了后台工作人员,我似乎也无法让它不冻结 UI。
我在网上四处寻找,但找不到解决办法。我已经尝试创建基本线程并且有效,但我还需要在 UI 运行时更新它,这就是我切换到后台工作人员的原因,但是如果你能帮助我弄清楚如何使用基本线程并让它工作就可以了.
using MediaToolkit;
using MediaToolkit.Model;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using VideoLibrary;
namespace ConsoleApp1
public partial class Form1 : Form
private List<VideoInfo> vids = new List<VideoInfo>();
private List<VideoInfo> failedVids = new List<VideoInfo>();
private int threads = 0;
BackgroundWorker worker;
private delegate void DELEGATE();
static void Main(string[] args)
Form1 form = new Form1();
form.ShowDialog();
public Form1()
InitializeComponent();
worker = new BackgroundWorker();
private void button1_Click(object sender, EventArgs e)
if(threads == 0)
progressBar1.Maximum = vids.Count;
progressBar1.Value = 0;
failedVids.Clear();
worker.DoWork += doWork;
worker.RunWorkerAsync();
//downloadVid();
else
Console.WriteLine("Waiting for threads" + threads);
/*Thread thread1 = new Thread(new ThreadStart(downloadVid));
thread1.Start();*/
private void button1_Click_1(object sender, EventArgs e)
VideoInfo vid = new VideoInfo(tbLink.Text, tbTitle.Text, tbArtist.Text);
vids.Add(vid);
tbLink.Clear();
tbTitle.Clear();
listView1.Items.Add(vid.getLink());
private int downloadThread(int i)
Console.WriteLine(i);
var source = @"C:\Users\derri\Downloads\DownloadTest\";
var youtube = YouTube.Default;
VideoInfo vidInfo = vids[(int) i];
var vid = youtube.GetVideo(vidInfo.getLink());
Console.WriteLine(vidInfo.getLink());
try
File.WriteAllBytes(source + vid.FullName, vid.GetBytes());
catch (Exception e)
failedVids.Add(vids[(int)i]);
Console.WriteLine(e);
goto End;
var inputFile = new MediaFile Filename = source + vid.FullName ;
var outputFile = new MediaFile Filename = $"source + vidInfo.getArtist() + " - " + vidInfo.getTitle().mp3" ;
using (var engine = new Engine())
engine.GetMetadata(inputFile);
engine.Convert(inputFile, outputFile);
File.Exists(outputFile.Filename);
File.Delete(inputFile.Filename);
setTags(vidInfo.getArtist(), vidInfo.getTitle());
End:
threads--;
return 1;
private void doWork(object sender, DoWorkEventArgs e)
Delegate del = new DELEGATE(downloadVid);
this.Invoke(del);
private void downloadVid()
int prog = 0;
for (int i = 0; i < vids.Count; i++)
Console.WriteLine(i);
while ((threads > 5))
Thread thread = new Thread(() => prog += downloadThread(i); );
thread.Start();
threads++;
System.Threading.Thread.Sleep(1000);
//thread.Join();
/*ParameterizedThreadStart start = new ParameterizedThreadStart(downloadThread);
Thread t = new Thread(start);
t.Start(i);
progressBar1.Value++;
threads++;*/
while (threads > 0)
foreach (VideoInfo failedVid in failedVids)
listView2.Items.Add(failedVid.getLink());
listView1.Clear();
vids.Clear();
private void setTags(string artist, string title)
TagLib.File file = TagLib.File.Create("C:\\Users\\derri\\Downloads\\DownloadTest\\" + artist + " - " + title + ".mp3");
file.Tag.Artists = (new String[] artist );
file.Tag.Title = (title);
file.Save();
【问题讨论】:
this.Invoke 将在 UI 线程上运行它。你为什么要这样调用它?我看到了问题,while 循环阻塞了 UI,因为你在 UI 线程中。 @RonBeyer 我正在关注在线教程,这就是他们放置 this.invoke 的地方,它对他们有用。我将如何在 UI 上不调用它? 只需从doWork
方法调用downloadVid
,或者将所有downloadVid
的东西放在doWork
中,无论哪种方式都不要使用this.Invoke
,因为你实际上是绕过了后台工作人员并再次在 UI 线程上运行。不过,您必须确保在 UI 线程上调用 listview
方法。
@RonBeyer 这就是我这样做的全部原因。这是我能找到的能够从 UI 线程调用 listview 方法的唯一方法。我该如何做你说的并从 UI 线程调用 listview 方法?
我怀疑在主 UI 线程上运行 while ((threads > 5))
可能会给您带来一些麻烦。
【参考方案1】:
this.Invoke 将在 UI 线程上运行。
了解如何使用 BackgroundWorker 类的 ReportProgress 或 RunWorkerCompleted 事件。两者都允许您将数据从后台线程传递到 UI 线程。
【讨论】:
非常感谢,C# 中的线程新手,所以感谢您在不告诉我的情况下为我提供修复它所需的信息。 Google 是一个很好的资源,这里有一个 link,它用一个例子解释了我提到的事件。以上是关于后台工作人员仍然冻结 ui的主要内容,如果未能解决你的问题,请参考以下文章
Android RecyclerView 在 notifyDataSetChanged 调用上冻结 UI