C# - 从线程更新 windows 窗体元素

     2023-04-13     77

关键词:

【中文标题】C# - 从线程更新 windows 窗体元素【英文标题】:C# - Updating windows forms elements from thread 【发布时间】:2019-06-29 03:41:59 【问题描述】:

我目前正在创建一个程序来将笔记本电脑备份到 U 盘。我创建了一个从中调用方法的类。然后我通过一个单独的线程开始实际的备份。目前,我正在尝试通过此线程更改文本框和进度条。但是,它总是只立即显示第一个更改,而只有在程序运行后才显示其他进度。 我从互联网上尝试了几种解决方案,但到目前为止没有任何效果。也许有人在这里有解决方案。

    backup sales_backup = new backup();

    //Start Backup Button
    private void backup_button_Click(object sender, EventArgs e)
    
        Thread backupprocess = new Thread(new 
        ThreadStart(sales_backup.backup_start));
        backupprocess.Start();
    

    //Backup Function
        public void backup_start()
        
            files_to_copy = 0;
            files_copied = 0;

            var principalForm = System.Windows.Forms.Application.OpenForms.OfType<Form1>().FirstOrDefault();

            if (principalForm.drive_selector.SelectedItem != null)
            
                //Set Parameters
                principalForm.backup_button.Visible = false;
                error_copy = false;
                error_message = "";
                device_removed = false;

                //Fill variables
                string temp = principalForm.drive_selector.SelectedItem.ToString();
                temp = regex_matching_return_match(temp, @"[A-Z,a-z](:\\)");
                backup_device = temp;

                //Set Backup device size
                for (int i = 0; i < backup_devices_list.Count; i++)
                
                    if (backup_devices_list[i].backup_device_name == temp)
                    
                        backup_device_size = backup_devices_list[i].device_size;
                        file_system = backup_devices_list[i].file_system;
                        double temp_free = calculate_GB(backup_devices_list[i].device_free_space.ToString());
                        device_free_space = temp_free;
                        break;
                    
                

                //If no device is initialized
                if (backup_device == null || backup_device_size == 0)
                
                    write_to_textbox(get_create_usb_instance_error(), "red");
                
                else //If select ist successfull
                
                    //Get Backup size
                    get_size();
                    if (backup_size < device_free_space)
                    
                        backup_path_target = backup_device + "\\Backup\\";
                        Directory.CreateDirectory(backup_path_target);

                        //Get file count
                        get_file_count();

                        //Create Copy job
                        for (int i = 0; i < backup_path_source.Length; i++)
                        
                            string backup_path_s = backup_path_source[i] + "\\";
                            string backup_path_t = backup_path_target + backup_path_target_folders[i] + "\\";
                            copy_function(backup_path_s, backup_path_t);
                            int progress = return_progress();
                            TextBox test = principalForm.textBox2;
                            ProgressBar progress_bar = principalForm.progressBar1;
                            //Delegate Textbox
                            if (test.InvokeRequired)
                            
                                test.Invoke(new Action(() => test.Text = "Copying: " + backup_path_t));
                            
                            else
                            
                                test.Text = "Copying: " + backup_path_t;
                            
                            //Delegate Progressbar
                            if (progress_bar.InvokeRequired)
                            
                                test.Invoke(new Action(() => progress_bar.Value = progress));
                            
                            else
                            
                                progress_bar.Value = progress;
                            
                        

【问题讨论】:

您无法从后台线程更新 UI。您也不需要需要Invoke,如果您使用async/awaitProcess&lt;T&gt; 类向其他线程报告进度 如果您使用Task.Runasync/await,则不必使用Invoke().。如果 UI 线程很忙,则调用自身 blocks。您也应该将 UI 与文件处理代码分开 - 当您可以将驱动器等作为方法参数传递时,无需像这样访问主窗体 【参考方案1】:

确保您从正确的线程进行更新。 GUI 只能从它自己的线程更新。更多here。

【讨论】:

【参考方案2】:

我无法对此进行测试,但它至少应该可以帮助您到达那里:

private void InvokeIfRequired<C>(C control, Action<C> action) where C : Control

    if (control.InvokeRequired)
    
        control.Invoke((Action)(() => action(control)));
    
    else
    
        action(control);
    


private void backup_button_Click(object sender, EventArgs e)

    var principalForm = System.Windows.Forms.Application.OpenForms.OfType<Form1>().FirstOrDefault();
    if (principalForm.drive_selector.SelectedItem != null)
    
        principalForm.backup_button.Visible = false;

        string temp = principalForm.drive_selector.SelectedItem.ToString();

        TextBox test = principalForm.textBox2;
        ProgressBar progress_bar = principalForm.progressBar1;

        Action<string> updateTest = t => this.InvokeIfRequired<TextBox>(test, c => c.Text = t);
        Action<int> updateProgress = v => this.InvokeIfRequired<ProgressBar>(progress_bar, c => c.Value = v);

        Thread backupprocess = new Thread(new ThreadStart(() => sales_backup.backup_start(temp, updateTest, updateProgress)));
        backupprocess.Start();
    


//Backup Function
public void backup_start(string temp, Action<string> updateTest, Action<int> updateProgress)

    files_to_copy = 0;
    files_copied = 0;

    //Set Parameters

    error_copy = false;
    error_message = "";
    device_removed = false;

    //Fill variables
    temp = regex_matching_return_match(temp, @"[A-Z,a-z](:\\)");
    backup_device = temp;

    //Set Backup device size
    for (int i = 0; i < backup_devices_list.Count; i++)
    
        if (backup_devices_list[i].backup_device_name == temp)
        
            backup_device_size = backup_devices_list[i].device_size;
            file_system = backup_devices_list[i].file_system;
            double temp_free = calculate_GB(backup_devices_list[i].device_free_space.ToString());
            device_free_space = temp_free;
            break;
        
    

    //If no device is initialized
    if (backup_device == null || backup_device_size == 0)
    
        write_to_textbox(get_create_usb_instance_error(), "red");
    
    else //If select ist successfull
    
        //Get Backup size
        get_size();
        if (backup_size < device_free_space)
        
            backup_path_target = backup_device + "\\Backup\\";
            Directory.CreateDirectory(backup_path_target);

            //Get file count
            get_file_count();

            //Create Copy job
            for (int i = 0; i < backup_path_source.Length; i++)
            
                string backup_path_s = backup_path_source[i] + "\\";
                string backup_path_t = backup_path_target + backup_path_target_folders[i] + "\\";
                copy_function(backup_path_s, backup_path_t);
                int progress = return_progress();

                //Delegate Textbox
                updateTest("Copying: " + backup_path_t);

                //Delegate Progressbar
                updateProgress(progress);
            
        
    

【讨论】:

【参考方案3】:

您是否尝试过使用progress_bar.Invoke((MethodInvoker)(() =&gt; progress_bar.Value = progress));

【讨论】:

这不是答案。它应该被删除。请赚取 50 个代表点来发布 cmets。 更改委托类型不会更改调用的内容。代码可以是progress_bar.Invoke(() =&gt; progress_bar.Value = progress);

在 C# 中使用多线程屏蔽/过滤图像(Windows 窗体应用程序)

】在C#中使用多线程屏蔽/过滤图像(Windows窗体应用程序)【英文标题】:UsingMultithreadingtomask/filteraimageinC#(windowsformapplication)【发布时间】:2018-10-1606:19:36【问题描述】:我目前正在尝试学习如何在C#中使用多线程,但我真的很难... 查看详情

如何在 Windows 窗体中分离 UI 线程和进程线程

】如何在Windows窗体中分离UI线程和进程线程【英文标题】:HowtoseparateUIthreadandprocessthread,inWindowsForms【发布时间】:2021-05-1903:28:30【问题描述】:我使用C#开发表单应用程序以从光谱仪设备收集数据。当我设置连续采集时,在采集... 查看详情

C# windows 窗体 - 关于跨线程事件的问题

】C#windows窗体-关于跨线程事件的问题【英文标题】:C#windowsforms-questionaboutcrossthreadevents【发布时间】:2019-11-0611:51:00【问题描述】:假设我创建了一个类名myClass并且这个类有一个名为myValue的任何类型的属性,没关系,比如:cla... 查看详情

c# - 如何在 Windows 窗体中排列元素,如 Windows 资源管理器

】c#-如何在Windows窗体中排列元素,如Windows资源管理器【英文标题】:c#-HowtoarrangeelementsinWindowsFormlikeWindowsExplorer【发布时间】:2013-10-1609:06:27【问题描述】:我正在填充一个自制的Windows资源管理器,它模拟MicrosoftWindows资源管理... 查看详情

C# - 从 Windows 服务启动 Windows 窗体 [重复]

】C#-从Windows服务启动Windows窗体[重复]【英文标题】:C#-LaunchaWindowsFormfromaWindowsService[duplicate]【发布时间】:2018-05-1407:45:29【问题描述】:我正在开发一个监视消息队列(RabbitMQ)的Windows服务。每当有消息在消息队列中排队时,Window... 查看详情

从 C# Windows 窗体内部调用的 Bash 脚本

】从C#Windows窗体内部调用的Bash脚本【英文标题】:BashScriptcalledfrominsideC#WindowsForms【发布时间】:2022-01-1714:14:05【问题描述】:我正在尝试从Windows窗体应用程序中运行bash脚本。我的代码如下所示://CommandStringstringflashNVS="c:\\\\msys... 查看详情

从 C# Windows 窗体调用 PHP Web 服务

