Visual studio Visual Studio调试器的线程问题

Visual studio Visual Studio调试器的线程问题,visual-studio,debugging,multithreading,Visual Studio,Debugging,Multithreading,我有一个应用程序,设计为在网络上运行。这意味着此应用程序的初始运行可能需要一段时间。所以我一直在制作一个闪屏来美化这个过程 它使用线程通过静态方法显示表单。我仍然是一个线程新手,所以当我遇到错误时,我有点困惑是什么和为什么 事实证明,当我在VisualStudio调试器之外运行代码时,它是非常好的。但当我从调试器内部运行它时,会出现异常: 跨线程操作无效:从创建控件“”的线程以外的线程访问该控件“” 这是我的班级: using System; using System.Collections.G

我有一个应用程序,设计为在网络上运行。这意味着此应用程序的初始运行可能需要一段时间。所以我一直在制作一个闪屏来美化这个过程

它使用线程通过静态方法显示表单。我仍然是一个线程新手,所以当我遇到错误时,我有点困惑是什么和为什么

事实证明,当我在VisualStudio调试器之外运行代码时,它是非常好的。但当我从调试器内部运行它时,会出现异常:

跨线程操作无效:从创建控件“”的线程以外的线程访问该控件“”

这是我的班级:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace MyApp
{
    public partial class SplashScreen : Form
    {
        private static double OPACITY_INCREMENT = .05;

        private static SplashScreen _splashForm;
        private static SplashScreen SplashForm
        {
            get { return SplashScreen._splashForm; }
            set { SplashScreen._splashForm = value; }
        }

        private static void ShowForm()
        {
            SplashScreen.SplashForm = new SplashScreen();            
            Application.Run(SplashScreen.SplashForm);
        }

        internal static void CloseForm()
        {
            if (SplashScreen.SplashForm != null &&
                SplashScreen.SplashForm.IsDisposed == false)
            {
                // Make it start going away.
                OPACITY_INCREMENT = -OPACITY_INCREMENT;
            }

            SplashScreen.SplashThread = null;
            SplashScreen.SplashForm = null;
        }

        private static Thread _splashThread;
        private static Thread SplashThread
        {
            get { return SplashScreen._splashThread; }
            set { SplashScreen._splashThread = value; }
        }

        internal static void ShowSplashScreen()
        {
            if (SplashScreen.SplashForm != null)
            {
                return;
            }

            SplashScreen.SplashThread = new Thread(new ThreadStart(SplashScreen.ShowForm));
            SplashScreen.SplashThread.IsBackground = true;
            SplashScreen.SplashThread.SetApartmentState(ApartmentState.STA);
            SplashScreen.SplashThread.Start();
        }

        public SplashScreen()
        {
            InitializeComponent();
            this.timerFade.Start();
            this.ClientSize = this.BackgroundImage.Size;
        }

        private void SplashScreen_Load(object sender, EventArgs e)
        {
        }

        private void timerFade_Tick(object sender, EventArgs e)
        {
            if (OPACITY_INCREMENT > 0)
            {
                if (this.Opacity < 1)
                    this.Opacity += OPACITY_INCREMENT;
            }
            else
            {
                if (this.Opacity > 0)
                    this.Opacity += OPACITY_INCREMENT;
                else
                {
                    this.Invoke(new MethodInvoker(this.TryClose));
                }
            }
        }

        private void TryClose()
        {
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new MethodInvoker(this.TryClose));
            }

            this.Close();
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用系统组件模型;
使用系统数据;
使用系统图;
使用System.Linq;
使用系统文本;
使用System.Windows.Forms;
使用系统线程;
名称空间MyApp
{
公共部分类SplashScreen:表单
{
私有静态双不透明度_增量=.05;
专用静态SplashScreen\u splashForm;
专用静态SplashScreen SplashForm
{
获取{返回SplashScreen.\u splashForm;}
设置{SplashScreen.\u splashForm=value;}
}
私有静态void ShowForm()
{
SplashScreen.SplashForm=新的SplashScreen();
Application.Run(SplashScreen.SplashForm);
}
内部静态void CloseForm()
{
如果(SplashScreen.SplashForm!=null&&
SplashScreen.SplashForm.IsDisposed==false)
{
//让它开始消失。
不透明度增量=-不透明度增量;
}
SplashScreen.SplashThread=null;
SplashScreen.SplashForm=null;
}
私有静态线程\u splash线程;
私有静态线程
{
获取{返回SplashScreen.\u splashThread;}
设置{SplashScreen.\u splashThread=value;}
}
内部静态无效显示屏幕()
{
if(SplashScreen.SplashForm!=null)
{
回来
}
SplashScreen.SplashThread=新线程(新线程开始(SplashScreen.ShowForm));
SplashScreen.SplashThread.IsBackground=true;
SplashScreen.splashtread.SetApartmentState(ApartmentState.STA);
SplashScreen.splasthread.Start();
}
公共屏幕()
{
初始化组件();
this.timerFade.Start();
this.ClientSize=this.BackgroundImage.Size;
}
私有无效SplashScreen_加载(对象发送器、事件参数e)
{
}
私有void timerFade_Tick(对象发送方,事件参数e)
{
如果(不透明度增量>0)
{
如果(此不透明度<1)
此.Opacity+=不透明度增量;
}
其他的
{
如果(this.Opacity>0)
此.Opacity+=不透明度增量;
其他的
{
Invoke(newmethodinvoker(this.TryClose));
}
}
}
私有void TryClose()
{
if(this.invokererequired)
{
this.BeginInvoke(新方法调用程序(this.TryClose));
}
这个。关闭();
}
}
}
我正在从Program.cs Main方法内部调用启动屏幕

namespace CIMA
{
    static class Program
    {
// <summary>
        ///     The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {            
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            SplashScreen.ShowSplashScreen();

            // Code omitted for brevity.

            SplashScreen.CloseForm();

            // Code omitted for brevity.
        }
    }
}
名称空间CIMA
{
静态类程序
{
// 
///应用程序的主要入口点。
/// 
[状态线程]
静态void Main(字符串[]参数)
{            
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
SplashScreen.ShowSplashScreen();
//为简洁起见,省略了代码。
SplashScreen.CloseForm();
//为简洁起见,省略了代码。
}
}
}
我希望能够从我的其他表单中调用SplashScreen.CloseForm(),但我还没有尝试过。我不知道调试器在干什么

