C# 动态更新UI时执行线程

C# 动态更新UI时执行线程,c#,C#,我想弄清楚这件事的时候最糟糕了。说到穿线,我很困惑 我想做的是在函数中延迟1次暂停,然后继续函数,直到出现另一次1秒的暂停,最后完成函数 public partial class SplashScreen : Form { public SplashScreen() { InitializeComponent(); // initalize splash screen DatabaseStatus(); // set database connec

我想弄清楚这件事的时候最糟糕了。说到穿线,我很困惑

我想做的是在函数中延迟1次暂停,然后继续函数,直到出现另一次1秒的暂停,最后完成函数

public partial class SplashScreen : Form
{
    public SplashScreen()
    {
        InitializeComponent(); // initalize splash screen
        DatabaseStatus(); // set database connection
        getUserInfo(); // get user information
        showInfo(); // show app information on splash screen
        System.Threading.Thread wa = new System.Threading.Thread(new System.Threading.ThreadStart(checkUser));
        wa.IsBackground = true;
        wa.Start();
    }

    void checkUser()
    { 
        if (RegisteredUser)
        {
            richTextBox1.Text += "Loading user settings...";  // SHOW THIS TEXT AND WAIT 1 SECOND UNTIL NEXT
            System.Threading.Thread.Sleep(1000); 

            if (DATABASE_CONNECTION)
            {
                richTextBox1.Text += "Loging on...";
                // WAIT AGAIN 1 SEC AND CONTINUE///
                LoginCheck login = new LoginCheck(USER_NAME, PASSWORD);
                if (login.LOGIN_SUCESS)
                {
                    richTextBox1.Text += "Sucess!";
                   // SHOW THIS TEXT AND WAIT 1 SEC UNTIL SPLASH SCREEN FADE OUT//
                    //MessageBox.Show(login.HASH);
                    opac.Interval = 12;
                    opac.Start();
                    opac.Tick += new EventHandler(dec);
                }
                else
                {
                    MessageBox.Show(login.HASH);
                }
            }
        }
        else
        {
            richTextBox1.Text += "Not user profile found...";
            // ask user to register
        }
    }
}
我把评论放在我希望线程暂停并继续的地方

有人有什么意见吗


谢谢

您需要使用Invoke()请参见

我建议您在单独的后台工作线程中执行所有操作,并更新UI中的状态。这使得用户界面更快,应用程序更可靠


首先,在使用WinForms(以及WPF/Silverlight…对吗?)时,您必须知道,除了创建表单/控件的原始线程之外,您不能也不应该从任何其他线程操作UI元素

如果需要执行异步工作,则需要使用
Invoke
BeginInvoke
将UI工作转换回窗体或控件的线程。此外,考虑使用委托(<代码>方法调用器>代码>很方便),而不是创建自己的线程。 此外,您需要在
Load
事件期间或之后启动异步工作,否则您的逻辑将在表单显示之前开始执行(请参见下面的示例)

我拿了你的例子,并把它放进了我自己的一个简化示例中

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        RegisteredUser = true;
        DATABASE_CONNECTION = true;


    }

    private void UpdateStatus(string message)
    {
        BeginInvoke(new MethodInvoker(() => richTextBox1.Text += message));
    }

    private void CheckUser()
    {
        if (RegisteredUser)
        {
            UpdateStatus("Loading user settings..."); // SHOW THIS TEXT AND WAIT 1 SECOND UNTIL NEXT
            System.Threading.Thread.Sleep(1000);

            if (DATABASE_CONNECTION)
            {
                UpdateStatus("Logging on...");
                //// WAIT AGAIN 1 SEC AND CONTINUE///
                //LoginCheck login = new LoginCheck(USER_NAME, PASSWORD);
                if (true)//login.LOGIN_SUCESS)
                {
                    UpdateStatus("Success!");
                    // SHOW THIS TEXT AND WAIT 1 SEC UNTIL SPLASH SCREEN FADE OUT//
                    //MessageBox.Show(login.HASH);
                    //opac.Interval = 12;
                    //opac.Start();
                    //opac.Tick += new EventHandler(dec);
                }
                else
                {
                    //MessageBox.Show(login.HASH);
                }
            }
        }
        else
        {
            UpdateStatus("No user profile found.");
            // ask user to register
        }
    }

    protected bool DATABASE_CONNECTION { get; set; }

    protected bool RegisteredUser { get; set; }

    private void Form1_Load(object sender, EventArgs e)
    {
        var invoker = new MethodInvoker(CheckUser);
        invoker.BeginInvoke(null, null);
    }
}
正如您所看到的,我使用了一种方法,比如
UpdateStatus
,来为我处理UI,确保它在UI线程上完成。您可以使用任意数量的类似方法在UI中执行其他操作,例如触发表单淡出或其他任何操作

你甚至不应该在UI线程外显示消息框;使用类似的方法安全地调用这些函数(同样,对于调试,只需
Debug.WriteLine
即可将消息写入调试器,而不必到处弹出消息框)。

