簡體   English   中英

后台工作人員未報告進度 Winforms

[英]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 )狀態被切換時,它使用CancellationTokenSourceCancellationToken調用此工作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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM