c# -在创建新控件的线程仍在运行时关闭窗体

本文关键字:线程 运行时 窗体 控件 创建 新控件 | 更新日期: 2023-09-27 18:07:13

我试图在次要线程上添加自定义控件,但是当我关闭窗口而线程仍在运行时,我得到这个异常:

Invoke或BeginInvoke不能在控件上调用,直到窗口句柄已创建。

我不知道得到这个异常的原因是由于一个错误的线程还是因为我关闭了窗口,而线程还在运行。

这是我得到异常的代码:

panelWall.Invoke(new Action(() =>
            {
                postControl = new FBPostUserControl(m_LoggedInUser.Name, m_LoggedInUser.ImageNormal, post.CreatedTime);
                postControl.PostBody = post.Message;
                postControl.Image = postImage;
                postControl.Dock = DockStyle.Top;
                postControl.BringToFront();
            }));
这是我的自定义控件的代码:
public partial class FBPostUserControl : UserControl
{
    private readonly string m_UserName = string.Empty;
    private readonly Image m_UserProfileImage = null;
    private readonly DateTime? m_DatePosted = null;
    private Image m_Image = null;
    private string m_PostBody = string.Empty;
    public string UserName
    {
        get { return m_UserName; }
    }
    public DateTime? DatePosted
    {
        get { return m_DatePosted; }
    }
    public Image Image
    {
        get { return m_Image; }
        set
        {
            if (value == null)
            {
                pictureBoxImage.Visible = false;
            }
            else
            {
                pictureBoxImage.Visible = true;
                pictureBoxImage.Image = value;
                updateImageSize();
            }
        }
    }
    private void updateImageSize()
    {
        if (pictureBoxImage.Image != null)
        {
            double ratio = pictureBoxImage.Image.Width / pictureBoxImage.Image.Height;
            pictureBoxImage.Height = (int)(pictureBoxImage.Width / ratio);
            pictureBoxImage.SizeMode = PictureBoxSizeMode.Zoom;
        }
    }
    public string PostBody
    {
        get { return m_PostBody; }
        set
        {
            if (string.IsNullOrWhiteSpace(value) == false)
            {
                labelPostBody.Visible = true;
                labelPostBody.Text = value;
            }
            else
            {
                labelPostBody.Visible = false;
            }
        }
    }
    public Image UserProfileImage
    {
        get { return m_UserProfileImage; }
    }
    public FBPostUserControl(string i_Name, Image i_ProfileImage, DateTime? i_PostDate)
    {
        InitializeComponent();
        m_UserName = i_Name;
        m_UserProfileImage = i_ProfileImage;
        m_DatePosted = i_PostDate;
        refreshHeader();
    }
    private void refreshHeader()
    {
        pictureBoxUserImage.Image = m_UserProfileImage;
        labelName.Text = m_UserName;
        if (labelDate != null)
        {
            labelDate.Text = m_DatePosted.ToString();
        }
        else
        {
            labelDate.Visible = false;
        }
    }
}

c# -在创建新控件的线程仍在运行时关闭窗体

12/1/2020编辑开始

有问题等待任务。https://getandplay.github.io/2019/05/15/transfer-of-execution-rights-Task-Yield-Dispatcher-Yield/

中提到的Dispatcher Priority导致的Yield

等待System.Windows.Threading.Dispatcher.Yield()会更安全

12/1/2020编辑开始

首先,我没有看到您在一个新线程中启动操作,因为Invoke方法只是将操作发布到UI线程中的调度程序队列中。

因此,在您的代码中没有真正的多线程,但是在执行操作时,用户有机会发布CLOSE FORM windows消息,并且可以在下一次调用之前处理它。因此,为了避免exceptión,请在下次调用之前检查表单是否已关闭。

顺便说一下,我认为仅仅为了更新图形元素而启动一个新线程并没有真正的优势,因为它们最终必须在UI线程中更新,而你只是在往返中花费时间和资源。

如果你有一个长图形操作,你的目标是。NET Framework 4.5或更高版本,标准的方法是等待一个长图形操作的异步方法,并在内部等待Task.Yield(),以给用户取消,关闭窗口等机会。

基本上Task.Yield()将方法延续发送给UI调度程序,当它返回时,您可以检查表单并取消长操作,如果表单关闭:

    async Task LongJustGraphicsOperation()
    {
        while (true)
        {
            //do some work and give a pause
            await Task.Yield();
            if (formIsClosed) break;
        }
    }

Task. yield()是旧VB doevents的Task版本。

。检查winform是否关闭有点棘手