Why does my C# Winforms program with a timer get bogged down after a day?












0















I have a program that updates two DataGridView objects every minute with a MySQL query from our internal orders database so we can keep track of older orders and make sure they're being handled.



It works well, but if you leave the program on it starts to get slower and slower and you really notice it after a day or so. Restarting the program fixes this, but I'd really like to know why I can't just leave this running.



Here is the timer code and the function it calls:



    private void timer1_Tick(object sender, EventArgs e)
{
UpdateOrderDisplay();
}

private void UpdateOrderDisplay()
{
grdOrderItems.Rows.Clear();
grdHoldOrders.Rows.Clear();
string strsql;
string CustomerName;
string MyConString = "SERVER=**********;" + "DATABASE=***********;" + "UID=************;" + "PASSWORD=***********;";
using (MySqlConnection connection = new MySqlConnection(MyConString))
{
MySqlCommand command = connection.CreateCommand();
MySqlDataReader Reader;
strsql = "select * from orders where ship_reference=0 and OnHold =0 order by order_id asc";
command.CommandText = strsql;
connection.Open(); Reader = command.ExecuteReader();
while (Reader.Read())
{
if (Reader["payment_date"].ToString() != "")
{
if (Reader["custom"].ToString().Contains("~*"))
{
CustomerName = Reader["custom"].ToString().Substring(0, Reader["custom"].ToString().IndexOf("~"));
}
else
{
CustomerName = Reader["shipping_address_name"].ToString();
}
grdOrderItems.Invoke(new MethodInvoker(() => grdOrderItems.Rows.Add(Convert.ToDateTime(Reader["payment_date"].ToString().Substring(0, 21)).ToString(), Reader["txn_id"].ToString(), CustomerName, Reader["mc_gross"].ToString(), Reader["memo"].ToString(), Reader["order_id"].ToString())));
}
}
connection.Close();
strsql = "select * from orders where OnHold =1 order by order_id asc";
command.CommandText = strsql;
connection.Open(); Reader = command.ExecuteReader();
while (Reader.Read())
{
if (Reader["payment_date"].ToString() != "")
{
if (Reader["custom"].ToString().Contains("~*"))
{
CustomerName = Reader["custom"].ToString().Substring(0, Reader["custom"].ToString().IndexOf("~"));
}
else
{
CustomerName = Reader["shipping_address_name"].ToString();
}
grdHoldOrders.Invoke(new MethodInvoker(() => grdHoldOrders.Rows.Add(Convert.ToDateTime(Reader["payment_date"].ToString().Substring(0, 21)).ToString(), Reader["txn_id"].ToString(), CustomerName, Reader["mc_gross"].ToString(), Reader["memo"].ToString(), Reader["order_id"].ToString(),Reader["Hold_Review_Date"].ToString().Substring(0,Reader["Hold_Review_Date"].ToString().IndexOf(" ")),Reader["payer_email"].ToString())));
}
}





connection.Close();
}

}


Also, in case it's relevant, here is some code I use to color code the lines of the DataGridView object so we can easily tell which order is older:



    private void grdOrderItems_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
{
grdOrderItems.RowPrePaint += new System.Windows.Forms.DataGridViewRowPrePaintEventHandler(this.grdOrderItems1_RowPrePaint);

}
private void grdOrderItems1_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
{
if (e.RowIndex <= grdOrderItems.Rows.Count - 1)
{
string StringNow = DateTime.Now.ToString();
string NowTime = StringNow.Substring(StringNow.IndexOf(" ")+1, StringNow.Length- StringNow.IndexOf(" ")-1);
string OrderDateTime = grdOrderItems.Rows[e.RowIndex].Cells[0].Value.ToString().Substring(0, grdOrderItems.Rows[e.RowIndex].Cells[0].Value.ToString().IndexOf(" ")+1) + NowTime;
if ((Convert.ToDateTime(StringNow) - Convert.ToDateTime(OrderDateTime)).Days > 2)
{
grdOrderItems.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Tomato;
}
else
{
if ((Convert.ToDateTime(StringNow) - Convert.ToDateTime(OrderDateTime)).Days > 1)
{
grdOrderItems.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Yellow;
}
else
{
if ((Convert.ToDateTime(StringNow) - Convert.ToDateTime(OrderDateTime)).Days > 0)
{
grdOrderItems.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Tan;
}

}
}
}
}









share|improve this question























  • Dispose those Commands.

    – GSerg
    Nov 13 '18 at 18:13






  • 1





    Yeah, close the reader explicitly after use (or put it in a using), would be my first thing to change.

    – 500 - Internal Server Error
    Nov 13 '18 at 18:15






  • 3





    Is the grdOrderItems_RowPrePaint an actual live handler that also fires? If so, you are adding another subscriber to grdOrderItems.RowPrePaint each time it fires, and after a while each grdOrderItems.RowPrePaint will cause thousands of executions of this.grdOrderItems1_RowPrePaint.

    – GSerg
    Nov 13 '18 at 18:15








  • 1





    @MatheusRocha No it won't. It will continue to exist until collected by the garbage collector, which may not happen in a while. That is precisely the reason why IDisposable exists.

    – GSerg
    Nov 13 '18 at 18:23






  • 1





    You don't need to close and re-open the connection in between the two commands.

    – Joel Coehoorn
    Nov 13 '18 at 18:31
















0















I have a program that updates two DataGridView objects every minute with a MySQL query from our internal orders database so we can keep track of older orders and make sure they're being handled.



It works well, but if you leave the program on it starts to get slower and slower and you really notice it after a day or so. Restarting the program fixes this, but I'd really like to know why I can't just leave this running.



Here is the timer code and the function it calls:



    private void timer1_Tick(object sender, EventArgs e)
{
UpdateOrderDisplay();
}

private void UpdateOrderDisplay()
{
grdOrderItems.Rows.Clear();
grdHoldOrders.Rows.Clear();
string strsql;
string CustomerName;
string MyConString = "SERVER=**********;" + "DATABASE=***********;" + "UID=************;" + "PASSWORD=***********;";
using (MySqlConnection connection = new MySqlConnection(MyConString))
{
MySqlCommand command = connection.CreateCommand();
MySqlDataReader Reader;
strsql = "select * from orders where ship_reference=0 and OnHold =0 order by order_id asc";
command.CommandText = strsql;
connection.Open(); Reader = command.ExecuteReader();
while (Reader.Read())
{
if (Reader["payment_date"].ToString() != "")
{
if (Reader["custom"].ToString().Contains("~*"))
{
CustomerName = Reader["custom"].ToString().Substring(0, Reader["custom"].ToString().IndexOf("~"));
}
else
{
CustomerName = Reader["shipping_address_name"].ToString();
}
grdOrderItems.Invoke(new MethodInvoker(() => grdOrderItems.Rows.Add(Convert.ToDateTime(Reader["payment_date"].ToString().Substring(0, 21)).ToString(), Reader["txn_id"].ToString(), CustomerName, Reader["mc_gross"].ToString(), Reader["memo"].ToString(), Reader["order_id"].ToString())));
}
}
connection.Close();
strsql = "select * from orders where OnHold =1 order by order_id asc";
command.CommandText = strsql;
connection.Open(); Reader = command.ExecuteReader();
while (Reader.Read())
{
if (Reader["payment_date"].ToString() != "")
{
if (Reader["custom"].ToString().Contains("~*"))
{
CustomerName = Reader["custom"].ToString().Substring(0, Reader["custom"].ToString().IndexOf("~"));
}
else
{
CustomerName = Reader["shipping_address_name"].ToString();
}
grdHoldOrders.Invoke(new MethodInvoker(() => grdHoldOrders.Rows.Add(Convert.ToDateTime(Reader["payment_date"].ToString().Substring(0, 21)).ToString(), Reader["txn_id"].ToString(), CustomerName, Reader["mc_gross"].ToString(), Reader["memo"].ToString(), Reader["order_id"].ToString(),Reader["Hold_Review_Date"].ToString().Substring(0,Reader["Hold_Review_Date"].ToString().IndexOf(" ")),Reader["payer_email"].ToString())));
}
}





connection.Close();
}

}


Also, in case it's relevant, here is some code I use to color code the lines of the DataGridView object so we can easily tell which order is older:



    private void grdOrderItems_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
{
grdOrderItems.RowPrePaint += new System.Windows.Forms.DataGridViewRowPrePaintEventHandler(this.grdOrderItems1_RowPrePaint);

}
private void grdOrderItems1_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
{
if (e.RowIndex <= grdOrderItems.Rows.Count - 1)
{
string StringNow = DateTime.Now.ToString();
string NowTime = StringNow.Substring(StringNow.IndexOf(" ")+1, StringNow.Length- StringNow.IndexOf(" ")-1);
string OrderDateTime = grdOrderItems.Rows[e.RowIndex].Cells[0].Value.ToString().Substring(0, grdOrderItems.Rows[e.RowIndex].Cells[0].Value.ToString().IndexOf(" ")+1) + NowTime;
if ((Convert.ToDateTime(StringNow) - Convert.ToDateTime(OrderDateTime)).Days > 2)
{
grdOrderItems.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Tomato;
}
else
{
if ((Convert.ToDateTime(StringNow) - Convert.ToDateTime(OrderDateTime)).Days > 1)
{
grdOrderItems.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Yellow;
}
else
{
if ((Convert.ToDateTime(StringNow) - Convert.ToDateTime(OrderDateTime)).Days > 0)
{
grdOrderItems.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Tan;
}

}
}
}
}









share|improve this question























  • Dispose those Commands.

    – GSerg
    Nov 13 '18 at 18:13






  • 1





    Yeah, close the reader explicitly after use (or put it in a using), would be my first thing to change.

    – 500 - Internal Server Error
    Nov 13 '18 at 18:15






  • 3





    Is the grdOrderItems_RowPrePaint an actual live handler that also fires? If so, you are adding another subscriber to grdOrderItems.RowPrePaint each time it fires, and after a while each grdOrderItems.RowPrePaint will cause thousands of executions of this.grdOrderItems1_RowPrePaint.

    – GSerg
    Nov 13 '18 at 18:15








  • 1





    @MatheusRocha No it won't. It will continue to exist until collected by the garbage collector, which may not happen in a while. That is precisely the reason why IDisposable exists.

    – GSerg
    Nov 13 '18 at 18:23






  • 1





    You don't need to close and re-open the connection in between the two commands.

    – Joel Coehoorn
    Nov 13 '18 at 18:31














0












0








0








I have a program that updates two DataGridView objects every minute with a MySQL query from our internal orders database so we can keep track of older orders and make sure they're being handled.



It works well, but if you leave the program on it starts to get slower and slower and you really notice it after a day or so. Restarting the program fixes this, but I'd really like to know why I can't just leave this running.



Here is the timer code and the function it calls:



    private void timer1_Tick(object sender, EventArgs e)
{
UpdateOrderDisplay();
}

private void UpdateOrderDisplay()
{
grdOrderItems.Rows.Clear();
grdHoldOrders.Rows.Clear();
string strsql;
string CustomerName;
string MyConString = "SERVER=**********;" + "DATABASE=***********;" + "UID=************;" + "PASSWORD=***********;";
using (MySqlConnection connection = new MySqlConnection(MyConString))
{
MySqlCommand command = connection.CreateCommand();
MySqlDataReader Reader;
strsql = "select * from orders where ship_reference=0 and OnHold =0 order by order_id asc";
command.CommandText = strsql;
connection.Open(); Reader = command.ExecuteReader();
while (Reader.Read())
{
if (Reader["payment_date"].ToString() != "")
{
if (Reader["custom"].ToString().Contains("~*"))
{
CustomerName = Reader["custom"].ToString().Substring(0, Reader["custom"].ToString().IndexOf("~"));
}
else
{
CustomerName = Reader["shipping_address_name"].ToString();
}
grdOrderItems.Invoke(new MethodInvoker(() => grdOrderItems.Rows.Add(Convert.ToDateTime(Reader["payment_date"].ToString().Substring(0, 21)).ToString(), Reader["txn_id"].ToString(), CustomerName, Reader["mc_gross"].ToString(), Reader["memo"].ToString(), Reader["order_id"].ToString())));
}
}
connection.Close();
strsql = "select * from orders where OnHold =1 order by order_id asc";
command.CommandText = strsql;
connection.Open(); Reader = command.ExecuteReader();
while (Reader.Read())
{
if (Reader["payment_date"].ToString() != "")
{
if (Reader["custom"].ToString().Contains("~*"))
{
CustomerName = Reader["custom"].ToString().Substring(0, Reader["custom"].ToString().IndexOf("~"));
}
else
{
CustomerName = Reader["shipping_address_name"].ToString();
}
grdHoldOrders.Invoke(new MethodInvoker(() => grdHoldOrders.Rows.Add(Convert.ToDateTime(Reader["payment_date"].ToString().Substring(0, 21)).ToString(), Reader["txn_id"].ToString(), CustomerName, Reader["mc_gross"].ToString(), Reader["memo"].ToString(), Reader["order_id"].ToString(),Reader["Hold_Review_Date"].ToString().Substring(0,Reader["Hold_Review_Date"].ToString().IndexOf(" ")),Reader["payer_email"].ToString())));
}
}





connection.Close();
}

}


Also, in case it's relevant, here is some code I use to color code the lines of the DataGridView object so we can easily tell which order is older:



    private void grdOrderItems_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
{
grdOrderItems.RowPrePaint += new System.Windows.Forms.DataGridViewRowPrePaintEventHandler(this.grdOrderItems1_RowPrePaint);

}
private void grdOrderItems1_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
{
if (e.RowIndex <= grdOrderItems.Rows.Count - 1)
{
string StringNow = DateTime.Now.ToString();
string NowTime = StringNow.Substring(StringNow.IndexOf(" ")+1, StringNow.Length- StringNow.IndexOf(" ")-1);
string OrderDateTime = grdOrderItems.Rows[e.RowIndex].Cells[0].Value.ToString().Substring(0, grdOrderItems.Rows[e.RowIndex].Cells[0].Value.ToString().IndexOf(" ")+1) + NowTime;
if ((Convert.ToDateTime(StringNow) - Convert.ToDateTime(OrderDateTime)).Days > 2)
{
grdOrderItems.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Tomato;
}
else
{
if ((Convert.ToDateTime(StringNow) - Convert.ToDateTime(OrderDateTime)).Days > 1)
{
grdOrderItems.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Yellow;
}
else
{
if ((Convert.ToDateTime(StringNow) - Convert.ToDateTime(OrderDateTime)).Days > 0)
{
grdOrderItems.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Tan;
}

}
}
}
}









share|improve this question














I have a program that updates two DataGridView objects every minute with a MySQL query from our internal orders database so we can keep track of older orders and make sure they're being handled.



It works well, but if you leave the program on it starts to get slower and slower and you really notice it after a day or so. Restarting the program fixes this, but I'd really like to know why I can't just leave this running.



Here is the timer code and the function it calls:



    private void timer1_Tick(object sender, EventArgs e)
{
UpdateOrderDisplay();
}

private void UpdateOrderDisplay()
{
grdOrderItems.Rows.Clear();
grdHoldOrders.Rows.Clear();
string strsql;
string CustomerName;
string MyConString = "SERVER=**********;" + "DATABASE=***********;" + "UID=************;" + "PASSWORD=***********;";
using (MySqlConnection connection = new MySqlConnection(MyConString))
{
MySqlCommand command = connection.CreateCommand();
MySqlDataReader Reader;
strsql = "select * from orders where ship_reference=0 and OnHold =0 order by order_id asc";
command.CommandText = strsql;
connection.Open(); Reader = command.ExecuteReader();
while (Reader.Read())
{
if (Reader["payment_date"].ToString() != "")
{
if (Reader["custom"].ToString().Contains("~*"))
{
CustomerName = Reader["custom"].ToString().Substring(0, Reader["custom"].ToString().IndexOf("~"));
}
else
{
CustomerName = Reader["shipping_address_name"].ToString();
}
grdOrderItems.Invoke(new MethodInvoker(() => grdOrderItems.Rows.Add(Convert.ToDateTime(Reader["payment_date"].ToString().Substring(0, 21)).ToString(), Reader["txn_id"].ToString(), CustomerName, Reader["mc_gross"].ToString(), Reader["memo"].ToString(), Reader["order_id"].ToString())));
}
}
connection.Close();
strsql = "select * from orders where OnHold =1 order by order_id asc";
command.CommandText = strsql;
connection.Open(); Reader = command.ExecuteReader();
while (Reader.Read())
{
if (Reader["payment_date"].ToString() != "")
{
if (Reader["custom"].ToString().Contains("~*"))
{
CustomerName = Reader["custom"].ToString().Substring(0, Reader["custom"].ToString().IndexOf("~"));
}
else
{
CustomerName = Reader["shipping_address_name"].ToString();
}
grdHoldOrders.Invoke(new MethodInvoker(() => grdHoldOrders.Rows.Add(Convert.ToDateTime(Reader["payment_date"].ToString().Substring(0, 21)).ToString(), Reader["txn_id"].ToString(), CustomerName, Reader["mc_gross"].ToString(), Reader["memo"].ToString(), Reader["order_id"].ToString(),Reader["Hold_Review_Date"].ToString().Substring(0,Reader["Hold_Review_Date"].ToString().IndexOf(" ")),Reader["payer_email"].ToString())));
}
}





connection.Close();
}

}


Also, in case it's relevant, here is some code I use to color code the lines of the DataGridView object so we can easily tell which order is older:



    private void grdOrderItems_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
{
grdOrderItems.RowPrePaint += new System.Windows.Forms.DataGridViewRowPrePaintEventHandler(this.grdOrderItems1_RowPrePaint);

}
private void grdOrderItems1_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
{
if (e.RowIndex <= grdOrderItems.Rows.Count - 1)
{
string StringNow = DateTime.Now.ToString();
string NowTime = StringNow.Substring(StringNow.IndexOf(" ")+1, StringNow.Length- StringNow.IndexOf(" ")-1);
string OrderDateTime = grdOrderItems.Rows[e.RowIndex].Cells[0].Value.ToString().Substring(0, grdOrderItems.Rows[e.RowIndex].Cells[0].Value.ToString().IndexOf(" ")+1) + NowTime;
if ((Convert.ToDateTime(StringNow) - Convert.ToDateTime(OrderDateTime)).Days > 2)
{
grdOrderItems.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Tomato;
}
else
{
if ((Convert.ToDateTime(StringNow) - Convert.ToDateTime(OrderDateTime)).Days > 1)
{
grdOrderItems.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Yellow;
}
else
{
if ((Convert.ToDateTime(StringNow) - Convert.ToDateTime(OrderDateTime)).Days > 0)
{
grdOrderItems.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Tan;
}

}
}
}
}






c# mysql winforms datagridview timer






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 13 '18 at 18:08









Alan DenkeAlan Denke

325




325













  • Dispose those Commands.

    – GSerg
    Nov 13 '18 at 18:13






  • 1





    Yeah, close the reader explicitly after use (or put it in a using), would be my first thing to change.

    – 500 - Internal Server Error
    Nov 13 '18 at 18:15






  • 3





    Is the grdOrderItems_RowPrePaint an actual live handler that also fires? If so, you are adding another subscriber to grdOrderItems.RowPrePaint each time it fires, and after a while each grdOrderItems.RowPrePaint will cause thousands of executions of this.grdOrderItems1_RowPrePaint.

    – GSerg
    Nov 13 '18 at 18:15








  • 1





    @MatheusRocha No it won't. It will continue to exist until collected by the garbage collector, which may not happen in a while. That is precisely the reason why IDisposable exists.

    – GSerg
    Nov 13 '18 at 18:23






  • 1





    You don't need to close and re-open the connection in between the two commands.

    – Joel Coehoorn
    Nov 13 '18 at 18:31



















  • Dispose those Commands.

    – GSerg
    Nov 13 '18 at 18:13






  • 1





    Yeah, close the reader explicitly after use (or put it in a using), would be my first thing to change.

    – 500 - Internal Server Error
    Nov 13 '18 at 18:15






  • 3





    Is the grdOrderItems_RowPrePaint an actual live handler that also fires? If so, you are adding another subscriber to grdOrderItems.RowPrePaint each time it fires, and after a while each grdOrderItems.RowPrePaint will cause thousands of executions of this.grdOrderItems1_RowPrePaint.

    – GSerg
    Nov 13 '18 at 18:15








  • 1





    @MatheusRocha No it won't. It will continue to exist until collected by the garbage collector, which may not happen in a while. That is precisely the reason why IDisposable exists.

    – GSerg
    Nov 13 '18 at 18:23






  • 1





    You don't need to close and re-open the connection in between the two commands.

    – Joel Coehoorn
    Nov 13 '18 at 18:31

















Dispose those Commands.

– GSerg
Nov 13 '18 at 18:13





Dispose those Commands.

– GSerg
Nov 13 '18 at 18:13




1




1





Yeah, close the reader explicitly after use (or put it in a using), would be my first thing to change.

– 500 - Internal Server Error
Nov 13 '18 at 18:15





Yeah, close the reader explicitly after use (or put it in a using), would be my first thing to change.

– 500 - Internal Server Error
Nov 13 '18 at 18:15




3




3





Is the grdOrderItems_RowPrePaint an actual live handler that also fires? If so, you are adding another subscriber to grdOrderItems.RowPrePaint each time it fires, and after a while each grdOrderItems.RowPrePaint will cause thousands of executions of this.grdOrderItems1_RowPrePaint.

– GSerg
Nov 13 '18 at 18:15







Is the grdOrderItems_RowPrePaint an actual live handler that also fires? If so, you are adding another subscriber to grdOrderItems.RowPrePaint each time it fires, and after a while each grdOrderItems.RowPrePaint will cause thousands of executions of this.grdOrderItems1_RowPrePaint.

– GSerg
Nov 13 '18 at 18:15






1




1





@MatheusRocha No it won't. It will continue to exist until collected by the garbage collector, which may not happen in a while. That is precisely the reason why IDisposable exists.

– GSerg
Nov 13 '18 at 18:23





@MatheusRocha No it won't. It will continue to exist until collected by the garbage collector, which may not happen in a while. That is precisely the reason why IDisposable exists.

– GSerg
Nov 13 '18 at 18:23




1




1





You don't need to close and re-open the connection in between the two commands.

– Joel Coehoorn
Nov 13 '18 at 18:31





You don't need to close and re-open the connection in between the two commands.

– Joel Coehoorn
Nov 13 '18 at 18:31












2 Answers
2






active

oldest

votes


















3














