|
thanks, i'll take a look at quartz.net.
|
|
|
|
|
Don't use a timer for this - take a look, rather, at using something like a Monitor where you can specify an elapsed interval before the monitor "wakes up". It would look something like this:
private static readonly object _syncLock = new object();
private bool _cancel;
private void ScheduleProcess(DateTime scheduledDate)
{
if (scheduledDate >= DateTime.Now)
throw new ArgumentOutOfRangeException("The scheduled time is set for a time that has already passed.");
TimeSpan waittime = scheduledDate - DateTime.Now;
lock (_syncLock)
{
Monitor.Wait(_syncLock, waittime);
}
}
public void Cancel()
{
_cancel = true;
lock(_syncLock)
{
Monitor.PulseAll(_syncLock);
}
} Create a background thread, and use ScheduleProcess to block access to your functionality until the time has passed. For instance:
public void DoSomething(DateTime scheduledTime)
{
SmartThreadPool stp = new SmartThreadPool();
stp.QueueWorkItem(new WorkItemCallback(RunProcess), scheduledTime);
}
private object RunProcess(object scheduledTime)
{
ScheduleProcess((DateTime)scheduledTime);
if (!_cancel)
{
}
return null;
} This example uses the SmartThreadPool[^].
|
|
|
|
|
Using Monitor.Wait() is a great solution but comes with its own set of problems. Most notably, it has no guaranteed accuracy. If you tell it to wait one hour, it will wait AT LEAST one hour. A number of factors can delay the response. It would be much safer to use Monitor.Wait() to suspend the thread, then switch to a more accurate but processor-intensive method for precision.
Also, when calculating the delay, since a number of factors (already pointed out by someone else) can cause this delay to be off, if you really want precision, I would calculate it a few times, then perform the reverse calculation for each result. This will allow you to be assured that your delay value is accurate.
|
|
|
|
|
thanks for pointing out this.
|
|
|
|
|
Thanks very much for your example.
|
|
|
|
|
May be you should look at API functions CreateWaitableTimer(), SetWaitableTimer() and CancelWaitableTimer(). SetWaitableTimer() has the ability to specify UTC-based absolute time. Dont't know, if these functions are implemented directly in BCL though. THT.
|
|
|
|
|
|
If you consider one second as precise enough, this should suffice.
When I hear precision timer, I am thinking microsecond or nanosecond accuray.
http://quartznet.sourceforge.net/[^]
|
|
|
|
|
Actually, I also meant 'micorsecond' (well, I'm not sure whether .net can really cater for nanosecond accuray or not)
I'll take look at quartz.net, thanks.
modified on Thursday, September 2, 2010 6:28 PM
|
|
|
|
|
My answer starts in the wayback machine, before things such as .net and controls and whatnot existed. It's an alternate idea, but probably doesn't do what you want.
Anyway, back a long time ago, we had systems which needed to do take certain actions at certain times. We bulit a server application which would go in our data and look for certain conditions. When they were met, an event would happen.
I wonder if you could write a service to do something similar. When you know you want to trigger an event at 10:25:15, you write to an event table, noting the event name and time.
The service is pretty simple; look in the event table for things in the past which are in a state of 'not run'; fire off an appropriate class/method based on event name, mark as 'complete' the event entry. Mark as 'run, but with exception' if the action fails.
I think this solution depends on how time-specific your answer really needs to be. If it's life-critical, this is no good. If it's within a few seconds, this might be a pretty simle solution.
|
|
|
|
|
Definitely, we can do it in this way, but the thing is what techique I can use in .net not to rely on the inefficient polling tech (and polling is not accurate as well). I'd like to let the working thread to sleep and when the specific time coming, woken up. This model is what I really want. I wonder if .net has mechanism directly support this model, don't have to do converting interval stuff.
By the way, if the time-specific matter needs to meet life-critical requirement, what .net mechanism we can rely on? Does .net have such capability to support this level of accuracy? (My understanding is this needs real-time OS and device to support).
|
|
|
|
|
I think you're right on the life-critical aspect. I don't believe there is anything in .net that will give you that granularity.
I don't know if my idea fits your needs, or is even a step down the right path. In the solution I was talking about, we knew every time an action was taken exactly what the next 'automatic' action would be, and exactly when it would occur.
However, for us, not so time-critical. So, even though we were able to come up with a simple 'if this happens, write this event and time to the database' scenario, our server wouldn't necessarily notice that event right at the time written.
But, it did turn out to be a really simple solution to a timer-type problem.
I suppose in today's world, you'd just go ahead and use a Timer and tie it to the event you wanted to perform.
Anyway, good luck.
|
|
|
|
|
FWIW: In a Windows Service that I wrote awhile back, I used the following:
// Initiate our System Timer (set to one minute here)
double dblStartupInterval = 60000;
this.timProcessTimer_PollPV = new System.Timers.Timer (dblStartupInterval);
// Note that everything done by the Timer is tied to
// the Elapsed Event, which is raised every interval.
// Instruct the Framework to call
// the "ServiceTimer_PollPV_Tick" method when this
// Timer elapses -- that is, when its interval runs its course.
this.timProcessTimer_PollPV.Elapsed += new System.Timers.ElapsedEventHandler(this.ServiceTimer_PollPV_Tick);
|
|
|
|
|
I googled this extensively yesterday and didn't come out with an answer:
Is it possible to do some thing like this, and if so how?
labela1.Text = "something";
labela2.Text = "something";
labela3.Text = "something";
Now what I want is a way to write that code as say:
for (int i=1;i<4;i++)
labelai.Text = "something";
so that the i in labelai above is replaced by 1, 2, 3 at runtime and the net result of the for loop is the same as what happens in the block above.
Is there a way to do that?
Thanks!
|
|
|
|
|
Yes, however, you may not like it.
foreach(Control control in Controls){
if(control is Label){
((Label)control).Text = "Something";
}
}
Unfortunately this will set all labels. If you are in Windows forms you can use the Tag option to set a tag, or you can subclass your Label control to give it a type.
The other option is, after Initialize component, place all Labels you care about looping through in a collection.
|
|
|
|
|
Here's a refinement that will only touch all labels you care about:
foreach (Control control in Controls)
{
if (control is Label && label.Name.StartsWith("labelNamePrefixToModifyAsAGroup"))
{
((Label)control).Text = "Something";
}
}
|
|
|
|
|
|
which can be reduced to
foreach (Control c in Controls) if (c.Name.StartsWith("labela")) c.Text = "Something";
as every Control has a Name and a Text property.
|
|
|
|
|
Slaps self on head for missing that one.
|
|
|
|
|
Reference parameters are your friend:
private void SetLabelText(ref Label label, string text)
{
label.Text = text;
}
private void SomeFunction()
{
SetLabelText(ref label1, "something1");
SetLabelText(ref label2, "something2");
SetLabelText(ref label3, "something3");
}
.45 ACP - because shooting twice is just silly ----- "Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997 ----- "The staggering layers of obscenity in your statement make it a work of art on so many levels." - J. Jystad, 2001
|
|
|
|
|
No need for 'ref', unless you want to change what the label1, label2, and label3 variables point to.
|
|
|
|
|
for (int i=1;1<4;i++){
this.Controls[string.Concat("labela", i.ToString())].Text = "something";
}
|
|
|
|
|
No-one with a LINQ version yet?
class Form1
{
IEnumerable<Control> summingLabels;
public Form1()
{
InitializeComponent();
summingLabels =
from c in Controls.Cast<Control>().AsQueryable()
where c.Name.StartsWith("sumLabel")
select c;
foreach(Control l in summingLabels)
l.Text = l.Name;
}
}
Keep a pointer around to the controls that you found; no need to iterate them every time
I are Troll
|
|
|
|
|
how about lambda?
foreach (Control l in Controls.Cast<Control>().Where(c => c.Name.StartsWith("sumLabel")))
l.Text = l.Name;
|
|
|
|
|