Loading Data Animation

4 posts, 0 answers
  1. Andreas Haeusler
    Andreas Haeusler avatar
    25 posts
    Member since:
    Nov 2009

    Posted 22 Jul 2013 Link to this post

    Hello,

    is there a simple way to show a "Loading Data" animation when asynchroniously fetching data?
    In our application we create a RadTabPage with detailed information about a previously double clicked GridViewItem. This RadTabPage contains an empty RadGridView bound to a properly typed DataBindingsource. Until the data was successfully fetched from our database -- which can be time consuming -- the end user only sees this empty grid.

    To communicate to the user that some data will appear, it would be great to overlay the grid with a spinner animation or some textual hint.

    We would prefer a generic approach which only affects the GridView itself so that it can be wrapped into an extension method or extended class.


    Kind regards,
    Andreas Haeusler
  2. George
    Admin
    George avatar
    500 posts

    Posted 24 Jul 2013 Link to this post

    Hi Andreas,

    Thank you for writing.

    There are a few available approaches in your case:
    1. Use a picturebox which can be added to the controls of the grid and position it in the center of the grid. It can be easily toggled to visible and invisible at any given time. Also supports gif images.
    2. Draw the picture directly on top the grid. This approach does not support gif images.
    3. Set the image to the TableElement of the grid. Gifs are supported however the image will stay below the rows, this approach is useful if you are sure that the image will appear only when there are no rows. Additionally this approach requires the least tuning and code.
    I have created a sample project which demonstrates these three possibilities. I have used asynchronous method to recreate a real situation, this should help you decide which approach fits your needs best. Please refer to the attached project.

    I hope this helps, if you have any other questions or comments, please let me know.
     
    Regards,
    George
    Telerik
    TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for WINFORMS.
    Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
    Sign up for Free application insights >>
  3. UI for WinForms is Visual Studio 2017 Ready
  4. Andreas Haeusler
    Andreas Haeusler avatar
    25 posts
    Member since:
    Nov 2009

    Posted 24 Jul 2013 Link to this post

    Thank you George!

    The approach using TableElement.Image proved to be the one of choice!

    I modified my initial version (using a picturebox) and attached it to this post. It contains a custom RadGridView boasting a new method LoadDataAsync(ObjectContext, ProcedureName,params[]) which asynchronously populates the grid with data (showing the loading animation) using an entity framework ObjectContext.
    In case of timeouts or connectivity problems it even allows to retry the data fetching by painting a retry button in place.

    I hope someone finds it useful.


    Thanks again,
    Andreas



    using System;
    using System.Data.Objects;
    using System.Threading;
    using System.Windows.Forms;
    using CustomControlCollection.Properties;
    using Telerik.WinControls.UI;
     
    namespace CustomControlCollection
    {
        public class CustomRadGridView : RadGridView
        {
           
            
     
            public override string ThemeClassName
            {
                get { return typeof(RadGridView).FullName; }
            }
     
           
     
            #region asynchronous loading of data
     
            new public object DataSource  // hide default setter to force either Sync or Async
            {
                get { return base.DataSource; }
                private set { base.DataSource = value; }  // if you really want to set this synchronously use DataSourceSync!
            }
     
            public object DataSourceSync // synchronous setter
            {
                set { base.DataSource = value; }
            }
     
            // delegate and event to notify application of completed data loading process
            public delegate void DataLoadedAsyncHandler(object sender);
            public event DataLoadedAsyncHandler DataLoadedAsync;
     
     
     
     
     
            private readonly RadButton _retryButton = new RadButton { Text = @"Retry", Dock = DockStyle.Fill };
            private readonly RadLabel _retryLabel = new RadLabel { Dock = DockStyle.Fill };
            private string _methodName;
            private object[] _params;
            private Type _objectContextType;
            private readonly System.Drawing.Bitmap _loadingAnimation = Resources.spin_24x24_loading;
     
     
            private void RetryButtonOnClick(object sender, EventArgs eventArgs)
            {
                ToggleRetryButton();
                StartDataFetchingThread();
            }
     
            /// <summary>
            /// Gets data by stored procedure or function call on an objectcontext
            /// </summary>
            /// <param name="exemplaryContext">exemplary instance of the objectcontext to use... a new instance will be created and used</param>
            /// <param name="methodName">Name of the sproc or udf to call</param>
            /// <param name="parameters">parameters for the sproc or udf</param>
            public void LoadDataAsync(ObjectContext exemplaryContext, string methodName, object[] parameters)
            {
                _retryButton.Click -= RetryButtonOnClick;
                _retryButton.Click += RetryButtonOnClick;
                _methodName = methodName;
                _params = parameters;
                _objectContextType = exemplaryContext.GetType();
                StartDataFetchingThread();
            }
     
            private void StartDataFetchingThread()
            {
                var thread = new Thread(FetchData) { IsBackground = true };
                thread.Start();
            }
     
            private void FetchData()
            {
     
                this.InvokeIfRequired(c => ToggleTableElementImage());
     
                if (_objectContextType != null)
                {
                    var cont = Activator.CreateInstance(_objectContextType);
                    var methodInfo = _objectContextType.GetMethod(_methodName);
                    try
                    {
                        object result = methodInfo.Invoke(cont, _params);
                        this.InvokeIfRequired(c =>
                        {
                            DataSource = result;
                        });
     
                    }
                    catch (Exception e) // something went wrong... show retry button
                    {
                        this.InvokeIfRequired(c =>
                        {
                            ToggleTableElementImage();
                            ToggleRetryButton(e.Message);
                        });
                        return;
                    }
                }
     
                this.InvokeIfRequired(c =>
                {
                    if (DataLoadedAsync != null) DataLoadedAsync(this);
                    ToggleTableElementImage();
                });
            }
     
            private void ToggleTableElementImage()
            {
                TableElement.Image = TableElement.Image == null ? _loadingAnimation : null;
            }
     
            private void ToggleRetryButton(string errorDescription = null)
            {
                if (Parent.Controls.Contains(_retryButton))
                {
                    Parent.Controls.Remove(_retryButton);
                    Parent.Controls.Remove(_retryLabel);
                    return;
                }
                int controlIndex = Parent.Controls.GetChildIndex(this); // locate the radgrid position
                _retryLabel.Text = errorDescription;
                Parent.Controls.Add(_retryLabel);
                Parent.Controls.SetChildIndex(_retryLabel, controlIndex++);
                Parent.Controls.Add(_retryButton);
                Parent.Controls.SetChildIndex(_retryButton, controlIndex);
            }
     
     
     
     
            #endregion
     
          
        }
    }

  5. George
    Admin
    George avatar
    500 posts

    Posted 29 Jul 2013 Link to this post

    Hi Andreas,

    Thank you for posting your solution in our forums. I am sure someone will benefit from it.

    If you have any other questions or comments, please let me know.
     
    Regards,
    George
    Telerik
    TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for WINFORMS.
    Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
    Sign up for Free application insights >>
Back to Top