首页 > 解决方案 > 从对象构造函数更新 WPF GUI

问题描述

这是我的第一篇文章,就这样吧……我有一个名为 Job 的类,它在构造函数中连接到数据库中的多个表,并从每个表中获取一个项目。正在通过 SOAP Web 服务访问该数据库。该对象是通过单击按钮创建的。当在 main 中创建类时,会传入一个搜索字符串和一个带有文本的自定义进度条 GUI 元素。

进度条是一个自定义的用户控件,并且有一个 Update() 方法来更新消息文本和进度。

我尝试了多种方法来从构造函数更新 GUI(进度条),并发现这篇文章(如何使用 WPF Background Worker)非常有帮助,但是 GUI 仅在整个方法完成后才会更新。

我尝试从 Job 类的构造函数中删除方法并从主线程调用它们并在方法调用之间更新 GUI,我尝试使用调度程序来更新 GUI,甚至将它们作为任务等待。我还尝试直接更新自定义控件的值。尽管如此,GUI 似乎只在搜索方法完成后才会更新。

有没有更好的方法来解决这个问题?我在 Job 类的构造函数中做的太多了吗?即使在创建对象之前,GUI 似乎也没有更新。

private async void AddMasterJob_Click(object sender, RoutedEventArgs e)
    {
        SearchMethod();
    }
//Search method is used in multiple places.
private async void SearchMethod()
    {
        //This does not change the GUI until the whole method is complete. 
        await Task.Run(() => CurrentProgressControl.Visibility = Visibility.Visible);
        await Task.Run(() => CurrentProgressControl.BringIntoView());

        //Checks if record exists during constructor
        var tempJob = new Job(SearchBox.Text, CurrentProgressControl);
        //Only assign _masterJob if search was successful.
        if (tempJob.MasterJob != null)
        {
            //Try updating the GUI fields directly
            await Task.Run(() => CurrentProgressControl.progressBar.Value = 25);
            await Task.Run(() => CurrentProgressControl.label.Content = "Getting SubJobs");
            //Gets the subjobs and creates an array of subjob objects
            tempJob.GetSubJobs();
            //Try updating using the update method built into the custom control
            CurrentProgressControl.Update("Getting Planning Lines and Ledger Entries.", 45);
            //Get the planning lines and ledger entries
            tempJob.GetPlanningLinesandLedgerEntries();
            CurrentProgressControl.Update("Creating the Estimate Line List.", 60);
            //Combines Subjobs, Planning Lines, and Ledger Entries
            //Calls CalculateTable(_tableLines)
            tempJob.CreateEstimateLineList();
            CurrentProgressControl.Update("Separating into Labor and Material.", 75);
            //Populate _laborLines and _materialLines
            tempJob.SeparateTableLines(tempJob.TableLines);
            CurrentProgressControl.Update("Creating SubTotals.", 85);
            //Insert the subtotal Lines
            tempJob.CreateSubtotalLines(tempJob.LaborLines);
            tempJob.CreateSubtotalLines(tempJob.MaterialLines);
            CurrentProgressControl.Update("Calculating Totals.", 95);
            //Calculate the total estimate column and subtotal lines
            tempJob.CalculateTable(tempJob.MaterialLines);
            tempJob.CalculateTable(tempJob.LaborLines);

            //Calculate the totals for the whole Job
            tempJob.CalculateTotals();
            CurrentProgressControl.Update("Completed Successfully.", 100);

            _masterJob = tempJob;
            RaisePropertyChanged("MasterJob");
        }
    }

在 searchMethod 完成之后,GUI 会更新,但之前不会更新。搜索方法中的一些构造方法需要几秒钟,所以我希望 GUI 更新多次,但只有一次更新说完成。

标签: c#wpfxamluser-interface

解决方案


不要通过 更新 UI Task.Run,而是使用它来执行和等待长时间运行的操作:

private async void AddMasterJob_Click(object sender, RoutedEventArgs e)
{
    await SearchMethod();
}

