Background worker C#


Hi friends,

I am developing one application - in which on click event of a button, I am calling several functions and other sub-routines (e.g. creation of CSV file, Copy them to SQL table, load them to Datagrid) - now my problem is that when there are loads of data - it takes considerable time until grid fills with the data. So I need to execute progressbar or any other animation - during that idle time.

I read something about background worker in C# - but I could not fit it into my requirement any how.... so kindly help, it would be fine if some other alternative to the same requirement

thanks a lot,
Jeet

Comments

  • What you are looking to do is create a proxy for your display controls/views

    Here is a very heavily commented example of what one of these would look like:
    [code]
    using System;
    using System.ComponentModel;
    using System.Windows.Forms;

    // This control will proxy your actual display control.
    // We will then use a command pattern to handle the processing and
    // eventual loading of your data into your view.
    namespace SomeProgram
    {
    ///
    /// Defines a proxy for a control that displays data in some way.
    ///
    /// The concrete data view type.
    public partial class DataViewProxy : UserControl where TView : Control
    {
    private Panel _panel = null;
    private ProgressBar _progressbar = null;

    ///
    /// The control you are proxying
    ///
    public TView DataView { get; set; }

    ///
    /// Creates the proxy around your display object.
    ///
    /// Your display control
    public DataViewProxy(TView dataview)
    {
    InitializeComponent();

    //Adding the data view as a child to our proxy control.
    //And making it fill to the proxy control.
    DataView = dataview;
    Controls.Add(DataView);
    DataView.Dock = DockStyle.Fill;
    //Now instead of adding your datagrid - or whatever to your form
    //you will add this proxy control instead.

    //Disabling the data control because it has not loaded data yet
    DataView.Enabled = false;

    SetUpProxyDisplay();
    }

    ///
    /// You should probably use the designer view to put together the appearance
    /// of your proxy view, but here I am doing it in all code so you can see
    /// what I'm doing.
    ///
    private void SetUpProxyDisplay()
    {
    //What I am doing here is slapping a panel at the bottom of the proxy
    //view that will pop up when data is loading and dissapear when the
    //loading has completed.
    _panel = new Panel()
    {
    Dock = DockStyle.Bottom,
    Height = 15,
    };
    _progressbar = new ProgressBar()
    {
    Dock = DockStyle.Right,
    Width = 150,
    Style = ProgressBarStyle.Blocks,
    Minimum = 0,
    Maximum = 100,
    Value = 0,
    };
    var text = new Label()
    {
    Text = "Loading...",
    Dock = DockStyle.Right,
    AutoSize = false,
    Width = 60,
    };
    _panel.Controls.Add(text);
    _panel.Controls.Add(_progressbar);
    Controls.Add(_panel);
    _panel.BringToFront();
    _panel.Hide();
    }

    ///
    /// An async loader method that applies a command pattern to populate your view.
    ///
    /// The data structure that will be displayed.
    /// The loader delegate.
    /// The display delegate.
    public void LoadDataAsync(Func, TData> dowork, Action publish) where TData : class
    {
    TData result = null;

    // Showing the loading ui
    _panel.Show();
    // Disabling the data view
    DataView.Enabled = false;

    // Creates a worker...
    var worker = new BackgroundWorker();

    // Creates a progress bar updater delegate that will be passed to the
    // dowork method allowing it to update progress.
    var progress = new Action(
    (val) => Invoke(new MethodInvoker(() => _progressbar.Value = val)));

    // tells the worker how to load the data...
    worker.DoWork += delegate { result = dowork(progress); };
    // tells the worker how to display the data...
    worker.RunWorkerCompleted +=
    delegate
    {
    Invoke(new MethodInvoker(() => publish(result, DataView)));
    // Hides the loading ui
    _panel.Hide();
    // Reenables the data view
    DataView.Enabled = true;
    };
    // runs the worker...
    worker.RunWorkerAsync();
    }
    }
    }
    [/code]

    Copy that into a code file and as you understand what it's doing pull out all the comments.

    What this will do is wrap whatever display you are using (in your case a datagrid) with a proxy control that will handle background processing of data for you.

    You will want to actually add this control to your Form INSTEAD of the control/view it is proxying.

    So something like this...

    [code]
    // Creating a datagrid view with 3 columns...
    var grid = new DataGridView();
    grid.Columns.Add(new DataGridViewTextBoxColumn() { HeaderText = "Column1" });
    grid.Columns.Add(new DataGridViewTextBoxColumn() { HeaderText = "Column2" });
    grid.Columns.Add(new DataGridViewTextBoxColumn() { HeaderText = "Column3" });

    // Creating the datagrid proxy...
    var proxy = new DataViewProxy(grid);

    // Adding the proxy to a form...
    var form = new Form();
    form.Controls.Add(proxy);
    proxy.Dock = DockStyle.Fill;
    [/code]

    So now any time you want to load data into the form you will call the proxy's LoadDataAsync method and pass it 2 delegates:
    One for loading the data,
    And one for writing the data to your data grid:

    [code]
    // In this example I am using a "string" as the data result -
    // But you should be passing a data structure of some kind
    // that will contain your resulting data.
    proxy.LoadDataAsync(
    (progress) => // This is a delegate that loads the data
    {
    // I have a make-shift delay here to simulate
    // a 15 second loading time...
    var secondsToLoad = 15;
    var finish = DateTime.Now + TimeSpan.FromSeconds(secondsToLoad);
    while (finish > DateTime.Now)
    {
    var remainder = (finish - DateTime.Now);
    progress(100 - (100 / secondsToLoad) * remainder.Seconds);//updates the progress bar
    }
    return "MyData";// returns the completed data structure.
    },
    (d, v) => // This is a delegate that populates the proxied view
    {
    v.Rows.Add(new object[] { d, d, d });
    v.Rows.Add(new object[] { d, d, d });
    v.Rows.Add(new object[] { d, d, d });
    });
    [/code]

    Now in here I simply proxied a lone DataGridView, but the idea of this is to create a usercontrol that contains an entire UI section that you want to proxy. This will help you to reduce hang ups in your application and also give you an eye-pleasing loading bar to your users while they wait for your UI to populate with data.
    ><//~Psightoplasm`~
  • Many thanks for this pretty neat answer,,,,

    Regards
    Jeet
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories