views:

62

answers:

1

I want to bind the value property of a WPF ProgressBar to a dependency property that is updated during a long running process. If the long running process is called from the main thread then this blocks the UI (and hence the ProgressBar) from updating until the process completes - preventing the desired progress through the process being shown. The long running process also cannot be run by spinning a seperate thread because it is not possible to update a dependency property from a different thread to its owner (i.e. the thread on which it was created).

In the code below, when the button is clicked, the long running process runs and the progress bar jumps from 0% to 100% when it completes. Instead, I want to be able to click the button and have the progress bar show the progress through the long running progress (i.e. not just updating from 0% to 100% when the process finishes but showing a smooth progression).

MainWindow.xaml

<Window x:Class="ProgressBarTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525" DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <StackPanel>
        <Button Width="200" Height="50" x:Name="btnRun" Click="btnRun_Click">Run Process</Button>
        <ProgressBar Width="200" Height="20" x:Name="pbProgress" Minimum="0" Maximum="100" Value="{Binding Path=MyFoo.ProgressValue}"/>
    </StackPanel>
</Window>

MainWindow.xaml.cs

using System.Windows;
using System.Threading;

namespace ProgressBarTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public Foo MyFoo { get; set; }

        public MainWindow()
        {
            MyFoo = new Foo();
            InitializeComponent();

        }

        private void btnRun_Click(object sender, RoutedEventArgs e)
        {
            btnRun.IsEnabled = false;

            MyFoo.LongRunningProcess();  // Since this runs on same thread as UI, progress bar does not update until the long running process completes.

            btnRun.IsEnabled = true;
        }
    }

    public class Foo : DependencyObject
    {
        public static readonly DependencyProperty ProgressValueProperty = DependencyProperty.Register("ProgressValue", typeof(double), typeof(Foo));
        public double ProgressValue
        {
            get { return (double)GetValue(ProgressValueProperty); }
            set
            {
                SetValue(ProgressValueProperty, value);
            }
        }

        public Foo()
        {
            ProgressValue = 0;
        }

        public void LongRunningProcess()
        {
            do
            {
                ProgressValue += 1;

                Thread.Sleep(30);
            }
            while (ProgressValue < 100);
        }
    }
}

P.S. I know there is a way I can do this by passing the ProgressBar instance as an argument to the long running process so that it can update it directly through Dispatcher.Invoke, but that is not what I want. I want to have the progress bar update through binding to a dependency property.

Thanks

Sean

+2  A: 

I'll try to be nicer than Euphoric.

You need to run your LongRunningProcess using a BackgroundWorker that runs the process on a different thread and then update the property using the ProgressChanged event

// This event handler updates the progress bar.
private void backgroundWorker1_ProgressChanged(object sender,
    ProgressChangedEventArgs e)
{
    MyFoo.ProgressValue = e.ProgressPercentage;
}
Eduardo Molteni
Thanks Eduardo. However, I'm not sure how this would work to solve my problem. Following the above snippet: The MyFoo instance would have to raise the above event (ProgressChanged) on the background worker, and then the event would updates the MyFoo.ProgressValue property value? The MyFoo instance can of course update its own property (as it does in the code I showed), the problem is that the ProgressBar in the UI does not update.
sean