加载弹出窗体交叉线程

时间:2018-05-20 01:55:32

标签: c# forms winforms thread-safety

我在从其他线程处理表单时遇到问题。

我通过在运行时加载表单,显示它然后隐藏它来克服了这个问题。这意味着表单是在正确的线程上创建的,可以使用调用进行操作。

这不是正确的方法。我有3个问题来自使用此方法

  1. 我无法生成另一个弹出框,我必须使用我在运行时创建的弹出框
  2. 这些表格在加载时会短暂闪现 - 现在我有3个表格,这非常明显我正在做什么。
  3. 如果弹出窗口是打开的话,我必须使用变量bool来保持。
  4. 如果有人能指出我正确的方向,我将不胜感激。目前我的代码如下:

    在主表单上加载:

            CallerIDfrm = new frmCallerID();
            CallerIDfrm.Show();
            CallerIDfrm.Hide();
    

    使用

    操作弹出窗口Im
        delegate void StringArgReturningVoidDelegate1(string CallerIDnum, string CallerIDname, string ContactID);
        private void CallerID(string CallerIDnum, string CallerIDname, string ContactID)
        {
            if (CallerIDfrm.InvokeRequired)
            {
                StringArgReturningVoidDelegate1 d = new StringArgReturningVoidDelegate1(CallerID);
                CallerIDfrm.Invoke(d, new object[] { CallerIDnum, CallerIDname, ContactID });
            }
            else
            {
    
                if (ContactID != null || ContactID != "0")
                {
                    CallerIDfrm.ContactID = ContactID;
    
    
                }
                CallerIDfrm.Mainfrm = this;
                CallerIDfrm.TopLevel = true;
                CallerIDfrm.TopMost = true;
                CallerIDfrm.lblCallerIDname.Text = CallerIDname;
                CallerIDfrm.lblCallerIDnum.Text = CallerIDnum;
                CallerIDfrm.Show();
                CallerIDOpen = true;
    
            }
        }
    

    使用以下方法隐藏弹出窗口,直到需要:

    delegate void StringArgReturningVoidDelegate2();
    
    private void CallerIDClose()
    {
        if (CallerIDfrm.InvokeRequired)
        {
            StringArgReturningVoidDelegate2 d = new StringArgReturningVoidDelegate2(CallerIDClose);
            CallerIDfrm.Invoke(d, new object[] { });
        }
        else
        {
            try
            {
                CallerIDfrm.Hide();
                CallerIDOpen = false;
            }
            catch
            {
            }
        }
    }
    

    我已经尝试了其他方法,但Popup加载就好像它没有响应而且我无法访问弹出窗口。

    最终,我希望能够生成多个弹出窗口,并能够从主窗体中关闭它们。

1 个答案:

答案 0 :(得分:0)

我从你的问题中收集到的内容:你有一个来电者api / lib / class,你喜欢在收到电话时在弹出窗体上显示CallerId。看看Events and Event Driven programming

以下代码尚未经过测试,我是从头顶编写的。可能无法编译,他们在这里展示一个例子:

在api / lib类中创建一个CallReceived事件,如下所示:

public event EventHandler<CallReceivedEventArgs> CallReceived;
protected void OnCallReceived(EventArgs e)
{
    var handler = CallReceived;
    if (handler != null)
        handler(this, e);

    // Note: For C# 6.0 and later, above statements can be simplified to
    // CallReceived?.Invoke(this, e);
}

注意:如果您无法访问此api / lib代码,请创建一个Gateway类并将您的事件放在那里以及触发它的机制。

还创建一个CallReceivedEventArgs,这将用于传输事件数据:

public class CallReceivedEventArgs : EventArgs
{
    public string CallerIDnum {get; set;}
    public string CallerIDname {get; set;}
    public string ContactID {get; set;}
}

现在,在你的api / lib类中,只要收到一个电话就会引发这个事件:

// a call received, replace dummy values with actual values
OnCallReceived(new CallReceivedEventArgs() { CallerIDnum="5554443322", CallerIDname="SOME_NAME", ContactID="SOME_CONTACT" });

最后在您的GUI表单中,注册所述事件并相应地处理。

// inside your main form class
private CallerAPI callerApi = new CallerAPI();

// somewhere inside you main form class, register to event
// from your use case, I would place it inside Main Form's constructor
callerApi.CallReceived += callerApi_Callreceived;

// receive event
void callerApi_Callreceived(object sender, CallReceivedEventArgs e)
{
    var callerIDnum = e.CallerIDnum;
    // etc.
    // show callerId form with details
    // you need to change frmCallerID's constructor accordingly
    CallerIDfrm = new frmCallerID(e.CallerIDnum, CallerIDname, ContantID);
    // to be able to track opened popups, you can store them inside a list
    // private List<Form> openPopupList = new List<Form>();
    //
    // alternatively, you can assign CallerIDnum to form's name property
    // and store these inside a List<string> instead of List<Form>
    openPopupList.add(CallerIDfrm);
    CallerIDfrm.Show();
}

不要忘记从事件中取消注册。

callerApi.CallReceived -= callerApi_Callreceived;

包装起来:

  
      
  1. 我无法生成另一个弹出框我必须使用我在运行时创建的弹出框
  2.   

您可以创建并显示多个frmCallerID,彼此独立。

  
      
  1. 这些表格在加载时会短暂闪现 - 现在我有3种形式,这显然是我正在做的事情。
  2.   

由于新方法基于事件创建了CallerID表单,因此您不会看到这些表单闪烁。只要收到CallReceived事件,它就会打开。

  
      
  1. 如果弹出窗口是打开的话,我必须使用变量bool来保持。
  2.   

更好的方法是:注册表格FormClosed事件,并相应地从openPopupList删除。

frmCallerID.FormClosed += frmCallerID_FormClosed;

void frmCallerID_FormClosed(object sender, EventArgs e)
{
    // remove form from openPopupList
    frmCallerID closedPopup = (frmCallerID) sender;
    openPopupList.remove(closedPopup);
}