Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proper way to sync a wpf progress bar with function from a library

I am using function from a library to process really big word files and I can't change this function. While processing, I want to show a progress bar, because either way the app looks frozen and the users are not aware it's actually working. For now I'm using a worker like this:

private void btnClick(object sender, RoutedEventArgs e)
{ 
    BackgroundWorker worker = new BackgroundWorker();
    worker.RunWorkerCompleted += worker_RunWorkerCompleted;
    worker.WorkerReportsProgress = true;
    worker.DoWork += worker_DoConvertOne;
    worker.ProgressChanged += worker_ProgressChanged;
    worker.RunWorkerAsync();
}

private void worker_DoConvertOne(object sender, DoWorkEventArgs e)
{
    var worker = sender as BackgroundWorker;
        //The progress bar is filled on 20%
        worker.ReportProgress(0);
        worker.ReportProgress(10);
        worker.ReportProgress(20);

        //Processing
        myLongLastingFunction(bigWordFile);

        //The progress bas is full
        worker.ReportProgress(100, "Done Processing.");
}

private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    MessageBox.Show("Converting finished!");
    TestProgressBar.Value = 0;
    ProgressTextBlock.Text = "";
}

private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    TestProgressBar.Value = e.ProgressPercentage;
    ProgressTextBlock.Text = (string)e.UserState;
}

It's doing the work, but it's a workaround and i want to know if there is a proper way to solve my problem. Thanks in advance. :)

like image 587
nyagolova Avatar asked Jan 27 '16 09:01

nyagolova


Video Answer


2 Answers

I take from your question that altering the myLongLastingFunction is not possible to give you periodic updates on progress, and this ability currently does not exist in the function.

For these scenarios when the duration of the task cannot be determined then a progress bar with the dependency property IsIndeterminate="True" is the accepted way to give this information to the user. This animates the progress bar to be scrolling continuously.

XAML

   <ProgressBar Margin="10" IsIndeterminate="True" />

I personally prefer the animated moving dots as seen on Windows Phone. An example has been implemented here.

If this is not what you require the next best method is to estimate the total time, and subdividing this time with a DispatchTimer to give a periodic event to increment the progress bar. This obviously has two problems of either finishing before reaching 100% (not a bad thing) or reaching 100% and getting stuck there as the actual time is significantly longer than the estimate. The second undesired effect will make the application look inactive again.

like image 140
Rhys Avatar answered Nov 09 '22 23:11

Rhys


It is possible to show current progress by ProgressBar and BackgroundWorker when reading .txt(Word) files. You should just calculate proportion of how many 1 percent is for ProgressBar. Let's see work example:

Code behind:

public partial class MainWindow : Window
{
    BackgroundWorker bw;
    long l_file;
    public MainWindow()
    {
        InitializeComponent();
    }

    string fileName = "";
    private void InitializeBackgroundWorker()
    {   
        bw = new BackgroundWorker();
        bw.DoWork += Bw_DoWork;
        bw.ProgressChanged += Bw_ProgressChanged;            
        bw.WorkerReportsProgress = true;
    }



    private void Bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressBar.Value = e.ProgressPercentage;
    }

    private void Bw_DoWork(object sender, DoWorkEventArgs e)
    {
        ReadFile(fileName);
    }

    private void btnOpenFLD_Click(object sender, RoutedEventArgs e)
    {
        progressBar.Minimum = 0;
        progressBar.Maximum = 100;

        OpenFileDialog ofd = new OpenFileDialog();            
        if (ofd.ShowDialog() == true)
        {                
            FileInfo fileInfo = new FileInfo(ofd.FileName);
            l_file = fileInfo.Length;
            fileName = ofd.FileName;
            InitializeBackgroundWorker();
            bw.RunWorkerAsync();
        }            
    }        

    private void ReadFile(string fileName)
    {
        string line;
        long onePercent = l_file / 100;
        long lineLength = 0;
        long flagLength = 0;
        using (StreamReader sr = new StreamReader(fileName, System.Text.Encoding.ASCII))
        {
            while (sr.EndOfStream == false)
            {
                line = sr.ReadLine();
                lineLength = line.Length;
                flagLength += lineLength+2;
                //Thread.Sleep(1);//uncomment it if you want to simulate a 
                //very heavy weight file
                if (flagLength >= onePercent)
                {
                    CountProgressBar += 1;
                    bw.ReportProgress(CountProgressBar);
                    flagLength %= onePercent;
                }
            }
        }
    }

    int countProgressBar = 0;
    private int CountProgressBar
    {
        get { return countProgressBar; }
        set
        {
            if (countProgressBar < 100)
                countProgressBar = value;
            else
                countProgressBar = 0;
        }
    }
}    

XAML:

<Window x:Class="BackgroundWorkerProgressBarReadFile.MainWindow"
        ...The code omitted for the brevity...
        xmlns:local="clr-namespace:BackgroundWorkerProgressBarReadFile"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="0.2*"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>            
        </Grid.ColumnDefinitions>
        <ProgressBar Margin="5" Name="progressBar"/>
        <Button Grid.Row="1" Content="Open File Dialog" Name="btnOpenFLD"  
        Click="btnOpenFLD_Click"/>


    </Grid>
</Window>

If you do some other works after reading file and you want to show progress, then just move this code after all works you do.

if (flagLength >= onePercent)
{
    CountProgressBar += 1;
    bw.ReportProgress(CountProgressBar);
    flagLength %= onePercent;
}
like image 26
StepUp Avatar answered Nov 09 '22 23:11

StepUp