[英]Background worker is not reporting progress Winforms
我有一個后台工作人員正在運行,它正在從 xml 文件動態地制作表單字段。 根據 xml 的大小,加載需要一些時間,所以我使用加載欄來報告要使用的進度,這樣它們就不會退出程序。 該程序按預期工作,它隱藏加載面板並在工作人員完成時顯示表單字段,但在加載時,加載欄不會加載。 我沒有收到任何錯誤。
這是調用報告進度的地方:
if (!retrievePath.Equals(""))
{
// create the template with the data from the file
XDocument filledDoc = templateCreator.CreateTemplateWithGivenData2(retrievePath, fileName2);
tempDoc = filledDoc;
XElement root = tempDoc.Root;
// get child forms of return data state and sections
IDataInterface dataInterface = new DataInterfaceImplementation();
IEnumerable<XElement> sections = dataInterface.GetSections(filledDoc);
// Grab forms that aren't empty
IEnumerable<XElement> forms = XmlClass.GetMefForms(filledDoc).Where(u => u.Value != "").ToList();
IEnumerable<XElement> extra = dataInterface.GetSections(filledDoc).Where(u => u.Value != "").ToList();
// get the return header state
elemForms = dataMiddleman.GetSections(filledDoc);
foreach (XElement el in elemForms)
{
if (el.Name.LocalName.Equals("ReturnHeaderState"))
{
createForms(el, 3);
}
}
foreach (XElement el in forms)
{
i = i + 1;
i = (i / forms.Count()) * 100;
if (i == 100)
{
i = (i / (forms.Count() - 1)) * 100;
}
createForms(el, i);
}
private void createForms(XElement x, int i)
{
this.Invoke((MethodInvoker)delegate {
backgroundWorker1.ReportProgress(i);
var pLabel = new ParentLabel(x);
this.leftGroup.Controls.Add(pLabel);
var parentPanel = new CustomPanel(x);
parentPanel.SendToBack();
this.thebox.Controls.Add(parentPanel);
RecursiveTraverse(x, parentPanel);
pLabel.Click += (sender, e) => PLabel_Click(sender, e);
pPanels.Add(parentPanel);
});
}
這是我的后台工作人員代碼:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
loadingPanel.BringToFront();
populateNewFields();
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
loadingBar.Value = e.ProgressPercentage;
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
loadingBar.Value = 100;
Thread.Sleep(100);
loadingPanel.SendToBack();
loadingBar.Value = 0;
}
您的問題是關於后台工作人員沒有報告進度 Winforms ,我希望如果我使用Minimal Reproducible Example來演示如何在后台線程上發生進度時成功觸發event
(這是實現您想要的結果的一種方法) 並將復雜的 Xml 操作簡化為“耗時的黑匣子”,作為單獨的問題處理。
此Form
將提供一種使用MockCreateForm
方法測試通知的方法,該方法通過將后台工作程序阻塞 5 毫秒來模擬表單創建。 我相信您的設計規范是每 100 次操作發送一次通知。
通用event
缺少所需的屬性,因此繼承EventArgs
以自定義接收到的信息(在MainForm
類之外聲明它)。
public delegate void ProgressEventHandler(ProgressEventArgs e);
public class ProgressEventArgs : EventArgs
{
public ProgressEventArgs(int count, int total)
{
Count = count;
Total = total;
}
public int Count { get; }
public int Total { get; }
}
當按鈕(實際上是一個CheckBox
,其中Appearance
= Button
)狀態被切換時,它使用CancellationTokenSource
和CancellationToken
調用此工作Task
,因此可以暫停。 每 100 次觸發Progress
event
:
private void btnWorker_CheckedChanged(object sender, EventArgs e)
{
if(btnWorker.Checked)
{
_cts = new CancellationTokenSource();
Task.Run(() =>
{
var formCount = 10000;
for (int i = 0; i < formCount; i++)
{
if(_cts.IsCancellationRequested)
{
return;
}
// Notify every 100 times.
if((i % 100) == 0)
{
Progress?.Invoke(new ProgressEventArgs(count: i, total: formCount));
}
MockCreateForm();
}
Progress?.Invoke(new ProgressEventArgs(count: formCount, total: formCount));
}, _cts.Token);
}
else
{
_cts.Cancel();
labelStatus.Text = "Idle";
}
}
CancellationTokenSource _cts = null;
唯一剩下的就是在MainForm
中消費事件。 唯一需要編組回 UI 線程的是Label.Text
正在更新的短暫時刻。
public MainForm()
{
InitializeComponent();
Progress += (e) =>
{
Invoke((MethodInvoker)delegate
{
labelStatus.Text = $"{e.Count} of {e.Total}";
});
};
}
public event ProgressEventHandler Progress;
你在后台線程上做什么取決於你。 把它放在這里:
public void MockCreateForm()
{
Task.Delay(5).Wait();
}
我希望這能讓你更接近你想要達到的目標。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.