我错过什么了吗?或者,如果启动屏幕正在调试器中运行,是否必须禁用它


如果是这样的话,有什么好办法?如果可能的话,我希望避免使用编译符号,因为我讨厌跟踪它们。

在.NET中,不允许从未创建控件的线程访问控件。在代码中,看起来有一个单独的线程正在创建启动窗体,而主线程试图关闭启动窗体

我建议您采用另一种方法:在主线程中创建splash表单,并让单独的线程对其进行更新

另外,在您的
TryClose
方法中,在调用
BeginInvoke
之后缺少一个返回


但是,您可以查看启动屏幕的其他实现。有一些现成的,例如

好的-我找到了一个解决办法

我使用语句添加了以下内容:

using System.Diagnostics;
。。。并将ShowSplashScreen()方法更改如下:

    internal static void ShowSplashScreen()
    {
        if (!Debugger.IsAttached)
        {
            if (SplashScreen.SplashForm != null)
            {
                return;
            }

            SplashScreen.SplashThread = new Thread(new ThreadStart(SplashScreen.ShowForm));
            SplashScreen.SplashThread.IsBackground = true;
            SplashScreen.SplashThread.SetApartmentState(ApartmentState.STA);
            SplashScreen.SplashThread.Start();
        }
    }
因此,如果我从VisualStudio运行,我的程序将忽略启动屏幕,否则它将使用启动屏幕运行。不再在每次测试重建时修改代码

我仍然不明白为什么我在调试器内部运行而不是一般代码时会出现错误,所以我希望这个站点上的一些聪明的bug能够出现并解释这个错误


否则,这项工作对我来说就足够了。

好的-这里有另一个解决方案。我想这是现在。我只是把它包括在内,以防其他人也有同样的问题。简短版本:托尔斯滕是对的

问题在于我的闪屏cl的性质
public partial class SplashScreen : Form
{
    private static double OPACITY_INCREMENT = .05;

    private static SplashScreen _splashForm;
    private static SplashScreen SplashForm
    {
        get { return SplashScreen._splashForm; }
        set { SplashScreen._splashForm = value; }
    }

    private static void ShowForm()
    {        
        Application.Run(SplashScreen.SplashForm);
    }

    internal static void CloseForm()
    {
        if (SplashScreen.SplashForm != null &&
            SplashScreen.SplashForm.IsDisposed == false)
        {
            // Make it start going away.
            SplashScreen.SplashForm.FadeOut();
        }

        //if (SplashScreen.SplashForm.InvokeRequired)
        //{
        //    SplashScreen.SplashForm.Invoke(new MethodInvoker(SplashScreen.SplashForm.Close));
        //}
        //else
        //{
        //    SplashScreen.SplashForm.DoClose();
        //}

        SplashScreen.SplashThread = null;
        SplashScreen.SplashForm = null;
    }

    private void FadeOut()
    {
        this.timerFadeOut.Start();
    }

    private static Thread _splashThread;
    private static Thread SplashThread
    {
        get { return SplashScreen._splashThread; }
        set { SplashScreen._splashThread = value; }
    }

    internal static void ShowSplashScreen()
    {
        if (SplashScreen.SplashForm != null)
        {
            return;
        }

        SplashScreen.SplashForm = new SplashScreen();
        SplashScreen.SplashThread = new Thread(new ThreadStart(SplashScreen.ShowForm));
        SplashScreen.SplashThread.IsBackground = true;
        SplashScreen.SplashThread.SetApartmentState(ApartmentState.STA);
        SplashScreen.SplashThread.Start();
    }

    public SplashScreen()
    {
        InitializeComponent();
        this.ClientSize = this.pictureBox1.Size;
    }

    private void SplashScreen_Load(object sender, EventArgs e)
    {

    }

    private void timerFadeIn_Tick(object sender, EventArgs e)
    {
        if (OPACITY_INCREMENT > 0)
        {
            if (this.Opacity < 1)
            {
                this.Opacity += OPACITY_INCREMENT;
            }
            else
            {
                this.timerFadeIn.Stop();
            }
        }
    }

    private void SplashScreen_Shown(object sender, EventArgs e)
    {
        this.timerFadeIn.Start();
    }

    private void timerFadeOut_Tick(object sender, EventArgs e)
    {
        if (OPACITY_INCREMENT > 0)
        {
            if (this.Opacity > 0)
            {
                if (this.InvokeRequired)
                {
                    this.Invoke(new MethodInvoker(this.FadeOutStep));
                }
                else
                {
                    this.FadeOutStep();
                }                    
            }
            else
            {
                this.timerFadeOut.Stop();

                if (this.InvokeRequired)
                {
                    this.Invoke(new MethodInvoker(this.Close));
                }
                else
                {
                    this.Close();
                }
            }
        }
    }

    private void FadeOutStep()
    {
        this.Opacity -= OPACITY_INCREMENT;
    }
}