I am about to build a alarm system. The way it works is by pulling date/time information from a gridview column, then I use a async action to check when the time now is equal to one or more of the rows in the gridview date/time column, if it is then show an alarm.
Everything works fine so far, except that when 2 rows contains the same date/time, the alarm will trigger 4 times instead of 2. This is what I got so far:
string firma = "";
private void radButton1_Click(object sender, EventArgs e)
{
try
{
for (int i = 0; i < radGridView4.Rows.Count; i++)
{
DateTime executionTime = Convert.ToDateTime(radGridView4.Rows[i].Cells[10].Value.ToString());
ScheduleAction(action, executionTime);
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
public async void ScheduleAction(Action action, DateTime ExecutionTime)
{
try
{
if (DateTime.Now < ExecutionTime)//ExecutionTime only create an alarm for rows that are later than now
{
await Task.Delay((int)ExecutionTime.Subtract(DateTime.Now).TotalMilliseconds);
action();
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
public void action()
{
RadDesktopAlert Alert;
for (int i = 0; i < radGridView4.Rows.Count; i++)
{
DateTime executionTime = Convert.ToDateTime(radGridView4.Rows[i].Cells[10].Value.ToString());
if (DateTime.Now.Date == executionTime.Date && DateTime.Now.Hour == executionTime.Hour && DateTime.Now.Minute == executionTime.Minute)
{
Alert = new RadDesktopAlert();
firma = radGridView4.Rows[i].Cells[2].Value.ToString();
Alert.CaptionText = "Telefonmøde";
Alert.ContentText = firma;
Alert.Show();
}
}
}
Any help is appreciated, and everything works without errors without the try statement aswell.
Thanks in advance!
Part of the problem is that you're scheduling duplicate alarms, and the other part is that your action is going to also trigger duplicate alarms, because both of these blocks of code is looping through your grid.
It might help if the action
method does not depend on data in the grid, but rather gets everything it needs through it's arguments. This means we should capture the content
the first time we loop through the grid items, and then pass this info to the method.
To do this, we can modify the action
method to take a string for the content, and we can remove the looping of the grid. Note that if we now call action
, it will just execute the action right away, so it's up to the caller to schedule it at the correct time:
public void action(string content)
{
var alert = new RadDesktopAlert
{
CaptionText = "Telefonmøde",
ContentText = content
};
alert.Show();
}
Now that we've modified the action
method, we also need to modify the ScheduleAction
method so that it passes the new required parameter. This means that it will also need to take a new parameter:
public async void ScheduleAction(Action<string> action, string content,
DateTime ExecutionTime)
{
if (DateTime.Now < ExecutionTime)
{
await Task.Delay((int)ExecutionTime.Subtract(DateTime.Now).TotalMilliseconds);
action(content);
}
}
Next, we could create a separate List<DataTime>
object to keep track of the times we've already scheduled. Then, as we loop through the grid view, we only schedule a time if it's not in in the list. We also capture the content
data while we're at it:
var scheduledExecutionTimes = new List<DateTime>();
for (int i = 0; i < radGridView4.Rows.Count; i++)
{
DateTime executionTime = Convert.ToDateTime(radGridView4.Rows[i].Cells[10].Value.ToString());
if (!scheduledExecutionTimes.Contains(executionTime))
{
string content = radGridView4.Rows[i].Cells[2].Value.ToString();
ScheduleAction(action, content, executionTime);
// Add this time to our list
scheduledExecutionTimes.Add(executionTime);
}
}