private async Task SearchMethod()
{
    CurrentProgressControl.Visibility = Visibility.Visible;
    CurrentProgressControl.BringIntoView();

    var tempJob = new Job(SearchBox.Text, CurrentProgressControl);

    if (tempJob.MasterJob != null)
    {
        CurrentProgressControl.progressBar.Value = 25;
        CurrentProgressControl.label.Content = "Getting SubJobs";

        await Task.Run(() => tempJob.GetSubJobs());

        CurrentProgressControl.Update("Getting Planning Lines and Ledger Entries.", 45);

        await Task.Run(() => tempJob.GetPlanningLinesandLedgerEntries());

        CurrentProgressControl.Update("Creating the Estimate Line List.", 60);

        await Task.Run(() => tempJob.CreateEstimateLineList());

        CurrentProgressControl.Update("Separating into Labor and Material.", 75);

        await Task.Run(() => tempJob.SeparateTableLines(tempJob.TableLines));

        CurrentProgressControl.Update("Creating SubTotals.", 85);

        await Task.Run(() =>
        {
            tempJob.CreateSubtotalLines(tempJob.LaborLines);
            tempJob.CreateSubtotalLines(tempJob.MaterialLines);
        });

        CurrentProgressControl.Update("Calculating Totals.", 95);

        await Task.Run(() =>
        {
            tempJob.CalculateTable(tempJob.MaterialLines);
            tempJob.CalculateTable(tempJob.LaborLines);
            tempJob.CalculateTotals();
        });

        CurrentProgressControl.Update("Completed Successfully.", 100);

        _masterJob = tempJob;
        RaisePropertyChanged("MasterJob");
    }
}

或者使用单个 Task.Run 调用并通过其 Dispatcher 更新 UI:

private async Task SearchMethod()
{
    CurrentProgressControl.Visibility = Visibility.Visible;
    CurrentProgressControl.BringIntoView();

    var tempJob = new Job(SearchBox.Text, CurrentProgressControl);

    if (tempJob.MasterJob != null)
    {
        CurrentProgressControl.progressBar.Value = 25;
        CurrentProgressControl.label.Content = "Getting SubJobs";

        await Task.Run(() =>
        {
            tempJob.GetSubJobs());

            Dispatcher.Invoke(() => CurrentProgressControl.Update("Getting Planning Lines and Ledger Entries.", 45));

            tempJob.GetPlanningLinesandLedgerEntries();

            Dispatcher.Invoke(() => CurrentProgressControl.Update("Creating the Estimate Line List.", 60));

            tempJob.CreateEstimateLineList();

            Dispatcher.Invoke(() => CurrentProgressControl.Update("Separating into Labor and Material.", 75));

            tempJob.SeparateTableLines(tempJob.TableLines);

            Dispatcher.Invoke(() => CurrentProgressControl.Update("Creating SubTotals.", 85));

            tempJob.CreateSubtotalLines(tempJob.LaborLines);
            tempJob.CreateSubtotalLines(tempJob.MaterialLines);

            Dispatcher.Invoke(() => CurrentProgressControl.Update("Calculating Totals.", 95));

            tempJob.CalculateTable(tempJob.MaterialLines);
            tempJob.CalculateTable(tempJob.LaborLines);
            tempJob.CalculateTotals();
        });

        CurrentProgressControl.Update("Completed Successfully.", 100);

        _masterJob = tempJob;
        RaisePropertyChanged("MasterJob");
    }
}

如果可能,使作业方法异步:

private async Task SearchMethod()
{
    CurrentProgressControl.Visibility = Visibility.Visible;
    CurrentProgressControl.BringIntoView();

    var tempJob = new Job(SearchBox.Text, CurrentProgressControl);

    if (tempJob.MasterJob != null)
    {
        CurrentProgressControl.progressBar.Value = 25;
        CurrentProgressControl.label.Content = "Getting SubJobs";

        await tempJob.GetSubJobsAsync();

        CurrentProgressControl.Update("Getting Planning Lines and Ledger Entries.", 45);

        await tempJob.GetPlanningLinesandLedgerEntriesAsync();

        CurrentProgressControl.Update("Creating the Estimate Line List.", 60);

        await tempJob.CreateEstimateLineListAsync();

        CurrentProgressControl.Update("Separating into Labor and Material.", 75);

        await tempJob.SeparateTableLinesAsync(tempJob.TableLines);

        CurrentProgressControl.Update("Creating SubTotals.", 85);

        await tempJob.ob.CreateSubtotalLinesAsync(tempJob.LaborLines);
        await tempJob.CreateSubtotalLinesAsync(tempJob.MaterialLines);

        CurrentProgressControl.Update("Calculating Totals.", 95);

        await tempJob.CalculateTableAsync(tempJob.MaterialLines);
        await tempJob.CalculateTableAsync(tempJob.LaborLines);
        await tempJob.CalculateTotalsAsync();

        CurrentProgressControl.Update("Completed Successfully.", 100);

        _masterJob = tempJob;
        RaisePropertyChanged("MasterJob");
    }
}

推荐阅读