公共部分类SplashScreen:Form
{      
bool数据库连接;
bool RegisteredUser;//如果用户已注册
字符串用户名;
字符串密码;
双直线x=0.01;
对话结果;
自定义con=新自定义();
定时器opac=新定时器();
公共屏幕()
{
InitializeComponent();//初始化初始屏幕
DatabaseStatus();//设置数据库连接
getUserInfo();//获取用户信息
showInfo();//在启动屏幕上显示应用程序信息
}
私有void UpdateStatus(字符串消息)
{
BeginInvoke(新方法调用程序(()=>richTextBox1.Text+=message+Environment.NewLine));
}
void checkUser()
{
UpdateStatus(“加载用户设置…”);
if(RegisteredUser)
{
UpdateStatus(“用户”+用户名+“已找到”);
if(数据库连接)
{
UpdateStatus(“登录…”);
登录检查登录=新登录检查(用户名、密码);
if(login.login\u success)
{
UpdateStatus(“成功!加载”+con.AppTitle()+“…请稍候”);
//UpdateStatus(login.HASH);从网站返回哈希字符串
FadesFlash();//开始淡出窗体
}
其他的
{
UpdateStatus(“登录时出错。”);
}
}
其他的
{
UpdateStatus(“未找到数据库连接”);
}
}
其他的
{
UpdateStatus(“未找到用户”);
Reg();//登记表
}
}
私有void fadeSplash()
{
opac.间隔=12;
opac.Tick+=新事件处理程序(12月);
opac.Start();
}
私有void dec(对象发送方,事件参数e)
{
this.Opacity-=LIN_x;
如果(此不透明度<0.04)
{
opac.Stop();
this.Hide();
main open=new main();//启动应用程序
open.Show();
}
}
}

下面是在MethodInvoke期间fade方法不会触发的代码,谢谢您的输入。然而,我仍然会遇到这样一个问题:在表单显示之前,逻辑已经完成了。通常情况下,表单几乎需要1秒才能完全加载。使用此方法,表单需要5秒的时间加载最后一条UpdateStatus消息。我想做的是创建一个启动屏幕,并在文本框中显示状态更新。我必须查看您的更新代码。也许你错过了我指定的一个变化。我创建的示例正是我所解释的。在玩了一会儿并查看了你给mem的链接后,我终于让它工作了!您仍然可以从非UI线程显示消息框和表单
BackgroundWorker
似乎不适合此任务,因为至少有一种情况需要在异步线程中暂停执行并提示用户输入,然后将该输入返回异步线程并继续工作
BackgroundWorker
不支持此操作;您开始工作,启动进度更新,然后在工作结束或取消时启动事件。你需要更具互动性的东西,这就是为什么我给了你答案,那是我的错。花费这么长时间的原因是我在另一台电脑上工作,它的windows主机没有正确解析我的专用服务器,导致数据库连接失败。。。我不得不暂停。不管怎样,我重新尝试了你的方法,做了一些小的调整,效果非常好。我的问题是,什么时候应该使用Invoke,什么时候应该使用BackgroundWorker?另外,如何停止线程?例如,如果找不到用户,我希望它停止并开始提示?谢谢,如果可以的话,阿加尼会选择
BackgroundWorker
,因为它已经为您完成了,而且非常容易使用。然而,
public partial class SplashScreen : Form
{      
    bool DATABASE_CONNECTION;
    bool RegisteredUser; // if user has been registered
    string USER_NAME;
    string PASSWORD;
    double LIN_x = 0.01;

    DialogResult result;
    custom con = new custom();
    Timer opac = new Timer();

    public SplashScreen()
    {
        InitializeComponent(); // initalize splash screen
        DatabaseStatus(); // set database connection
        getUserInfo(); // get user information
        showInfo(); // show app information on splash screen
    }

    private void UpdateStatus(string message)
    {
        BeginInvoke(new MethodInvoker(() => richTextBox1.Text += message + Environment.NewLine));
    }

    void checkUser()
    {
        UpdateStatus("Loading user settings..."); 
        if (RegisteredUser)
        {
            UpdateStatus("User " + USER_NAME + " found." );
            if (DATABASE_CONNECTION)
            {
                UpdateStatus("Logging on..."); 
                LoginCheck login = new LoginCheck(USER_NAME, PASSWORD);
                if (login.LOGIN_SUCESS)
                {
                    UpdateStatus("Success! Loading " + con.AppTitle() + "...please wait");

                    //UpdateStatus(login.HASH); return hash string from web site
                    fadeSplash(); // begin fade out of form
                }
                else
                {
                    UpdateStatus("There was an error logging in."); 

                }
            }
            else
            {
                UpdateStatus("No database connection found."); 

            }
        }
        else
        {
            UpdateStatus("No user found"); 

            Reg(); // Registration form
        }
    }

    private void fadeSplash()
    {
        opac.Interval = 12;
        opac.Tick += new EventHandler(dec);
        opac.Start();
    }

    private void dec(object sender, EventArgs e)
    {
        this.Opacity -= LIN_x;
        if (this.Opacity < 0.04)
        {
            opac.Stop();
            this.Hide();
            main open = new main(); // start application
            open.Show();
        }
    }
}