Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

update datagridview very frequently

I'm having trouble refreshing my DataGridView in a reasonable time in C# (which I am new to btw, I'm used to java...).

I'm getting data over a network with 20 packages sent per second. I'd like to parse the data and put it in a DataGridView. I would also like to adjust the interval in which the DataGridView is updated, from 0.1 seconds to 1 minute.

So I created an extra thread, which reads the packages and parses them to an Array. I also have a Timer, which I use to change the Interval. On every timer tick, I reassign the DataSource to the DataGridView.

Interestingly, when I do, even if I set the timer to 0.1 seconds, it is only triggered about once a second. If I do not refresh the DataGridView, it gets triggered 10 times a second, as it is supposed to.

So I am assuming that my method of updating the DataGridView is too time consuming. But what do I have to do to make it more efficient, so I can update it 10 times a second without any problems?

Here is the code I use:

public MyForm()
    {
        InitializeComponent();

        timer = new System.Windows.Forms.Timer();
        timer.Interval = (1 * 1000); // 1 secs
        timer.Tick += new EventHandler(timer_Tick);
        timer.Start();

        readNetworkValues = true;
        networkReader = new Thread(() =>
        {
            Thread.CurrentThread.IsBackground = true;
            byte[] data = new byte[1024];
            IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 49003);
            UdpClient newsock = new UdpClient(ipep);
            IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);

            while (readNetworkValues)
            {
                data = newsock.Receive(ref sender);
                dataSet = parseData(data); //Decrypts the data
            }
        newsock.Close();
        });
        networkReader.Start();
    }

    private void timer_Tick(object sender, EventArgs e)
    {
        if (dataSet != null)
        {
            lock (dataSet)
            {
                int currentRow = dataGrid.FirstDisplayedScrollingRowIndex;
                dataGrid.DataSource = dataSet;
                dataGrid.FirstDisplayedScrollingRowIndex = currentRow;
            }
        }
    }
like image 751
Maverick283 Avatar asked Jan 04 '23 23:01

Maverick283


1 Answers

The number of cells you want to update and also the update rate you want are high enough to cause flicker and lagging.

To avoid it you can turn on DoubleBuffering for the DataGridView.

This property is not exposed by default. So have a have a choice of either

  • creating a subclass or
  • accessing it via reflection

Here is a post that demonstrates the former. It was written for a case of scrolling flicker but will help avoid update lags as well. The class can maybe look like this:

public class DBDataGridView : DataGridView
{
    public new bool DoubleBuffered
    {
        get { return base.DoubleBuffered; }
        set { base.DoubleBuffered = value; }
    }

    public DBDataGridView()
    {
        DoubleBuffered = true;
    }
}

You can add this class to the project or simply to the form class (before the very last curly.) Compile and it will show up in the ToolBox.

The other option uses reflection; here is a general-purpose function that should work for for any type of control:

using System.Reflection;

static void SetDoubleBuffer(Control ctl, bool DoubleBuffered)
{
    typeof(Control).InvokeMember("DoubleBuffered", 
        BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty, 
        null, ctl, new object[] { DoubleBuffered });
}

Both ways let you turn DoubleBuffering on and off at will; the former via the now exposed property, the latter by the bool param of the method.

like image 85
TaW Avatar answered Jan 15 '23 11:01

TaW