C# WPF上位机开发(子窗口通知父窗口更新进度)

2023-12-24 17:30:54

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

? ? ? ? 这两天在编写代码的时候,正好遇到一个棘手的问题,解决之后感觉挺有意义的,所以先用blog记录一下,后面可以当成经验来参考。问题是这样的,本身软件在加载子窗口的时间可能会比较长,这么长的时间的加载,会给用户造成一个错觉,会以为这个软件是不是真的卡死了?所以在子窗口加载的过程中,我们希望子窗口根据不同的加载进度,更新父窗口中的进度条,至少让用户觉得软件还在跑,没有卡死。整个需求就是这么一个想法。

? ? ? ? 为了解决这个问题,想了很多办法,最后还是通过BackgroundWorker和参数传递的方式才解决的。

1、首先设计主窗口界面

? ? ? ? 主窗口界面不复杂,主要就两个控件。一个是按钮,用户弹出子窗口;一个是进度条,子窗口中的按钮按下去的时候,这个进度条就会慢慢更新到100%。

<Window x:Class="WpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Button  x:Name="Button1"  Content="Button1" Click="Button1_Click" HorizontalAlignment="Left" Margin="335,135,0,0" VerticalAlignment="Top" Width="75"/>
        <ProgressBar Name="progressBar" HorizontalAlignment="Left" VerticalAlignment="Top" Width="300" Height="20" Margin="230,205,0,0"/>

    </Grid>
</Window>

? ? ? ? 整个显示效果是这样的,

2、主窗口的代码

? ? ? ? 有了界面,下面开始设计主窗口的代码。整个代码其实有两块。一块是按钮Button1的回调函数,这部分就是弹出子窗口,还要给子窗口传递一个参数。另外一块就是注册BackgroundWorker变量以及它的回调函数。注意这个BackgroundWorker的变量是在构造函数里面进行设置的。而且刚刚谈到的子窗口传递参数,说的也就是这个BackgroundWorker变量。

? ? ? ? 有兴趣的同学可以观察一下BackgroundWorker的回调函数ProgressChanged。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;

namespace WpfApp
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        private BackgroundWorker worker;

        public MainWindow()
        {
            InitializeComponent();

            worker = new BackgroundWorker();
            worker.WorkerReportsProgress = true;
            worker.ProgressChanged += Worker_ProgressChanged;
        }

        private void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar.Value = e.ProgressPercentage;
        }

        private void Button1_Click(object sender, RoutedEventArgs e)
        {
            ChildWindow childWindow = new ChildWindow(worker);
            childWindow.ShowDialog();
        }
    }
}

3、设计子窗口界面

? ? ? ? 子窗口界面部分就比较简单了,就是一个按钮而已,

<Window x:Class="WpfApp.ChildWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp"
        mc:Ignorable="d"
        Title="ChildWindow" Height="450" Width="800">
    <Grid>
        <Button x:Name="Button2" Content="Button2" Click="Button2_Click" HorizontalAlignment="Left" Margin="355,150,0,0" VerticalAlignment="Top" Width="75"/>

    </Grid>
</Window>

? ? ? ? 转成图形的话,它的界面是这样的,

4、子窗口代码设计

? ? ? ? 有了子窗口,下面就要开始实现按钮的回调函数了。既然在主窗口中已经定义好了BackgroundWorker,那么回调函数需要做的就是有了进展之后,去ReportProgress就好了。这样有了这个ReportProgress就会进一步触发主窗口中的回调函数,这样主窗口中的进度条也会得到更新。并且所有操作都完毕之后,还会弹出一个MessageBox。大概就是这么一个过程。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Threading;
using System.ComponentModel;

namespace WpfApp
{
    /// <summary>
    /// ChildWindow.xaml 的交互逻辑
    /// </summary>
    public partial class ChildWindow : Window
    {
        public int add_flag = 0;
        private BackgroundWorker worker;

        public ChildWindow(BackgroundWorker worker)
        {
            InitializeComponent();
            this.worker = worker;
        }

        private void Button2_Click(object sender, RoutedEventArgs e)
        {
            if (add_flag == 0)
            {
                add_flag = 1;
                worker.DoWork += (s, args) =>
                {
                    for (int i = 1; i <= 100; i++)
                    {
                        worker.ReportProgress(i);
                        Thread.Sleep(50);
                    }
                };

                worker.RunWorkerCompleted += (s, args) =>
                {
                    MessageBox.Show("Task finished!");
                };
            }

            worker.RunWorkerAsync();
        }
    }
}

? ? ? ? 细心的同学应该还发现了,代码中还多了一个add_flag,这主要是为了防止在子窗口中重复按钮之后,反复进行进度条的更新。

5、编译和测试

? ? ? ? 编译无误之后,就可以开始测试。测试的方式和之前说的一样,首先打开主窗口,利用按钮Button1再打开子窗口,进一步单击子窗口中的按钮Button2,如果发现主窗口的中的进度条可以正常更新,那说明一切流程都是ok的,否则就要去check一下问题,同时debug一下软件失败的原因。

文章来源:https://blog.csdn.net/feixiaoxing/article/details/135183360
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。