2009-09-29 34 views
10

Tôi không thực sự viết một ứng dụng đồng hồ báo thức, nhưng nó sẽ giúp minh họa cho câu hỏi của tôi.Ứng dụng đồng hồ báo thức trong .Net

Giả sử tôi có phương pháp trong đơn đăng ký của mình và tôi muốn phương thức này được gọi mỗi giờ một giờ (ví dụ: lúc 7:00 tối, 8:00 tối, 9:00 tối, v.v ...). Tôi có thể tạo Bộ hẹn giờ và đặt Khoảng thời gian là 3600000, nhưng cuối cùng điều này sẽ không đồng bộ với đồng hồ hệ thống. Hoặc tôi có thể sử dụng một vòng lặp while() với Thread.Sleep(n) kiểm tra định kỳ thời gian hệ thống và gọi phương thức khi thời gian mong muốn đạt được, nhưng tôi không thích điều này một trong hai (Thread.Sleep(n) là một mùi code lớn đối với tôi).

Điều tôi đang tìm là phương thức trong .Net cho phép tôi chuyển đối tượng DateTime trong tương lai và phương thức xử lý sự kiện hoặc đại biểu, nhưng tôi không thể tìm thấy bất kỳ thứ gì như vậy. Tôi nghi ngờ có một phương pháp trong API Win32 làm điều này, nhưng tôi đã không thể tìm thấy điều đó, một trong hai.

+4

Bạn đang muốn cuộn Quartz.Net của riêng mình? http://quartznet.sourceforge.net/ –

+1

@Austin: không, tôi chỉ đang tìm một phương pháp đơn giản như những gì tôi mô tả trong đoạn cuối, mà không cần phải cuộn của riêng tôi hoặc sử dụng một số thành phần của bên thứ ba. – MusiGenesis

+1

Trình xây dựng trong Windows Scheduler có API có thể truy cập thông qua PInvoke http://www.pinvoke.net/default.aspx/netapi32/NetScheduleJobAdd.html – xcud

Trả lời

10

Hoặc, bạn có thể tạo bộ hẹn giờ với khoảng thời gian 1 giây và kiểm tra thời gian hiện tại mỗi giây cho đến khi đạt được thời gian sự kiện, nếu có, bạn hãy tăng sự kiện của mình.

Bạn có thể tạo một wrapper đơn giản cho rằng:

public class AlarmClock 
{ 
    public AlarmClock(DateTime alarmTime) 
    { 
     this.alarmTime = alarmTime; 

     timer = new Timer(); 
     timer.Elapsed += timer_Elapsed; 
     timer.Interval = 1000; 
     timer.Start(); 

     enabled = true; 
    } 

    void timer_Elapsed(object sender, ElapsedEventArgs e) 
    { 
     if(enabled && DateTime.Now > alarmTime) 
     { 
      enabled = false; 
      OnAlarm(); 
      timer.Stop(); 
     } 
    } 

    protected virtual void OnAlarm() 
    { 
     if(alarmEvent != null) 
      alarmEvent(this, EventArgs.Empty); 
    } 


    public event EventHandler Alarm 
    { 
     add { alarmEvent += value; } 
     remove { alarmEvent -= value; } 
    } 

    private EventHandler alarmEvent; 
    private Timer timer; 
    private DateTime alarmTime; 
    private bool enabled; 
} 

Cách sử dụng:

AlarmClock clock = new AlarmClock(someFutureTime); 
clock.Alarm += (sender, e) => MessageBox.Show("Wake up!"); 

Xin lưu ý các mã trên là rất sơ sài và không đề an toàn.

+0

Vâng, nhưng đó cũng không phải những gì tôi đang tìm kiếm, xin lỗi. – MusiGenesis

+4

Điều bạn đang tìm kiếm không tồn tại. – RichardOD

+1

Xin lỗi, nhưng bạn đang tìm gì? – Coincoin

1

Bạn có thể tạo một lớp Báo thức có chuỗi chuyên dụng chuyển sang chế độ ngủ cho đến thời gian đã chỉ định, nhưng điều này sẽ sử dụng phương thức Thread.Sleep. Một cái gì đó như:

/// <summary> 
/// Alarm Class 
/// </summary> 
public class Alarm 
{ 
    private TimeSpan wakeupTime; 

    public Alarm(TimeSpan WakeUpTime) 
    { 
     this.wakeupTime = WakeUpTime; 
     System.Threading.Thread t = new System.Threading.Thread(TimerThread) { IsBackground = true, Name = "Alarm" }; 
     t.Start(); 
    } 

    /// <summary> 
    /// Alarm Event 
    /// </summary> 
    public event EventHandler AlarmEvent = delegate { }; 

    private void TimerThread() 
    { 
     DateTime nextWakeUp = DateTime.Today + wakeupTime; 
     if (nextWakeUp < DateTime.Now) nextWakeUp = nextWakeUp.AddDays(1.0); 

     while (true) 
     { 
      TimeSpan ts = nextWakeUp.Subtract(DateTime.Now); 

      System.Threading.Thread.Sleep((int)ts.TotalMilliseconds); 

      try { AlarmEvent(this, EventArgs.Empty); } 
      catch { } 

      nextWakeUp = nextWakeUp.AddDays(1.0); 
     } 
    } 
} 
+0

Ooh, 'Thread.Sleep (n)' * và * một khối trống 'catch {}'. : P – MusiGenesis

+1

Thật vậy. Thêm một nguyên mẫu của những gì bạn có thể làm. Tốt hơn là sử dụng Bộ hẹn giờ như Jacob mô tả. – JDunkerley

2

Bạn chỉ có thể thiết lập lại trong suốt thời gian hẹn giờ mỗi lần nó cháy, như thế này:

// using System.Timers; 

private void myMethod() 
{ 
    var timer = new Timer { 
     AutoReset = false, Interval = getMillisecondsToNextAlarm() }; 
    timer.Elapsed += (src, args) => 
    { 
     // Do timer handling here. 

     timer.Interval = getMillisecondsToNextAlarm(); 
     timer.Start(); 
    }; 
    timer.Start(); 
} 

private double getMillisecondsToNextAlarm() 
{ 
    // This is an example of making the alarm go off at every "o'clock" 
    var now = DateTime.Now; 
    var inOneHour = now.AddHours(1.0); 
    var roundedNextHour = new DateTime(
     inOneHour.Year, inOneHour.Month, inOneHour.Day, inOneHour.Hour, 0, 0); 
    return (roundedNextHour - now).TotalMilliseconds; 
} 
+0

Điều này sẽ không giải quyết được vấn đề, thật không may. Vấn đề trôi dạt là vì Timer không chính xác trong thời gian dài (Đồng hồ bấm giờ có cùng vấn đề). – MusiGenesis

+0

Tôi chưa từng nghe điều đó trước đây. Bạn dựa vào yêu cầu không chính xác nào? – Jacob

+0

@ Jacob: đừng dùng từ ngữ của tôi vì nó - hãy thử nó. Bắt đầu một bộ đếm thời gian (bất kỳ loại nào) và để cho nó chạy trong một hoặc hai ngày, và xem cách xa nó được. – MusiGenesis

8

Thú vị, tôi thực sự đã gặp một vấn đề rất giống và đã tìm kiếm một phương thức trong khung .Net sẽ xử lý trường hợp này. Cuối cùng, chúng tôi đã kết thúc việc thực hiện giải pháp riêng của chúng tôi là một biến thể trên một vòng lặp while/Thread.Sleep (n) trong đó n càng nhỏ thì bạn càng tiến gần đến thời gian đích mong muốn (logarithmically thực sự, nhưng với một số ngưỡng hợp lý bạn không phải là tối đa CPU khi bạn đến gần thời gian mục tiêu.) Đây là một thực hiện đơn giản thực sự mà chỉ cần ngủ một nửa thời gian giữa bây giờ và thời gian mục tiêu.

class Program 
{ 
    static void Main(string[] args) 
    { 
     SleepToTarget Temp = new SleepToTarget(DateTime.Now.AddSeconds(30),Done); 
     Temp.Start(); 
     Console.ReadLine(); 
    } 

    static void Done() 
    { 
     Console.WriteLine("Done"); 
    } 
} 

class SleepToTarget 
{ 
    private DateTime TargetTime; 
    private Action MyAction; 
    private const int MinSleepMilliseconds = 250; 

    public SleepToTarget(DateTime TargetTime,Action MyAction) 
    { 
     this.TargetTime = TargetTime; 
     this.MyAction = MyAction; 
    } 

    public void Start() 
    { 
     new Thread(new ThreadStart(ProcessTimer)).Start(); 
    } 

    private void ProcessTimer() 
    { 
     DateTime Now = DateTime.Now; 

     while (Now < TargetTime) 
     { 
      int SleepMilliseconds = (int) Math.Round((TargetTime - Now).TotalMilliseconds/2); 
      Console.WriteLine(SleepMilliseconds); 
      Thread.Sleep(SleepMilliseconds > MinSleepMilliseconds ? SleepMilliseconds : MinSleepMilliseconds); 
      Now = DateTime.Now; 
     } 

     MyAction(); 
    } 
} 
-2

Tôi đã sử dụng này trước khi với thành công rực rỡ:

Vb.net:

Imports System.Threading 
Public Class AlarmClock 
    Public startTime As Integer = TimeOfDay.Hour 
    Public interval As Integer = 1 
    Public Event SoundAlarm() 
    Public Sub CheckTime() 
     While TimeOfDay.Hour < startTime + interval 
      Application.DoEvents() 
     End While 
     RaiseEvent SoundAlarm() 
    End Sub 
    Public Sub StartClock() 
     Dim clockthread As Thread = New Thread(AddressOf CheckTime) 
     clockthread.Start() 
    End Sub 
End Class 

C#:

using System.Threading; 
public class AlarmClock 
{ 
    public int startTime = TimeOfDay.Hour; 
    public int interval = 1; 
    public event SoundAlarmEventHandler SoundAlarm; 
    public delegate void SoundAlarmEventHandler(); 
    public void CheckTime() 
    { 
     while (TimeOfDay.Hour < startTime + interval) { 
      Application.DoEvents(); 
     } 
     if (SoundAlarm != null) { 
      SoundAlarm(); 
     } 
    } 
    public void StartClock() 
    { 
     Thread clockthread = new Thread(CheckTime); 
     clockthread.Start(); 
    } 
} 

Tôi không biết nếu C# công trình, nhưng vb hoạt động tốt.

Cách sử dụng trong VB:

Dim clock As New AlarmClock 
clock.interval = 1 'Interval is in hours, could easily convert to anything else 
clock.StartClock() 

Sau đó, chỉ cần thêm một event handler cho sự kiện SoundAlarm.

+1

TimeOfDay là một điều VB.Net chỉ, và vòng lặp 'while' với một cuộc gọi' DoEvents() 'sẽ tối đa bộ xử lý của bạn trong khi điều này đang chạy. – MusiGenesis

+0

Không biết điều đó, nhưng bây giờ tôi làm. Mã ban đầu có vòng lặp ngủ trong 15 giây, nhưng vì bạn không muốn tôi bỏ nó ra. – Cyclone

+0

Tại sao bạn muốn Application.DoEvents trong một phương thức chạy trong một chủ đề (hoặc thậm chí cả) là ngoài tôi –

Các vấn đề liên quan