views:

2600

answers:

4

I'm trying to create a progress bar that will work asynchronously to the main process. I'm created a new event and invoked it however everytime I then try to perform operations on the progress bar I recieve the following error:

"The calling thread cannot access this object because a different thread owns it"

The following code is an attempt to send an instance of the progress bar to the event as an object, it obviously failed but it gives you an idea of what the code looks like.

    private event EventHandler importing;

    void MdbDataImport_importing(object sender, EventArgs e)
    {
        ProgressBar pb = (ProgressBar)sender;
        while (true)
        {
            if (pb.Value >= 200)
                pb.Value = 0;

            pb.Value += 10;
        }
    }

    private void btnImport_Click(object sender, RoutedEventArgs e)
    {
        importing += new EventHandler(MdbDataImport_importing);
        IAsyncResult aResult = null;

        aResult = importing.BeginInvoke(pbDataImport, null, null, null);

        importing.EndInvoke(aResult);
    }

Does anyone have ideas of how to do this.

Thanks in advance SumGuy.

A: 

You need to delegate pbDataImport to the dispatcher. Only the GUI-dispatcher can make changes to GUI controls :)

cwap
A: 

You should use something like this

pb.Dispatcher.Invoke(
                  System.Windows.Threading.DispatcherPriority.Normal,
                  new Action(
                    delegate()
                    {

                        if (pb.Value >= 200)
                            pb.Value = 0;

                        pb.Value += 10;
                    }
                ));

in your while loop

ArsenMkrt
This does work thanks however it's quite slow. Not sure whether it's the way I've done it though, I'll have to poke around with it some more
SumGuy
1) Instead of Invoke use BeginInvoke (you wouldn't want your background processing thread wait until GUI gets redrawn, would you?)2) Don't try to update progress every microsecond, choose sensible interval.
Oleg Mihailik
A: 

I've looked into it further and the asynchronous method will work as well as the following method from MSDN.

In XAML:

<ProgressBar Width="100" Height="20" Name="progressBar1">
    <ProgressBar.Triggers>
        <EventTrigger RoutedEvent="ProgressBar.Loaded">
            <BeginStoryboard>
                <Storyboard>
                    <DoubleAnimation Storyboard.TargetName="progressBar1"  From="0" To="100" Duration="0:0:5"  />
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </ProgressBar.Triggers>
</ProgressBar>

In C#:

        ProgressBar progbar = new ProgressBar();
        progbar.IsIndeterminate = false;
        progbar.Orientation = Orientation.Horizontal;
        progbar.Width = 150;
        progbar.Height = 15;
        Duration duration = new Duration(TimeSpan.FromSeconds(10));
        DoubleAnimation doubleanimation = new DoubleAnimation(100.0, duration);
        progbar.BeginAnimation(ProgressBar.ValueProperty, doubleanimation);

My problem was that I was performing a stored procedure when I wanted the progress bar to perform and this holds the process up and therefore makes the progress bar a bit rubbish, even when asynchronous.

I suppose the other possiblilty would be to make the stored procedure actions asynchronous, what do you guys think?

Cheers, SumGuy

Edit (17 May 2010)

It seems a lot of people are interested in this post so I thought I'd add this. I found an excellent piece which describes Asynchronous work in WPF in great detail along with a tasty bit on progress bars:

http://www.codeproject.com/KB/WPF/AsynchronousWPF.aspx

SumGuy
do you know when SP will finish? why don't you use indeterminate progress bar? http://msdn.microsoft.com/en-us/library/system.windows.controls.progressbar.isindeterminate.aspx
ArsenMkrt
A: 

Hi

I have posted an article in CodeProject at http://www.codeproject.com/KB/WPF/WPFWaitProgressBar.aspx - can you please check out and let me know if that helps in your scenario. Thanks

Raja

Raja Lakshman