C# 简单秒表 - 初学者

Posted

技术标签:

【中文标题】C# 简单秒表 - 初学者【英文标题】:C# simple stopwatch - Total beginner 【发布时间】:2020-07-13 14:20:00 【问题描述】:

我来自嵌入式 C 编程,我对 oop、任务、线程、ecc 完全不了解。 我正在了解 C# 和 oop 的基本概念,并想尝试编写一个简单的秒表。

目标:用按钮切换秒表状态,并在按钮内部显示值。

到目前为止,我已经做到了:

namespace Cronometro

    public partial class MainWindow : Window
    
        public MainWindow()
        
            InitializeComponent();

        
    

    public class MyTimerClass
    
        private DateTime TimeValue;
        private System.Timers.Timer TimerObj;
        private const int TimeInterval = 1;

        public MyTimerClass()
        
            TimeValue new DateTime(0, 0, 0, 0, 0, 0, 0, DateTimeKind.Local);
            TimerObj = new System.Timers.Timer(TimeInterval);
            TimerObj.AutoReset = true;

            TimerObj.Elapsed += TimerObj_Elapsed;
        

        private void TimerObj_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        
            TimeValue = TimeValue.AddMilliseconds((double)TimeInterval);
        

        public void Start()
        
            TimerObj.Start();
        
        public void Stop()
        
            TimerObj.Stop();
        
    

说到这里,我只是想用 Button.Content 打印值,但似乎我不能在 MainWindow 类之外使用它。

我该怎么办?我开始考虑在主类中创建一个任务并等待计时器事件打印值,但我对线程和任务一无所知。

【问题讨论】:

首先,在表单上添加一个按钮。没有按钮,您将无法按下它。 为什么要包装Timer 类?您似乎没有在那里添加任何值,因此只需在没有包装器的主类中使用它并处理 elapsed 事件。 我明白你的观点@RonBeyer,但这只是为了练习课程。 【参考方案1】:

目前还不清楚您的意思,因为目前您根本无法在 MainWindow 类中使用它。只需通过公共函数公开值,您就可以在任何地方获取实例的值。

namespace Cronometro

    public partial class MainWindow : Window
    
        public MainWindow()
        
            InitializeComponent();
            var x = new MyTimerClass();       // <<<
            x.Start();                        // <<<
            var timeValue = x.GetTimeValue(); // <<<
        
    

public class MyTimerClass

    private DateTime TimeValue;
    private System.Timers.Timer TimerObj;
    private const int TimeInterval = 1;

    public MyTimerClass()
    
        TimeValue new DateTime(0, 0, 0, 0, 0, 0, 0, DateTimeKind.Local);
        TimerObj = new System.Timers.Timer(TimeInterval);
        TimerObj.AutoReset = true;

        TimerObj.Elapsed += TimerObj_Elapsed;
    

    private void TimerObj_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    
        TimeValue = TimeValue.AddMilliseconds((double)TimeInterval);
    

    public DateTime GetTimeValue() // <<<
                                  // <<<
        return TimeValue;          // <<<
                                  // <<<

    public void Start()
    
        TimerObj.Start();
    
    public void Stop()
    
        TimerObj.Stop();
    

【讨论】:

我发现了dispatcher的东西,好像是解决问题的办法?计时器和 UI 在不同的线程中运行,因此不仅仅是对象范围的问题。【参考方案2】:

首先,您不必编写自己的 Stopwatch 类。 DotNet 有自己的: https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.stopwatch?view=netframework-4.8

其次,尝试理解 async/await 模式: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/

所以,你可以这样做: https://wouterdekort.com/2013/10/01/async-and-await-and-the-ui-thread/

【讨论】:

异步/等待秒表?做什么?这里没有异步操作【参考方案3】:

填充按钮文本的一种方法是在MyTimerClass 类中创建一个事件,并从MainWindow 类内部将一个侦听器委托附加到它。

然后,在MyTimerClass 中触发TimerObj_Elapsed 中的事件,以便调用MainWindow 中的事件处理程序,您将有机会填充按钮。

但是,除了“练习课”之外,还有其他事情需要处理。因为您使用的是线程池计时器,所以计时器的Elapsed 事件处理程序是从工作线程调用的。在 GUI 应用程序中,只有主 / UI 线程可以与控件交互。所以很有可能,在尝试设置Button.Text 时会出现异常。您需要将 set 操作编组到 UI 线程。

坦率地说,如果您正在练习用 C# 编写课程,我建议您使用控制台应用程序而不是 GUI 应用程序开始。如果人们同时在桌面上抛出太多你不知道的概念,这可能不是一个好主意。

【讨论】:

你说得对,就我目前的知识而言,这太复杂了。我认为这将是一个简单的第一个项目,但在这一点上很明显它不是 你正在练习窗口类和后台计时器之间的通信,这不是一个开始的话题。如果你想使用定时器,从一个窗口类开始,使用winform定时器docs.microsoft.com/en-us/dotnet/api/… 如果项目是 WPF,则为 DispatcherTimer

以上是关于C# 简单秒表 - 初学者的主要内容,如果未能解决你的问题,请参考以下文章

如何在这个颤振秒表中制作代码?

CSS样式表初学,比C#和JS简单

C#初学单例模式

C#使用TcpListener和TcpClient实现简单通信

初学c# -- 学习笔记

初学者的小随笔