【问题标题】:Invoke of a UserControl doesn't work调用 UserControl 不起作用
【发布时间】:2015-06-08 06:16:41
【问题描述】:

我有一个表单 (MainPage),我有时在其中设置了一个 UserControl,所以我在该表单中编写了一个这样的方法来调用:

delegate void containerPanelCallback(UIPart uiPart);
public void IncludeUIPart(UIPart uiPart)
{
    if (this.containerPanel.InvokeRequired)
    {
        containerPanelCallback d = new containerPanelCallback(IncludeUIPart);
        containerPanel.Invoke(d, new object[] { uiPart });
    }
    else
    {
        containerPanel.Controls.Clear();
        containerPanel.Controls.Add(uiPart);
    }
    uiPart.Size = this.containerPanel.Size;
    uiPart.Dock = DockStyle.Fill;
}

UIPart 类继承自 UserControl,而我的 UserControls 继承自 UIPart

这个方法和调用是这样启动的:

public class myClass
{ 
...
private static MainPage _frmMain;
private static myUIPart6 UIP6;
...
public static void aMethod(/* Some arguments */)
{
    UIP6 = new myUIPart6 { /* Some settings of properties */ };
    _frmMain.IncludeUIPart(UIP6);
    _frmMain.Show(); /*Throws an error*/
}
...
}

错误是:

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

我在这里找到了很多关于这个错误的问题和答案,但我不明白为什么它会抛出_frmMain.Show();?,我应该调用别的东西吗?还是我走错路了?它与创建我的 UserControl 的句柄有关吗?

【问题讨论】:

  • 你怎么称呼aMethod
  • Invoke() 必须在非主线程执行 UI 时调用任何/所有操作。在您的示例中,您在调用 IncludeUIPart() 时使用 Invoke on,但在调用 _frmMain.Show 时不使用 Invoke()。尝试将整个 aMethod 包装在 Invoke() 中并从 IncludeUIPart() 中删除 Invoke 调用
  • 我认为您在 2000 年初作为开发人员以及您的笑话 ;)
  • 所以你不应该拿严肃的事情开玩笑;)
  • @HamletHakobyan 我有一个Send 线程调用aMethod() ;)。

标签: c# multithreading winforms


【解决方案1】:

尝试添加以下代码:

public static void aMethodCaller(){
 if (_frmMain.InvokeRequired)
   _frmMain.Invoke(new Action(aMethod));
 else
   aMethod();
}

并将代码中对 aMethod() 的所有引用替换为 aMethodCaller()

下面是示例代码:

class Foo 
{
    static Form _frmMain;
    public static void aMethod()
    {
        _frmMain.Show(); 
    }        
    public static void aMethodCaller()
    {
        if (_frmMain.InvokeRequired)
            _frmMain.Invoke(new Action(aMethod));
        else
            aMethod();
    }
}

【讨论】:

  • aMethod 根据您问题中的代码是静态的,因此您不能将其称为 _frmMain.aMethod(),可以吗? -- 嗯,这似乎是对已删除操作的评论的回答
  • 为什么人们一次又一次地发布错误的解决方案来解决这个问题。可以,但是当您必须使用 Inovke 从另一个线程更改您的 UI 时,这是一个设计错误。
  • @user743414,你​​是对的。但这个世界是不完美的。每个设计都是错误的,因为总是有完美的空间;-) 说真的,人们想要的解决方案比“正确”的解决方案更有效。然后他们在错误但有效的解决方案中发现问题,这就是他们学习的方式
  • Yarkovoy 是的,但是,当每个人都这样做时。软件开发并没有变得更好。 :) 我很生气,因为那天我在 stackoverflow 上不止一次地阅读了该解决方案。
【解决方案2】:

_frmMain.Show() 不受任何调用要求检查的保护。所以你可能在后台线程中调用它。

【讨论】:

  • 如果你的aMethod是从非UI线程调用的,那么你必须检查aMethod中的InvokeRequired并在正确的线程中执行_frmMain.Show(),就像你在IncludeUIPart.
  • 你在哪里调用它并不重要,重要的是你如何调用它,即从哪个线程调用它。
  • 我有一个线程 SendMyUIPart5 内部调用 aMethod
  • 那么请看我的第一条评论。
  • 感谢您澄清这一点,我应该像 Denis Yarkovoy 的回答一样做同样的事情,还是有其他方法?
猜你喜欢
  • 2014-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-25
  • 2014-03-29
  • 1970-01-01
相关资源
最近更新 更多