【问题标题】:How do I set a ToolStripProgressBar's Value from a Thread?如何从线程设置 ToolStripProgressBar 的值?
【发布时间】:2012-05-05 13:14:11
【问题描述】:

现在,我知道当大多数人看到这种问题时,他们会想“哦,请使用代表”。好吧,我正在使用委托。这是迄今为止唯一拒绝与他们合作的控件。我也没有使用 BackgroundWorker。

我为自己编写了一个 System::Threading::Thread 的包装类,因为我知道我会经常使用它们。我为该类提供了各种委托事件,以便它可以与 UI 线程交互。我一直在使用它主要只是为了设置状态栏的状态。我还有一个未使用的进度条,所以我想添加它。我给了它一个委托,但是当我运行它时,它会因臭名昭著而崩溃:

System.Windows.Forms.dll 中出现“System.InvalidOperationException”类型的未处理异常

附加信息:跨线程操作无效:Control '' 从创建它的线程以外的线程访问。

我现在很困惑,因为据我所知,我使用委托的方式与使用其他控件的方式相同。这一款很特别吗?我已经在互联网上进行了广泛搜索,我得到的只是 C# BackgroundWorker 问题,这些问题并不真正适用于此。这是我的代表的代码:

委托人:

delegate void               OnThreadProgressUpdateDel(int progress, String^ status);

保存事件的变量:

OnThreadProgressUpdateDel^  m_updateProgressEvent;

事件绑定方式:

thread->OnThreadProgressUpdate += gcnew ObjectLoadThread::OnThreadProgressUpdateDel(this, &CObjectLoader::ProgressUpdate);

事件调用:

void CObjectLoader::ProgressUpdate(int progress, String^ status)
{
    gGlobal->ProgramProgress->Maximum = 100;
    gGlobal->ProgramProgress->Value = progress; //Crash here...
    gGlobal->SetProgramStatus(status);
}

在这里调用:

m_updateProgressEvent->Invoke(1, "Loading objects...");

这个愚蠢的 ToolStripProgressBar 有什么特别之处让它不想更新:(

在 Microsoft Visual C++ 2008 Express Edition 中使用 C++ CLR、Windows 窗体应用程序。

【问题讨论】:

    标签: winforms multithreading c++-cli clr


    【解决方案1】:

    // 使用下面的代码 Ahmad abbulkmailer.com

    SetControlPropertyValue1(ProgressBar2, "value", 67);
    
      delegate void SetControlValueCallback1(ToolStripProgressBar oControl, string propName, object propValue);
            private void SetControlPropertyValue1(ToolStripProgressBar oControl, string propName, object propValue) {
                if (oControl.GetCurrentParent().InvokeRequired) {
                    SetControlValueCallback1 d = new SetControlValueCallback1(SetControlPropertyValue1);
                    oControl.GetCurrentParent().Invoke(d, new object[] { oControl, propName, propValue });
                }
                else {
    
                    Type t = oControl.GetType();
                    PropertyInfo[] props = t.GetProperties();
    
                    foreach (PropertyInfo p in props) {
                        if (p.Name.ToUpper() == propName.ToUpper()) {
                            p.SetValue(oControl, propValue, null);
                        }
                    }
                }
                
    
            }
    

    【讨论】:

      【解决方案2】:

      “ToolStripProgressBar 没有 Invoke 方法。”

      你是对的;但是 toolStripProgressBar.ProgressBar.Invoke 和 InvokeRequired 确实存在并按预期运行。

      【讨论】:

        【解决方案3】:

        Windows 控件希望从创建它们的同一线程进行修改。根据控制和操作,MDA 或 Exception 不会触发,但最好遵循标准:

        if(InvokeRequired) control.Invoke();

        处理线程和控件时的模式。

        http://msdn.microsoft.com/en-us/library/ms171728(v=vs.80).aspx

        【讨论】:

        • ToolStripProgressBar 没有Invoke 方法。我可以使用GetCurrentParent() 获得Invoke 方法吗? InvokeRequired 也是如此。
        • @smoth190 您可以使用位于同一线程上的任何组件,甚至是主机表单。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-06
        • 2017-03-06
        相关资源
        最近更新 更多