】从C#Windows窗体调用PHPWeb服务【英文标题】:CallingPHPWeb-ServicefromC#WindowsForm【发布时间】:2019-05-0701:14:07【问题描述】:我正在尝试将C#Windows窗体的用户名、密码和软件令牌号验证为MySQL数据库中的值。我的C#代码:privatevoidbtnlogi... 查看详情

从 C# 中的外部 DLL 访问 windows 窗体控件

】从C#中的外部DLL访问windows窗体控件【英文标题】:AccesswindowsformscontrolsfromexternalDLLsinC#【发布时间】:2019-02-1111:18:33【问题描述】:这是我在这里的第一个主题,我没有找到任何类似的主题,所以我尽量描述我的问题:我的公... 查看详情

如何使用 c# 从 Windows 窗体向用户显示默认的 Windows 身份验证提示?

】如何使用c#从Windows窗体向用户显示默认的Windows身份验证提示?【英文标题】:Howtoshowtheuserthedefaultwindowsauthenticationpromptfromawindowsformusingc#?【发布时间】:2011-10-1218:33:44【问题描述】:我认为这将是一种非常常见的做法,但我很... 查看详情

如何制作一个 C# Windows 窗体应用程序,为 Windows 应用商店转换,从 Windows 开始

】如何制作一个C#Windows窗体应用程序,为Windows应用商店转换,从Windows开始【英文标题】:HowtomakeaC#WindowsFormsapp,convertedfortheWindowsStore,startwithWindows【发布时间】:2019-11-1219:48:16【问题描述】:我创建了一个名为“DesktopWebTiles”的W... 查看详情

计时器每秒触发一次并更新 GUI(C# Windows 窗体)

】计时器每秒触发一次并更新GUI(C#Windows窗体)【英文标题】:TimerfiringeverysecondandupdatingGUI(C#WindowsForms)【发布时间】:2020-02-1419:43:27【问题描述】:我有一个Windows窗体应用程序,我需要一个计时器工作90秒,并且在它过去后每... 查看详情

跨线程更新windows窗体

delegatevoidupdateLabelTextDelegate(stringnewText);privatevoidupdateLabelText(stringnewText){if(lblMessage.InvokeRequired)//lblMessageUIID{//thisisworkerthreadupdateLabelTextDelegatedel=newupdateLabelTextDelegate(updateLabelText);lblMessage.Invoke(del,ne... 查看详情

C# Windows 窗体 - 带有事件的不可见元素(单击和 MouseEnter/Leave)

】C#Windows窗体-带有事件的不可见元素(单击和MouseEnter/Leave)【英文标题】:C#WindowsForms-InvisibleElementwithEvents(ClickandMouseEnter/Leave)【发布时间】:2021-12-2807:29:47【问题描述】:我在我的项目中将几个标签直接相邻排列。现在,当我... 查看详情

如何在 Windows 窗体 C# 中单击按钮通过 DataGridView 更新数据库中的布尔字段

】如何在Windows窗体C#中单击按钮通过DataGridView更新数据库中的布尔字段【英文标题】:HowtoupdateBooleanfieldindatabasethroughDataGridViewbybuttonclickinWindowsFormC#【发布时间】:2017-05-1401:54:02【问题描述】:DataGridView显示我的数据库表中的值... 查看详情

从 c# windows 窗体中的图像中读取文本

】从c#windows窗体中的图像中读取文本【英文标题】:Readingtextfromimagesinc#windowsform【发布时间】:2015-12-2400:41:49【问题描述】:我有一个Windows窗体应用程序,我将在其中将读取车牌文本的图像添加到文本块中。我可以使用哪种dll... 查看详情

C# Windows 窗体使用 OracleDataAdapter 从系统数据表向 Oracle 表插入行

】C#Windows窗体使用OracleDataAdapter从系统数据表向Oracle表插入行【英文标题】:C#WindowsFormusingOracleDataAdaptertoinsertrowstoaOracleTablefromaSystemDataTable【发布时间】:2017-04-1222:25:10【问题描述】:我正在编写一个填充DataTable的Windows窗体,我... 查看详情

C# Windows 窗体半透明

】C#Windows窗体半透明【英文标题】:C#WindowsFormssemi-opacity【发布时间】:2018-12-0308:41:05【问题描述】:我已经阅读了很多关于C#中Windows窗体的不透明度/透明度的主题,但这不是我想要的效果。我希望Form是100%透明的,但Panel的透... 查看详情

如何从文本框(windows窗体)检查主键是不是存在于我的数据库中,c#

】如何从文本框(windows窗体)检查主键是不是存在于我的数据库中,c#【英文标题】:Howtocheckiftheprimarykeyexistsinmydatabasefromatextbox(windowsform),c#如何从文本框(windows窗体)检查主键是否存在于我的数据库中,c#【发布时间】:2015-11... 查看详情