c# - 进度条[线程]跨线程操作无效:控制'progressBar'从其创建的线程以外的线程访问

时间:2010-09-08 11:25:30

标签: c#-3.0

我坚持上述问题。我有很多解决方案,但没有一个能为我工作。 请在此处找到我的代码

private void btnRunQuery_Click(object sender, EventArgs e)
    {
        try
        {

            Thread ProcessThread = new Thread(Process);
            ProcessThread.Start();

            Thread.CurrentThread.Join();
        }
        catch
        {
            Debug.WriteLine("Error in model creation");
            Console.WriteLine("Error in model creation");
        }
        finally
        {
            //dsModel = null;
        }
    }


private void Process()
    {

        using (var dataContext = new IControlerDataContext())
        {
            dataContext.EnlistTransaction();

            IItemPropertyRepository itemPropertyRepository = ObjectContainer.Resolve<IItemPropertyRepository>();
            IList<ItemProperty> itemPropertyCollection = itemPropertyRepository.LoadAll();
            totalCount = itemPropertyCollection.Count;
            currentCount = 0;

            foreach (var itemProperty in itemPropertyCollection)
            {
                try
                {
                    message = string.Empty;
                    currentCount++;
                    if (itemProperty.DeletedDate == null && (itemProperty.MetaItemProperty.ValueType == MetaItemPropertyValueType.MetaItemTableProperty || itemProperty.MetaItemProperty.ValueType == MetaItemPropertyValueType.MetaItemTableMultiSelectProperty))
                    {
                        //Property refresh issue in only applicable for table and multitable property.
                        //Need to filter the itemproperty for Table and multitable select property.
                        message = ProcessItemProperty(itemProperty);
                        //txtLogDetails.Text += message + Environment.NewLine;
                        //txtLogDetails.Refresh();
                        //txtLogDetails.ScrollToCaret();
                    }
                    //Log(message);
                    //progressBar.Value = (Int32)(currentCount * 100 / totalCount);
                    //progressBar.Refresh();
                    Invoke(new MyDelegate(ShowProgressBar), (Int32)(currentCount * 100 / totalCount));

                }
                catch (Exception ex)
                {
                    txtLogDetails.Text += "EXCEPTION ERROR : " + itemProperty.Id.ToString();
                    dataContext.RollBackTransaction();
                }
            }
            dataContext.CompleteTransaction();
        }
    }

 delegate void MyDelegate(int percentage);
    private void ShowProgressBar(int percentage)
    {
        progressBar.Value = percentage;
        progressBar.Refresh();
        //txtLogDetails.Text = message;
    }

当它执行“Invoke(new MyDelegate(ShowProgressBar),(Int32)(currentCount * 100 / totalCount));”时这条线超出了范围。它进入内部,永远不会回来。而且也没有陷入异常。

有人可以帮我解决这个问题吗?

谢谢, 马赫什

2 个答案:

答案 0 :(得分:5)

必须从创建它的线程访问控件progressBar。使用BeginInvoke

我会替换这一行...

Invoke(new MyDelegate(ShowProgressBar), (Int32)(currentCount * 100 / totalCount)); 

......这个......

this.progressBar.BeginInvoke( 
    (MethodInvoker)delegate() { 
        this.progressBar.Value =
           Convert.ToInt32(currentCount * 100 / totalCount); } );

或者你可以替换这些线......

progressBar.Value = percentage; 
        progressBar.Refresh(); 
        //txtLogDetails.Text = message; 

......按这些方式......

this.progressBar.BeginInvoke( 
    (MethodInvoker)delegate() { 
    progressBar.Value = percentage; 
    progressBar.Refresh(); 
    //txtLogDetails.Text = message; 

    } );

答案 1 :(得分:0)

我认为问题在于您使用Thread.Join来阻止UI线程。

Thread.Join理论上会继续提供UI消息,但实际上它并不总是有效。

请参阅Chris Brumme的博客here。特别

  

净效果是我们将始终为等待进入您的STA的COM呼叫提供泵送。任何发送到任何窗口的SendMessages都将得到服务。但是大多数PostMessages都会被延迟,直到你完成阻止。

你应该让按钮事件完成并让新线程在完成后回发消息(例如通过使用backgroundworker或其他异步框架)

(你的catch语句无论如何都是无用的,因为它只能捕获线程创建异常。)