通过制作一个简单的时钟学习WPF中DispatcherTimer的使用 Level 100

2 篇文章 0 订阅
1 篇文章 0 订阅

通过制作一个简单的时钟学习WPF中DispatcherTimer的使用 Level 100

作者:Tony Qu
注:大家可以对本文的写作风格作一些点评,看看是否喜欢,是否有更好的建议,先谢谢了!

Timer控件是WinForm开发中必备的控件之一,在.net 3.0之前的版本中,我们可以很方便的从工具箱中拖出一个Timer来,在组件可视化列表中,我们会看到一个时钟,这就表示该WinForm中存在一个计时器。

可能是CTP版本的关系,在WPF的VS2005插件的工具箱中,根本无法找到Timer控件的踪影。看来我只有自力更生了

既然我们要制作时钟,首先来画界面,自然要先定义窗口的XAML,如下:

<Window x:Class="EClock.Window1"
    xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
    Title
="EClock" Height="97" Width="187"
    
>
    
<Grid>
    
<TextBlock Margin="14,11,19,12" Name="textBlock1" Loaded="OnTextBlockLoaded" FontFamily="Time New Roman" FontSize="40">00:00:00</TextBlock>       
  
</Grid>

</Window>

有心人已经应该发现了,这个程序叫做EClock,而这个Window则叫做Window1(可以从x:Class中看出,这是code-behind代码的引用)

我定义了一个TextBlock,ID为textBlock1。其他的一些基本属性如FontFamily, FontSize, Margin就不说了,大家都会设置。来说说这个Loaded属性,目前的WPF还不支持在可视化界面下生成事件处理程序(event handler),所以得自己加,这里的Loaded就是TextBlock的加载事件,那么里面的OnTextBlockLoaded自然就是事件处理程序的名称。

首先,我在WPF 窗口Window1的Class声明中定义了一个新的变量,叫做timer,请注意我们并没有使用System.Timers.Timer,而是使用了DispatcherTimer,至于原因将在本文最后讲解。定义代码如下:

System.Windows.Threading.DispatcherTimer timer;

下面我们来看看这个事件处理程序的内容:

private void OnTextBlockLoaded(object  sender, RoutedEventArgs e)
{
     timer = new System.Windows.Threading.DispatcherTimer();
     timer.Interval = new TimeSpan(0,0,1);   //间隔1秒

     timer.Tick += new EventHandler(timer_Tick);
     timer.Start();
}

如注释所说,我把间隔设置为1秒。该计时器的间隔事件也是Tick事件。好了,一切就绪,最后让我们来看看timer_Tick中的代码:

void timer_Tick(object  sender, EventArgs e)
{
     textBlock1.Text 
=
 DateTime.Now.ToLongTimeString();
}


似乎和原来的Tick事件中的代码没啥两样,那就运行一下看看效果吧。。。。

     

左侧为Windows 2003下运行结果,右侧为Vista下运行结果(发觉一个细节,ToLongTimeString在不同环境下返回的字符串尽然不一样,有谁知道为啥吗?)

完工!一个简单的电子钟做好了。下面让我们来讲讲为什么我们没有用我们相对熟悉的System.Timers.Timer。其实在.net 3.0中这个Timer已经与过去我们所了解的Timer不同了,如果我们在这个例子中使用该计时器的话,我们将收到一下错误信息:

由于其他线程拥有此对象,因此调用线程无法对其进行访问。

根据MSDN文档的说明,System.Timers.Timer是在一个独立的线程上实现的,而我们要更新的TextBlock位于窗口线程中,所以会出现以上错误。所以在国外的大部分的WPF Blog中,作者们比较喜欢使用DispatcherTimer,因为它简单方便,似乎和过去Timer更相似。至于System.Timers.Timer到底该如何实现对UI的更新,我还没有底,如果有谁已经知道怎么弄了,请分享一下。

=======================Update on 2006.12.23======================
基于System.Timers.Timer的解决方案(由Tyrael 提供)