You probably have a MySqlDataReader leak. When you're done with each Reader object, dispose of it. This is a good way to make that happen; it's resilient against exceptions, and the reader variable goes out of scope at the end of the using.



    using (var reader = command.ExecuteReader()
{
while (reader.Read())
{
/* your per-row logic here */
}
}


You can also do this with Close():



    MySqlDataReader Reader; 
...
Reader = command.ExecuteReader()
while (Reader.Read())
{
/* your per-row logic here */
}
Reader.Close();


You are closing and reopening the Connection for each query. That's not necessary. Open it once, use it for both queries, and then close it.



You might consider keeping your Connection open for longer than a single timer tick. (If you have a connection pool, ignore this advice.)



Use the Task Manager to see how much cpu% and memory your program takes up (in the morning and again in the evening). If the memory is growing, you have some kind of leak. If the cpu% is growing, you have some sort of list processing going on where the list gets longer with every tick.






share|improve this answer


























  • For the last, it depends on the tick length, and a full minute connection pooling means he probably really does want a new connection object with each tick. In my experience, anything more than a few seconds idle and it's best to let the prior connection object dispose. But you're right that he should be able to re-use a single connection for the whole tick even handler method.

    – Joel Coehoorn
    Nov 13 '18 at 18:33








  • 1





    A red note on the RowPrePaint event that adds a new handler (grdOrderItems.RowPrePaint += new (...)) each time is raised. That's going to kill everything. I'm surprised it goes on a whole day.

    – Jimi
    Nov 13 '18 at 18:48













  • @Jimi You should add that as an answer. I missed that first time through, but it's definitely a factor, if not the entire problem.

    – Joel Coehoorn
    Nov 13 '18 at 19:02











  • @Joel Coehoorn It would be interesting to ask the OP whether this is some kind of style and it's, possibly, applied elsewhere. Anyway, there are already two answers to this question and, now I see, a bunch of comments that point this out. You two should pick it up, I think.

    – Jimi
    Nov 13 '18 at 19:15



















2














I don't have enough info for a complete answer, except to say this smells like a large object heap issue, where one of the fields you retrieve from the database will occasionally be longer than the 85K LOH threshold.



What I can do, and it might even help, is show you how to greatly simplify and improve the prepaint method like this:



private void grdOrderItems1_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
{
if (e.RowIndex > grdOrderItems.Rows.Count - 1) return;
var row = grdOrderItems.Rows[e.RowIndex];

TimeSpan timeOfDay = DateTime.Now - DateTime.Today;
//It *looks like* Cells[0].Value is already a DateTime, but I'm not 100% on this
// If I'm wrong and it's a string, its worth it to parse just that one value to a DateTime here, and still plug that DateTime value into this code instead of the Cell.
DateTime OrderDateTime = ((DateTime)row.Cells[0].Value).Date + timeOfDay;

var days = (DateTime.Now - OrderDateTime).TotalDays;
if (days > 2)
{
row.DefaultCellStyle.BackColor = Color.Tomato;
}
else if (days > 1)
{
row.DefaultCellStyle.BackColor = Color.Yellow;
}
else if (days > 0)
{
row.DefaultCellStyle.BackColor = Color.Tan;
}
}


This reduces nesting and extra blocks, making it a lot easier to understand, and it probably runs in less than half the time because of the reduced back-and-forth between string and DateTime values. The cultural/internationalization issues make converting between DateTime and string in either direction an inherently slow and error-prone operation.






share|improve this answer

























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53287079%2fwhy-does-my-c-sharp-winforms-program-with-a-timer-get-bogged-down-after-a-day%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    3














    You probably have a MySqlDataReader leak. When you're done with each Reader object, dispose of it. This is a good way to make that happen; it's resilient against exceptions, and the reader variable goes out of scope at the end of the using.



        using (var reader = command.ExecuteReader()
    {
    while (reader.Read())
    {
    /* your per-row logic here */
    }
    }


    You can also do this with Close():



        MySqlDataReader Reader; 
    ...
    Reader = command.ExecuteReader()
    while (Reader.Read())
    {
    /* your per-row logic here */
    }
    Reader.Close();


    You are closing and reopening the Connection for each query. That's not necessary. Open it once, use it for both queries, and then close it.



    You might consider keeping your Connection open for longer than a single timer tick. (If you have a connection pool, ignore this advice.)



    Use the Task Manager to see how much cpu% and memory your program takes up (in the morning and again in the evening). If the memory is growing, you have some kind of leak. If the cpu% is growing, you have some sort of list processing going on where the list gets longer with every tick.






    share|improve this answer


























    • For the last, it depends on the tick length, and a full minute connection pooling means he probably really does want a new connection object with each tick. In my experience, anything more than a few seconds idle and it's best to let the prior connection object dispose. But you're right that he should be able to re-use a single connection for the whole tick even handler method.

      – Joel Coehoorn
      Nov 13 '18 at 18:33








    • 1





      A red note on the RowPrePaint event that adds a new handler (grdOrderItems.RowPrePaint += new (...)) each time is raised. That's going to kill everything. I'm surprised it goes on a whole day.

      – Jimi
      Nov 13 '18 at 18:48













    • @Jimi You should add that as an answer. I missed that first time through, but it's definitely a factor, if not the entire problem.

      – Joel Coehoorn
      Nov 13 '18 at 19:02











    • @Joel Coehoorn It would be interesting to ask the OP whether this is some kind of style and it's, possibly, applied elsewhere. Anyway, there are already two answers to this question and, now I see, a bunch of comments that point this out. You two should pick it up, I think.

      – Jimi
      Nov 13 '18 at 19:15
















    3














    You probably have a MySqlDataReader leak. When you're done with each Reader object, dispose of it. This is a good way to make that happen; it's resilient against exceptions, and the reader variable goes out of scope at the end of the using.



        using (var reader = command.ExecuteReader()
    {
    while (reader.Read())
    {
    /* your per-row logic here */
    }
    }


    You can also do this with Close():



        MySqlDataReader Reader; 
    ...
    Reader = command.ExecuteReader()
    while (Reader.Read())
    {
    /* your per-row logic here */
    }
    Reader.Close();


    You are closing and reopening the Connection for each query. That's not necessary. Open it once, use it for both queries, and then close it.



    You might consider keeping your Connection open for longer than a single timer tick. (If you have a connection pool, ignore this advice.)



    Use the Task Manager to see how much cpu% and memory your program takes up (in the morning and again in the evening). If the memory is growing, you have some kind of leak. If the cpu% is growing, you have some sort of list processing going on where the list gets longer with every tick.






    share|improve this answer


























    • For the last, it depends on the tick length, and a full minute connection pooling means he probably really does want a new connection object with each tick. In my experience, anything more than a few seconds idle and it's best to let the prior connection object dispose. But you're right that he should be able to re-use a single connection for the whole tick even handler method.

      – Joel Coehoorn
      Nov 13 '18 at 18:33








    • 1





      A red note on the RowPrePaint event that adds a new handler (grdOrderItems.RowPrePaint += new (...)) each time is raised. That's going to kill everything. I'm surprised it goes on a whole day.

      – Jimi
      Nov 13 '18 at 18:48













    • @Jimi You should add that as an answer. I missed that first time through, but it's definitely a factor, if not the entire problem.

      – Joel Coehoorn
      Nov 13 '18 at 19:02











    • @Joel Coehoorn It would be interesting to ask the OP whether this is some kind of style and it's, possibly, applied elsewhere. Anyway, there are already two answers to this question and, now I see, a bunch of comments that point this out. You two should pick it up, I think.

      – Jimi
      Nov 13 '18 at 19:15














    3












    3








    3







    You probably have a MySqlDataReader leak. When you're done with each Reader object, dispose of it. This is a good way to make that happen; it's resilient against exceptions, and the reader variable goes out of scope at the end of the using.



        using (var reader = command.ExecuteReader()
    {
    while (reader.Read())
    {
    /* your per-row logic here */
    }
    }


    You can also do this with Close():



        MySqlDataReader Reader; 
    ...
    Reader = command.ExecuteReader()
    while (Reader.Read())
    {
    /* your per-row logic here */
    }
    Reader.Close();


    You are closing and reopening the Connection for each query. That's not necessary. Open it once, use it for both queries, and then close it.



    You might consider keeping your Connection open for longer than a single timer tick. (If you have a connection pool, ignore this advice.)



    Use the Task Manager to see how much cpu% and memory your program takes up (in the morning and again in the evening). If the memory is growing, you have some kind of leak. If the cpu% is growing, you have some sort of list processing going on where the list gets longer with every tick.






    share|improve this answer















    You probably have a MySqlDataReader leak. When you're done with each Reader object, dispose of it. This is a good way to make that happen; it's resilient against exceptions, and the reader variable goes out of scope at the end of the using.



        using (var reader = command.ExecuteReader()
    {
    while (reader.Read())
    {
    /* your per-row logic here */
    }
    }


    You can also do this with Close():



        MySqlDataReader Reader; 
    ...
    Reader = command.ExecuteReader()
    while (Reader.Read())
    {
    /* your per-row logic here */
    }
    Reader.Close();


    You are closing and reopening the Connection for each query. That's not necessary. Open it once, use it for both queries, and then close it.



    You might consider keeping your Connection open for longer than a single timer tick. (If you have a connection pool, ignore this advice.)



    Use the Task Manager to see how much cpu% and memory your program takes up (in the morning and again in the evening). If the memory is growing, you have some kind of leak. If the cpu% is growing, you have some sort of list processing going on where the list gets longer with every tick.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 13 '18 at 18:42

























    answered Nov 13 '18 at 18:25









    O. JonesO. Jones

    59.8k972106




    59.8k972106













    • For the last, it depends on the tick length, and a full minute connection pooling means he probably really does want a new connection object with each tick. In my experience, anything more than a few seconds idle and it's best to let the prior connection object dispose. But you're right that he should be able to re-use a single connection for the whole tick even handler method.

      – Joel Coehoorn
      Nov 13 '18 at 18:33








    • 1





      A red note on the RowPrePaint event that adds a new handler (grdOrderItems.RowPrePaint += new (...)) each time is raised. That's going to kill everything. I'm surprised it goes on a whole day.

      – Jimi
      Nov 13 '18 at 18:48













    • @Jimi You should add that as an answer. I missed that first time through, but it's definitely a factor, if not the entire problem.

      – Joel Coehoorn
      Nov 13 '18 at 19:02











    • @Joel Coehoorn It would be interesting to ask the OP whether this is some kind of style and it's, possibly, applied elsewhere. Anyway, there are already two answers to this question and, now I see, a bunch of comments that point this out. You two should pick it up, I think.

      – Jimi
      Nov 13 '18 at 19:15



















    • For the last, it depends on the tick length, and a full minute connection pooling means he probably really does want a new connection object with each tick. In my experience, anything more than a few seconds idle and it's best to let the prior connection object dispose. But you're right that he should be able to re-use a single connection for the whole tick even handler method.

      – Joel Coehoorn
      Nov 13 '18 at 18:33








    • 1





      A red note on the RowPrePaint event that adds a new handler (grdOrderItems.RowPrePaint += new (...)) each time is raised. That's going to kill everything. I'm surprised it goes on a whole day.

      – Jimi
      Nov 13 '18 at 18:48













    • @Jimi You should add that as an answer. I missed that first time through, but it's definitely a factor, if not the entire problem.

      – Joel Coehoorn
      Nov 13 '18 at 19:02











    • @Joel Coehoorn It would be interesting to ask the OP whether this is some kind of style and it's, possibly, applied elsewhere. Anyway, there are already two answers to this question and, now I see, a bunch of comments that point this out. You two should pick it up, I think.

      – Jimi
      Nov 13 '18 at 19:15

















    For the last, it depends on the tick length, and a full minute connection pooling means he probably really does want a new connection object with each tick. In my experience, anything more than a few seconds idle and it's best to let the prior connection object dispose. But you're right that he should be able to re-use a single connection for the whole tick even handler method.

    – Joel Coehoorn
    Nov 13 '18 at 18:33







    For the last, it depends on the tick length, and a full minute connection pooling means he probably really does want a new connection object with each tick. In my experience, anything more than a few seconds idle and it's best to let the prior connection object dispose. But you're right that he should be able to re-use a single connection for the whole tick even handler method.

    – Joel Coehoorn
    Nov 13 '18 at 18:33






    1




    1





    A red note on the RowPrePaint event that adds a new handler (grdOrderItems.RowPrePaint += new (...)) each time is raised. That's going to kill everything. I'm surprised it goes on a whole day.

    – Jimi
    Nov 13 '18 at 18:48







    A red note on the RowPrePaint event that adds a new handler (grdOrderItems.RowPrePaint += new (...)) each time is raised. That's going to kill everything. I'm surprised it goes on a whole day.

    – Jimi
    Nov 13 '18 at 18:48















    @Jimi You should add that as an answer. I missed that first time through, but it's definitely a factor, if not the entire problem.

    – Joel Coehoorn
    Nov 13 '18 at 19:02





    @Jimi You should add that as an answer. I missed that first time through, but it's definitely a factor, if not the entire problem.

    – Joel Coehoorn
    Nov 13 '18 at 19:02













    @Joel Coehoorn It would be interesting to ask the OP whether this is some kind of style and it's, possibly, applied elsewhere. Anyway, there are already two answers to this question and, now I see, a bunch of comments that point this out. You two should pick it up, I think.

    – Jimi
    Nov 13 '18 at 19:15





    @Joel Coehoorn It would be interesting to ask the OP whether this is some kind of style and it's, possibly, applied elsewhere. Anyway, there are already two answers to this question and, now I see, a bunch of comments that point this out. You two should pick it up, I think.

    – Jimi
    Nov 13 '18 at 19:15













    2














    I don't have enough info for a complete answer, except to say this smells like a large object heap issue, where one of the fields you retrieve from the database will occasionally be longer than the 85K LOH threshold.



    What I can do, and it might even help, is show you how to greatly simplify and improve the prepaint method like this:



    private void grdOrderItems1_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
    {
    if (e.RowIndex > grdOrderItems.Rows.Count - 1) return;
    var row = grdOrderItems.Rows[e.RowIndex];

    TimeSpan timeOfDay = DateTime.Now - DateTime.Today;
    //It *looks like* Cells[0].Value is already a DateTime, but I'm not 100% on this
    // If I'm wrong and it's a string, its worth it to parse just that one value to a DateTime here, and still plug that DateTime value into this code instead of the Cell.
    DateTime OrderDateTime = ((DateTime)row.Cells[0].Value).Date + timeOfDay;

    var days = (DateTime.Now - OrderDateTime).TotalDays;
    if (days > 2)
    {
    row.DefaultCellStyle.BackColor = Color.Tomato;
    }
    else if (days > 1)
    {
    row.DefaultCellStyle.BackColor = Color.Yellow;
    }
    else if (days > 0)
    {
    row.DefaultCellStyle.BackColor = Color.Tan;
    }
    }


    This reduces nesting and extra blocks, making it a lot easier to understand, and it probably runs in less than half the time because of the reduced back-and-forth between string and DateTime values. The cultural/internationalization issues make converting between DateTime and string in either direction an inherently slow and error-prone operation.






    share|improve this answer






























      2














      I don't have enough info for a complete answer, except to say this smells like a large object heap issue, where one of the fields you retrieve from the database will occasionally be longer than the 85K LOH threshold.



      What I can do, and it might even help, is show you how to greatly simplify and improve the prepaint method like this:



      private void grdOrderItems1_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
      {
      if (e.RowIndex > grdOrderItems.Rows.Count - 1) return;
      var row = grdOrderItems.Rows[e.RowIndex];

      TimeSpan timeOfDay = DateTime.Now - DateTime.Today;
      //It *looks like* Cells[0].Value is already a DateTime, but I'm not 100% on this
      // If I'm wrong and it's a string, its worth it to parse just that one value to a DateTime here, and still plug that DateTime value into this code instead of the Cell.
      DateTime OrderDateTime = ((DateTime)row.Cells[0].Value).Date + timeOfDay;

      var days = (DateTime.Now - OrderDateTime).TotalDays;
      if (days > 2)
      {
      row.DefaultCellStyle.BackColor = Color.Tomato;
      }
      else if (days > 1)
      {
      row.DefaultCellStyle.BackColor = Color.Yellow;
      }
      else if (days > 0)
      {
      row.DefaultCellStyle.BackColor = Color.Tan;
      }
      }


      This reduces nesting and extra blocks, making it a lot easier to understand, and it probably runs in less than half the time because of the reduced back-and-forth between string and DateTime values. The cultural/internationalization issues make converting between DateTime and string in either direction an inherently slow and error-prone operation.






      share|improve this answer




























        2












        2








        2







        I don't have enough info for a complete answer, except to say this smells like a large object heap issue, where one of the fields you retrieve from the database will occasionally be longer than the 85K LOH threshold.



        What I can do, and it might even help, is show you how to greatly simplify and improve the prepaint method like this:



        private void grdOrderItems1_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
        {
        if (e.RowIndex > grdOrderItems.Rows.Count - 1) return;
        var row = grdOrderItems.Rows[e.RowIndex];

        TimeSpan timeOfDay = DateTime.Now - DateTime.Today;
        //It *looks like* Cells[0].Value is already a DateTime, but I'm not 100% on this
        // If I'm wrong and it's a string, its worth it to parse just that one value to a DateTime here, and still plug that DateTime value into this code instead of the Cell.
        DateTime OrderDateTime = ((DateTime)row.Cells[0].Value).Date + timeOfDay;

        var days = (DateTime.Now - OrderDateTime).TotalDays;
        if (days > 2)
        {
        row.DefaultCellStyle.BackColor = Color.Tomato;
        }
        else if (days > 1)
        {
        row.DefaultCellStyle.BackColor = Color.Yellow;
        }
        else if (days > 0)
        {
        row.DefaultCellStyle.BackColor = Color.Tan;
        }
        }


        This reduces nesting and extra blocks, making it a lot easier to understand, and it probably runs in less than half the time because of the reduced back-and-forth between string and DateTime values. The cultural/internationalization issues make converting between DateTime and string in either direction an inherently slow and error-prone operation.






        share|improve this answer















        I don't have enough info for a complete answer, except to say this smells like a large object heap issue, where one of the fields you retrieve from the database will occasionally be longer than the 85K LOH threshold.



        What I can do, and it might even help, is show you how to greatly simplify and improve the prepaint method like this:



        private void grdOrderItems1_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
        {
        if (e.RowIndex > grdOrderItems.Rows.Count - 1) return;
        var row = grdOrderItems.Rows[e.RowIndex];

        TimeSpan timeOfDay = DateTime.Now - DateTime.Today;
        //It *looks like* Cells[0].Value is already a DateTime, but I'm not 100% on this
        // If I'm wrong and it's a string, its worth it to parse just that one value to a DateTime here, and still plug that DateTime value into this code instead of the Cell.
        DateTime OrderDateTime = ((DateTime)row.Cells[0].Value).Date + timeOfDay;

        var days = (DateTime.Now - OrderDateTime).TotalDays;
        if (days > 2)
        {
        row.DefaultCellStyle.BackColor = Color.Tomato;
        }
        else if (days > 1)
        {
        row.DefaultCellStyle.BackColor = Color.Yellow;
        }
        else if (days > 0)
        {
        row.DefaultCellStyle.BackColor = Color.Tan;
        }
        }


        This reduces nesting and extra blocks, making it a lot easier to understand, and it probably runs in less than half the time because of the reduced back-and-forth between string and DateTime values. The cultural/internationalization issues make converting between DateTime and string in either direction an inherently slow and error-prone operation.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 13 '18 at 18:54

























        answered Nov 13 '18 at 18:48









        Joel CoehoornJoel Coehoorn

        307k95490721




        307k95490721






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53287079%2fwhy-does-my-c-sharp-winforms-program-with-a-timer-get-bogged-down-after-a-day%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Xamarin.iOS Cant Deploy on Iphone

            Glorious Revolution

            Dulmage-Mendelsohn matrix decomposition in Python