0

I am using a wpf UserControl to replace text in files in selected drawing files of AutoCAD. The wpf control is to display a status (ProgressBar) indicating the number of files processed at any given time. So I put up the following code, but the ProgressBar simply does not show any progress. Here is the part of relevant code.

XAML:

<ProgressBar HorizontalAlignment="Stretch" Name="pgrSearch" Minimum="0" Maximum="{Binding Path=ProgressBarMaximum}"
                 Value="{Binding Path=ProgressBarCurrent}" Height="20" Margin="10"  />

CodeBehind:

public partial class ReplaceUserControl : UserControl, INotifyPropertyChanged {
    public ReplaceUserControl() {
        InitializeComponent();
        this.DataContext = this;
    }
    ....

    private int _progressBarMaximum;
    public int ProgressBarMaximum {
        get { return _progressBarMaximum; }
        set { _progressBarMaximum = value; RaisePropertyChanged("ProgressBarMaximum"); }
    }

    private int _progressBarCurrent;
    private int ProgressBarCurrent {
        get { return _progressBarCurrent; }
        set { _progressBarCurrent = value; RaisePropertyChanged("ProgressBarCurrent"); }
    }


    private void ReplaceTextInFiles() { //Called from Button_Click Handler
        ....

        ProgressBarMaximum = filesList.Count - 1;

        SearchReplaceWorker replaceWorker = new SearchReplaceWorker(); //The Work Horse
        replaceWorker.FileProcessed += new FileProcessedEventHandler(worker_FileProcessed); //Raised by Work Horse when each file is processed

        BackgroundWorker workerThread = new BackgroundWorker(); //The Background Worker Thread
        workerThread.DoWork += (o, e) => {
            replaceWorker.ReplaceTextInFiles(SearchText, ReplaceText, filesList, ReportFolderPath, MatchCase, MatchSubstring);
        };
        workerThread.RunWorkerAsync(); //Start the Background Thread Async
    }