private delegate void  UpdateTimer();

private void
 UpdateTimerCallback()
{
textBlock1.Text 
=
 DateTime.Now.ToLongTimeString();
}


void timer_Elapsed(object  sender, System.Timers.ElapsedEventArgs e)
{
Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, 
new
 UpdateTimer(UpdateTimerCallback)); 
}

这里的timer_Elapsed事件处理程序对应于Timer的Elapsed事件

版权声明:本文由作者Tony Qu原创, 未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则视为侵权。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WPF 秒表 计时器 定时关机 到计时关机 public const uint WM_SYSCOMMAND = 0x0112; public const uint SC_MONITORPOWER = 0xF170; [DllImport("user32")] public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, uint wParam, int lParam); /// /// 关闭显示器 /// public void CloseScreen() { IntPtr windowHandle = Process.GetCurrentProcess().MainWindowHandle; SendMessage(windowHandle, WM_SYSCOMMAND, SC_MONITORPOWER, 2); // 2 为关闭显示器, -1则打开显示器 } using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Windows.Threading; using IniFiles; namespace StopWatch { /// /// shutdonwCtrl.xaml 的交互逻辑 /// public partial class shutdonwCtrl : UserControl { DispatcherTimer timer1; DispatcherTimer timer2; public shutdonwCtrl() { InitializeComponent(); timer1 = new DispatcherTimer(); timer1.Tick += new EventHandler(OnTimer1); timer1.Interval = new TimeSpan(0, 0, 1); timer2 = new DispatcherTimer(); timer2.Tick += new EventHandler(OnTimer2); timer2.Interval = new TimeSpan(0, 0, 1); btn_cancel.IsEnabled = false; cancel1.IsEnabled = false; } IniFile INI = new IniFile(IniFile.AppIniName); public void LoadIni() { cbo_hour.Text = INI.ReadString("定时关机", "时", "0"); cbo_Minute.Text = INI.ReadString("定时关机", "分", "0"); cbo_Second.Text = INI.ReadString("定时关机", "秒", "0"); cbo1.Text = INI.ReadString("到计时关机", "分", "0"); //combobox1.Text = INI.ReadString("到计时", "时", "0"); //combobox2.Text = INI.ReadString("到计时", "分", "0"); //combobox3.Text = INI.ReadString("到计时", "秒", "0"); } public void SaveIni() { INI.WriteString("定时关机", "时", cbo_hour.Text); INI.WriteString("定时关机", "分", cbo_Minute.Text); INI.WriteString("定时关机", "秒", cbo_Second.Text); INI.WriteString("到计时关机", "分", cbo1.Text); } private void ShutDown() { System.Diagnostics.Process.Start("shutdown.exe", "-s -t 1"); } private void OnTimer1(object sender,EventArgs e) { if (second > 0) second--; label1.Content = string.Format("Windows将在 {0} 关机", TimerClass.GetTimeString1(second)); if (second <= 0 && !cbo1.IsEnabled) { ShutDown(); } } int second = 0; private void Button_Click(object sender, RoutedEventArgs e) { second = Convert.ToInt32(cbo1.Text) * 60; if (second <= 0) { MessageBox.Show("数值必须大于0!"); return; } timer1.Start(); cbo1.IsEnabled = false; cancel1.IsEnabled = true; start1.IsEnabled = false; } private void Button_Click_1(object sender, RoutedEventArgs e) { label1.Content = " "; timer1.Stop(); second = 0; cbo1.IsEnabled = true; cancel1.IsEnabled = false; start1.IsEnabled = true; } private void OnTimer2(object sender, EventArgs e) { if ( DateTime.Now.Hour == Convert.ToInt32(cbo_hour.Text) && DateTime.Now.Minute == Convert.ToInt32(cbo_Minute.Text) && DateTime.Now.Second == Convert.ToInt32(cbo_Second.Text) ) { ShutDown(); } } private void Button_Click_2(object sender, RoutedEventArgs e) { int s = Convert.ToInt32(cbo_hour.Text) * 3600 + Convert.ToInt32(cbo_Minute.Text) * 60 + Convert.ToInt32(cbo_Second.Text); timer2.Start(); label2.Content = string.Format("Windows将在 {0} 关机", TimerClass.GetTimeString1(s)); btn_start.IsEnabled = false; btn_cancel.IsEnabled = true; cbo_hour.IsEnabled = false; cbo_Minute.IsEnabled = false; cbo_Second.IsEnabled = false; } private void btn_cancel_Click(object sender, RoutedEventArgs e) { label2.Content = ""; timer2.Stop(); btn_start.IsEnabled = true; btn_cancel.IsEnabled = false; cbo_hour.IsEnabled = true; cbo_Minute.IsEnabled = true; cbo_Second.IsEnabled = true; } } } using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Threading.Tasks; using System.Runtime.InteropServices; using System.Windows.Threading; using IniFiles; namespace StopWatch { /// /// TimerCtrl.xaml 的交互逻辑 /// public partial class TimerCtrl : UserControl { private DispatcherTimer timer1 = null; private DispatcherTimer timer2 = null; int SND_SYNC = 0x0000; /* play asynchronously */ //异步 int SND_ASYNC = 0x0001; int SND_LOOP = 8; [DllImport("winmm")] public static extern bool PlaySound(string szSound, IntPtr hMod, int flags); private void playSound3() { Task tsk = new Task(new Action(proc)); tsk.Start(); } private void proc() { PlaySound(@"Sound\2.wav", IntPtr.Zero, SND_SYNC); PlaySound(@"Sound\2.wav", IntPtr.Zero, SND_SYNC); PlaySound(@"Sound\2.wav", IntPtr.Zero, SND_SYNC); } public TimerCtrl() { InitializeComponent(); timer1 = new DispatcherTimer(); timer1.Tick += new EventHandler(OnTimer1); timer1.Interval = new TimeSpan(0, 0, 1); timer2 = new DispatcherTimer(); timer2.Tick += new EventHandler(OnTimer2); timer2.Interval = new TimeSpan(0, 0, 1); btn_reset1.IsEnabled = false; btn_pause1.IsEnabled = false; } int h = 0; int m = 0; int s = 0; int seconds = 0; private void OnTimer1(object sender, EventArgs e) { if (seconds < 1) { PlaySound(@"Sound\2.wav", IntPtr.Zero, SND_ASYNC); btn_start.IsEnabled = false; btn_reset1.IsEnabled = true; btn_pause1.IsEnabled = false; combobox1.IsEnabled = true; combobox2.IsEnabled = true; combobox3.IsEnabled = true; return; } seconds--; label1.Content = TimerClass.GetTimeString1(seconds); } private void btn_start_Click(object sender, RoutedEventArgs e) { h = Convert.ToInt32(combobox1.Text); m = Convert.ToInt32(combobox2.Text); s = Convert.ToInt32(combobox3.Text); seconds = h * 3600 + m * 60 + s; label1.Content = TimerClass.GetTimeString1(seconds); timer1.Start(); btn_start.IsEnabled = false; btn_reset1.IsEnabled = true; btn_pause1.IsEnabled = true; combobox1.IsEnabled = false; combobox2.IsEnabled = false; combobox3.IsEnabled = false; } private void btn_reset_Click(object sender, RoutedEventArgs e) { seconds = 0; label1.Content = TimerClass.GetTimeString1(seconds); timer1.Stop(); btn_start.IsEnabled = true; btn_reset1.IsEnabled = false; btn_pause1.IsEnabled = false; combobox1.IsEnabled = true; combobox2.IsEnabled = true; combobox3.IsEnabled = true; } private void pause1_Click(object sender, RoutedEventArgs e) { if (btn_pause1.Content.ToString() == "暂停") { timer1.Stop(); btn_pause1.Content = "继续"; } else { timer1.Start(); btn_pause1.Content = "暂停"; } } int SEC = 0; private void OnTimer2(object sender, EventArgs e) { if (SEC < 1) { timer2.Stop(); playSound3(); btn_quick.IsEnabled = true; btn_cancel2.IsEnabled = false; combobox4.IsEnabled = true; return; } SEC--; label4.Content = TimerClass.GetTimeString1(SEC); } private void Button_Click(object sender, RoutedEventArgs e) { SEC = Convert.ToInt32(combobox4.Text) * 60; timer2.Start(); combobox4.IsEnabled = false; btn_quick.IsEnabled = false; btn_cancel2.IsEnabled = true; } private void Button_Click_1(object sender, RoutedEventArgs e) { SEC = 2; label4.Content = "00:00:00"; timer2.Stop(); combobox4.IsEnabled = true; btn_quick.IsEnabled = true; } IniFile INI = new IniFile(IniFile.AppIniName); public void LoadIni() { combobox1.Text = INI.ReadString("到计时", "时", "0"); combobox2.Text = INI.ReadString("到计时", "分", "0"); combobox4.Text = INI.ReadString("快速计时", "分", "0"); } public void SaveIni() { INI.WriteString("到计时", "时", combobox1.Text); INI.WriteString("到计时", "分", combobox2.Text); INI.WriteString("到计时", "秒", combobox3.Text); INI.WriteString("快速计时", "分", combobox4.Text); } } } using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Threading; using System.Windows.Threading; namespace StopWatch { /// /// WatchCtrl.xaml 的交互逻辑 /// public partial class WatchCtrl : UserControl { public WatchCtrl() { InitializeComponent(); timer1 = new DispatcherTimer(); timer1.Tick += new EventHandler(OnTimer1); timer1.Interval = new TimeSpan(0, 0, 1); timer1_1 = new DispatcherTimer(); timer1_1.Tick += new EventHandler(OnTimer1_1); timer1_1.Interval = new TimeSpan(0, 0, 0, 100); timer2 = new DispatcherTimer(); timer2.Tick += new EventHandler(OnTimer2); timer2.Interval = new TimeSpan(0, 0, 1); } private DispatcherTimer timer1 = null; private DispatcherTimer timer1_1 = null; private DispatcherTimer timer2 = null; private void OnTimer1(object sender, EventArgs e) { second++; label1.Content = TimerClass.GetTimeString1(second) ;//DateTime.Now.ToString("h:mm:ss"); } public int second = 0; private int second1 = 0; public int count = 0; private void OnTimer1_1(object sender, EventArgs e) { //label1.Content = TimerClass.GetTimeString1(second) + "." + count.ToString();//DateTime.Now.ToString("h:mm:ss"); //count++; //if (count > 9) // count = 0; } private void OnTimer2(object sender, EventArgs e) { second1++; label2.Content = TimerClass.GetTimeString1(second1) ;//.ToString("h:mm:ss"); } private void btn_start_Click(object sender, RoutedEventArgs e) { timer1.Start(); timer2.Start(); if (btn_start.Content.ToString() == "停止") { btn_start.Content = "开始"; btn_reset.Content = "复位"; timer1.Stop(); timer2.Stop(); } else { btn_start.Content = "停止"; btn_reset.Content = "计次"; } } private int counter = 0; private void btn_reset_Click(object sender, RoutedEventArgs e) { if (btn_reset.Content.ToString() == "复位") { second = 0; second1 = 0; label1.Content = "00:00:00"; label2.Content = "00:00:00"; timer1.Stop(); timer2.Stop(); } else { if (second1 > 0) { counter++; listbox1.Items.Add(string.Format(" {0}\t{1}", counter, label2.Content)); } second1 = 0; label2.Content = "00:00:00"; } if (btn_reset.Content.ToString() == "复位" && btn_start.Content.ToString()=="开始") { listbox1.Items.Clear(); } } } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值