C# 打开一个表单,然后用另一个方法关闭它

C# 打开一个表单,然后用另一个方法关闭它,c#,winforms,multithreading,C#,Winforms,Multithreading,我对C#还是个新手,对一些事情有点意见。我相信线程可能是答案,但这只是我在寻找解决方案时听到的一个流行词 namespace Test { public partial class Form1 : Form { private Form2 form2; public Form1() { InitializeComponent(); form2 = new Form2();

我对C#还是个新手,对一些事情有点意见。我相信线程可能是答案,但这只是我在寻找解决方案时听到的一个流行词

namespace Test { public partial class Form1 : Form { private Form2 form2; public Form1() { InitializeComponent(); form2 = new Form2(); } private void runCheck(object source, System.Timers.ElapsedEventArgs e) { form2.ShowDialog(); form2.TopMost = true; } private void runCheckFalse() { form2.Hide(); } } 名称空间测试 { 公共部分类Form1:Form { 私人表格2表格2; 公共表格1() { 初始化组件(); form2=新的form2(); } 私有void运行检查(对象源,System.Timers.ElapsedEventArgs e) { form2.ShowDialog(); form2.TopMost=真; } 私有void runCheckFalse() { form2.Hide(); } } 这只是我的剥离应用程序的一个快速代码片段,但是在尝试此操作时,我得到一个错误:跨线程操作无效:从创建控件“Form2”的线程以外的线程访问控件“Form2”


另外,我使用form2.TopMost=true;尝试在所有其他内容之上打开窗口,但这通常会在Visual Studio etc的后面结束。WinForm控件只能从UI线程更新。它提供了许多方法来确保在UI线程上进行更新。这是一篇很长的文章,但是值得一读。如果你没有时间去读的话,快速而肮脏的方法是第一个


Erick

WinForm控件只能从UI线程更新。它提供了许多方法来确保更新发生在UI线程上。这是一篇很长的文章,但值得一读。如果您没有时间阅读,快速而肮脏的方法是第一种


Erick

您需要使用
Invoke
来处理来自不同线程的表单

下面是一篇很好的文章,介绍如何从多个线程使用Windows窗体控件:

试试这个:

namespace Test
{
    public partial class Form1 : Form
    {
        private Form2 form2;

        public Form1()
        {
            InitializeComponent();
            form2 = new Form2();
        }

        private void runCheck(object source, System.Timers.ElapsedEventArgs e)
        {
            if (form2.InvokeRequired)
            {
                form2.Invoke(new EventHandler(delegate { form2.ShowDialog(); form2.TopMost = true; }));
            }
            else
            {
                form2.ShowDialog(); 
                form2.TopMost = true;
            }
        }

        private void runCheckFalse()
        {
            if(form2.InvokeRequired)
            {
                form2.Invoke(new EventHandler(delegate { form2.Hide(); }));
            }
            else
            {
                form2.Hide();
            }
        }
    }
}

您需要使用
Invoke
,以便从不同的线程处理表单

下面是一篇很好的文章,介绍如何从多个线程使用Windows窗体控件:

试试这个:

namespace Test
{
    public partial class Form1 : Form
    {
        private Form2 form2;

        public Form1()
        {
            InitializeComponent();
            form2 = new Form2();
        }

        private void runCheck(object source, System.Timers.ElapsedEventArgs e)
        {
            if (form2.InvokeRequired)
            {
                form2.Invoke(new EventHandler(delegate { form2.ShowDialog(); form2.TopMost = true; }));
            }
            else
            {
                form2.ShowDialog(); 
                form2.TopMost = true;
            }
        }