    void worker_FileProcessed(object sender, EventArgs e) {
        ProgressBarCurrent = ProgressBarCurrent + 1; //Update the ProgressBar status
    }

Why doesn't the ProgressBar update itself when the ProgressBarCurrent is incremented as indicated above in code.

Edit: In Order to process the ProgressBar update code on UI thread, I changed my code to use BackgroundWorker.ReportProgress() as given under.

CodeBehind for UserControl:

private void ReplaceTextInFiles() { //Called from Button_Click()
    if (!Directory.Exists(SearchFolderPath)) {
        MessageBox.Show("Invalid Directory Selected for Search");
        return;
    }

    if (!Directory.Exists(ReportFolderPath)) {
        MessageBox.Show("Invalid Directory Selected for Report File");
        return;
    }

    List<string> filesList = null;
    try {
        if (LookInSubFolders) {
            filesList = Directory.GetFiles(@SearchFolderPath, "*.dwg", SearchOption.AllDirectories).ToList();
        }
        else {
            filesList = Directory.GetFiles(@SearchFolderPath, "*.dwg", SearchOption.TopDirectoryOnly).ToList();
        }
    }
    catch (Exception ex) {
        MessageBox.Show("Error Occurred getting the files list. Contact Admin");
    }

    pgrSearch.Visibility = Visibility.Visible;
    ProgressBarMaximum = filesList.Count - 1;

    SearchReplaceWorker replaceWorker = new SearchReplaceWorker(); 

    BackgroundWorker workerThread = new BackgroundWorker(); 
    workerThread.WorkerReportsProgress = true;
    workerThread.ProgressChanged += (o, e) => { //This event handler gets called correctly.
        ProgressBarCurrent++; 
    };
    workerThread.RunWorkerCompleted += new RunWorkerCompletedEventHandler(workerThread_RunWorkerCompleted);
    workerThread.DoWork += (o, e) => {
        replaceWorker.ReplaceTextInFiles(workerThread, SearchText, ReplaceText, filesList, ReportFolderPath, MatchCase, MatchSubstring);
    };
    workerThread.RunWorkerAsync(); 
}

The BackgroundWorker:

public void ReplaceTextInFiles(BackgroundWorker workerThread, string searchText, string replaceText, List<string> filesList, string reportPath,
                                      bool MatchCase, bool MatchSubstring) {
    ...
    workerThread.ReportProgress(50);
}

Still the ProgressBar doesn't update itself.

John Saunders
  • 160,644
  • 26
  • 247
  • 397
Jatin
  • 4,023
  • 10
  • 60
  • 107
  • I had some help with a similar issue. http://stackoverflow.com/questions/1890518/wpf-multithreaded-progress-dialog – Joe Jun 19 '12 at 13:42
  • Where does it go wrong? Have you made sure that worker_FileProcessed gets called? – ekholm Jun 19 '12 at 13:45
  • @ekholm, Yes, I did debug the code and it properly hits the worker_FileProcessed. – Jatin Jun 19 '12 at 13:55
  • are the `RaisePropertyChanged` called in the setters (put a debug point)? do you see any binding errors in the Output window in Visual Studio? – Jake Berger Jun 19 '12 at 14:48
  • @jberger, The Setters are getting called properly. To my knowledge every thing seems to be hooked up properly. What feels like an issue here is that the FileProcessed event is fired by the Background Process on the Background thread. I believe for the UI to update itself, the event handler should run under the UI thread. So I would try firing FileProcessed event on the UI thread. Is there a way to get hold of the invoking UI thread in the Background Thread? Or am I completely wrong about my assumption? Thanks. – Jatin Jun 19 '12 at 15:16
  • in the ctor, do `UIDispatcher = this.Dispatcher`, where UIDispatcher is a local field ; then call `UIDispatcher.Invoke` or `BeginInvoke`. [Dispatcher](http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.aspx) – Jake Berger Jun 19 '12 at 15:29
  • @jberger, I used BackgroundWorker.ReportProgress(Int32) to send progress information from BackgroundWorker, the WorkHorse. According to the documentation here (http://msdn.microsoft.com/en-us/library/ka89zff4.aspx) the ReportProgress() raises ProgressChanged event, which executes on the calling thread (UI thread for my case). So I was expecting the ProgressBar to update itself this time. But I am still unsuccessful to get the ProgressBar updated. I also tried the Dispatcher, but nothing seems to update the progress bar. I am out of ideas now. Thanks anyway. – Jatin Jun 19 '12 at 15:49
  • your code and what you're saying do NOT make sense. 1. You say that `ReportProgress` raises `BackgroundWorker.ProgressChanged`, but you're not calling `ReportProgress` anywhere in your code. 2. You have NO hooks to `BackgroundWorker.ProgressChanged` (i.e. you're not subscribing to the event). (Also, please quit referring to the `BackgroundWorker` as "WorkHorse".) – Jake Berger Jun 19 '12 at 16:01
  • @jberger, when I used BackgroundWorker.ReportProgress, I changed my BackgroundWorker code to invoke the ReportProgress(). I also hooked up the ProgressChanged event EventHandler in my Button_Click() of UserControl and saw that ProgressChanged event handler was getting called properly. I incremented the ProgressBarCurrent variable by 1 to update the ProgressBar status. So this time the event was being handled in the UI thread. Because, of only limited number of characters allowed in the Comments, I skipped the describing the whole process and instead summarized what I did. – Jatin Jun 19 '12 at 16:17
  • 2
    your code in the question does NOT show calling BackgroundWorker.ReportProgress NOR hooking up to ProgressChanged. – Jake Berger Jun 19 '12 at 17:05
  • If you want help with code you need to post the actual code – paparazzo Jun 19 '12 at 19:35
  • @jberger, Please see my edit. I have posted the code that uses BackgroundWorker.ReportProgress(). – Jatin Jun 20 '12 at 02:54

1 Answers1

2

I created a test project with your initial code. After a while I found that you have declared the ProgressBarCurrent property as private. After changing to public it worked for me. So it doesn't seem necessary to update the property on the UI thread. It looks like a Dispatcher.Invoke call is made internally when reading back the updated property value.

ekholm
  • 2,543
  • 18
  • 18
  • 1
    Indeed it was a silly mistake. The ProgressBarCurrent was mistakenly declared private. I really thank you for taking the effort and finding that silly bug. – Jatin Jun 20 '12 at 10:17
  • In cases like this it would be nice with a compiler warning, although I realize it's not trivial... :) – ekholm Jun 20 '12 at 11:12