        private void runCheckFalse()
        {
            if(form2.InvokeRequired)
            {
                form2.Invoke(new EventHandler(delegate { form2.Hide(); }));
            }
            else
            {
                form2.Hide();
            }
        }
    }
}

您可以通过以下方式修改runCheckFalse方法-这是Windows窗体的标准模式:

private void runCheckFalse()      
{       
    if(InvokeRequired)
      {
            BeginInvoke(new MethodInvoker(runCheckFalse));
            return;
      }                    
    form2.Hide();  
}
实际上,这样做是为了检查我们是否在GUI线程上运行(“if InvokeRequired”)。如果我们没有,我们在GUI线程上调用自己并立即返回。如果我们在GUI线程上运行,那么我们不需要做任何事,只需像正常一样继续使用该方法

如果需要使用参数:

private void runCheckFalse(bool someParameter)      
{       
    if(InvokeRequired)
      {
            BeginInvoke(new MethodInvoker(() => { runCheckFalse(someParameter);}));
            return;
      }                    
    form2.Hide();  
}

您可以通过以下方式修改runCheckFalse方法-这是Windows窗体的标准模式:

private void runCheckFalse()      
{       
    if(InvokeRequired)
      {
            BeginInvoke(new MethodInvoker(runCheckFalse));
            return;
      }                    
    form2.Hide();  
}
实际上,这样做是为了检查我们是否在GUI线程上运行(“if InvokeRequired”)。如果我们没有,我们在GUI线程上调用自己并立即返回。如果我们在GUI线程上运行,那么我们不需要做任何事,只需像正常一样继续使用该方法

如果需要使用参数:

private void runCheckFalse(bool someParameter)      
{       
    if(InvokeRequired)
      {
            BeginInvoke(new MethodInvoker(() => { runCheckFalse(someParameter);}));
            return;
      }                    
    form2.Hide();  
}


您的项目中是否有线程代码?错误发生在哪一行?是否使用MDI表单?请尝试改用System.Windows.Forms.Timer,因为您的异常可能是在这里引发的(WindowsForms Timer Appead事件将发生在GUI线程上,System.Timers在后台线程上)。否则,请在InvokeRequired和BeginInvoke上读取。@BobHorn错误在form2.Hide()下的runCheckFalse上抛出;项目中是否有线程代码?错误发生在哪一行?是否使用MDI表单?请尝试改用System.Windows.Forms.Timer,因为可能是在这里引发了异常(WindowsForms timer Appead事件将发生在GUI线程、后台线程上的System.Timers上)。否则,在InvokeRequired和BeginInvoke上读取。@BobHorn错误将在form2.Hide()下的runCheckFalse上抛出;太好了!非常感谢!代码段工作得非常好,我添加了InvokeRequired语句,后面是一个else,它在没有调用的情况下运行这些部分。不过,我将进一步阅读原因等:)根据@dash的回答,我建议使用BeginInvoke,而不是Invoke。如果存在其他跨线程通信点,Invoke可能会导致死锁。只有当您需要等待操作完成后再继续时,才需要Invoke,而BeginInvoke根本不会阻塞。太好了!非常感谢!代码snippet工作得很好,我添加了InvokeRequired语句,后面是一个运行没有调用的部分的else。不过,我将进一步阅读原因等:)根据@dash的回答,我建议使用BeginInvoke,而不是Invoke。如果存在其他跨线程通信点,Invoke可能会导致死锁s、 只有在您需要等待操作完成后才能继续操作时,才需要调用,而BeginInvoke将完全不会阻塞。感谢Erick的精彩博文,Erick将进一步了解这一点,因为它是一块宝石!感谢Erick的精彩博文,Erick将进一步了解这一点,因为它是一块宝石!这是一个很棒的想法!但我已经将更长的代码,谢谢!@MattClements这是更容易维护的“勇气”但是,从所有这些中得到的最重要的教训是阅读为什么这一切都是必要的:-)玩得开心!这是一个很棒的主意!但是已经输入了更长的代码,无论如何谢谢!@MattClements这作为“勇气”更容易维护但是,从这一切中得到的最重要的教训是,仔细阅读为什么这一切都是必要的:-)玩得开心!