我有一个WPF应用程序和一个用Kinetis开发平台制作的数字时钟。 WPF发送初始时间和5条警报。但是,当Kinetis发送有关警报已激活的通知时,WPF应用程序会读取警报并显示为消息框,但在激活消息框时,应用程序中的数字时钟会停止。如何保持时钟运转?



CS

public partial class MainWindow : Window
    {
        SerialPort sp;

        public MainWindow()
        {
            InitializeComponent();
        }

        void timer_Tick(object sender, EventArgs e)
        {
            lblTime.Content = Convert.ToDateTime(lblTime.Content).AddSeconds(1).ToLongTimeString();
            int btr = sp.BytesToRead;
            if (btr != 0)
            {
                string alarma = char.ConvertFromUtf32(sp.ReadChar());
                MessageBoxResult result = MessageBox.Show("La alarma " + alarma + " se activo", "Alarma", MessageBoxButton.OK, MessageBoxImage.Exclamation);
            }
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            int intHoras = Convert.ToInt32(Horas.Text == "" ? "-1" : Horas.Text);
            int intMinutos = Convert.ToInt32(Minutos.Text == "" ? "-1" : Minutos.Text);

            int intHoras1 = Convert.ToInt32(Horas1.Text == "" ? "-1" : Horas1.Text);
            int intMinutos1 = Convert.ToInt32(Minutos1.Text == "" ? "-1" : Minutos1.Text);

            int intHoras2 = Convert.ToInt32(Horas2.Text == "" ? "-1" : Horas2.Text);
            int intMinutos2 = Convert.ToInt32(Minutos2.Text == "" ? "-1" : Minutos2.Text);

            int intHoras3 = Convert.ToInt32(Horas3.Text == "" ? "-1" : Horas3.Text);
            int intMinutos3 = Convert.ToInt32(Minutos3.Text == "" ? "-1" : Minutos3.Text);

            int intHoras4 = Convert.ToInt32(Horas4.Text == "" ? "-1" : Horas4.Text);
            int intMinutos4 = Convert.ToInt32(Minutos4.Text == "" ? "-1" : Minutos4.Text);

            int intHoras5 = Convert.ToInt32(Horas5.Text == "" ? "-1" : Horas5.Text);
            int intMinutos5 = Convert.ToInt32(Minutos5.Text == "" ? "-1" : Minutos5.Text);

            if ((intHoras <= 24) && (intMinutos <= 60) && (intHoras >= 0) && (intMinutos >= 0) &&
                (intHoras1 <= 24) && (intMinutos1 <= 60) && (intHoras1 >= 0) && (intMinutos1 >= 0) &&
                (intHoras2 <= 24) && (intMinutos2 <= 60) && (intHoras2 >= 0) && (intMinutos2 >= 0) &&
                (intHoras3 <= 24) && (intMinutos3 <= 60) && (intHoras3 >= 0) && (intMinutos3 >= 0) &&
                (intHoras4 <= 24) && (intMinutos4 <= 60) && (intHoras4 >= 0) && (intMinutos4 >= 0) &&
                (intHoras5 <= 24) && (intMinutos5 <= 60) && (intHoras5 >= 0) && (intMinutos5 >= 0))
            {
                sp = new SerialPort("COM3");
                sp.BaudRate = 19200;
                sp.Open();

                WriteTime(sp, intHoras, intMinutos);
                WriteTime(sp, intHoras1, intMinutos1);
                WriteTime(sp, intHoras2, intMinutos2);
                WriteTime(sp, intHoras3, intMinutos3);
                WriteTime(sp, intHoras4, intMinutos4);
                WriteTime(sp, intHoras5, intMinutos5);

                DateTime date = new DateTime();
                TimeSpan ts = new TimeSpan(0, intHoras, intMinutos + 2);
                date = date + ts;
                lblTime.Content = date.ToLongTimeString();
                DispatcherTimer timer = new DispatcherTimer();
                timer.Interval = TimeSpan.FromSeconds(1);
                timer.Tick += timer_Tick;
                timer.Start();

            }
            else
            {
                MessageBoxResult result = MessageBox.Show("Ingresaste datos incorrectos", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private void WriteTime(SerialPort sp, int intHoras, int intMinutos)
        {
            List<byte[]> horas = getVectorNumber(intHoras);
            List<byte[]> minutos = getVectorNumber(intMinutos);
            foreach (byte[] item in horas)
            {
                sp.Write(item, 0, 1);
            }
            foreach (byte[] item in minutos)
            {
                sp.Write(item, 0, 1);
            }
        }

        private List<byte[]> getVectorNumber(int number)
        {
            List<byte[]> result = new List<byte[]>();
            result.Add(Encoding.ASCII.GetBytes(Convert.ToString(number / 10)));
            result.Add(Encoding.ASCII.GetBytes(Convert.ToString(number % 10)));
            return result;
        }

        #region NumericValidation
        private void textBoxValue_PreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            e.Handled = !TextBoxTextAllowed(e.Text);
        }

        private void textBoxValue_Pasting(object sender, DataObjectPastingEventArgs e)
        {
            if (e.DataObject.GetDataPresent(typeof(String)))
            {
                String Text1 = (String)e.DataObject.GetData(typeof(String));
                if (!TextBoxTextAllowed(Text1)) e.CancelCommand();
            }
            else e.CancelCommand();
        }
        #endregion

        private Boolean TextBoxTextAllowed(String Text2)
        {
            return Array.TrueForAll<Char>(Text2.ToCharArray(),
                delegate(Char c) { return Char.IsDigit(c) || Char.IsControl(c); });
        }


    }


XAML

![<Window x:Class="DigitalPITClock.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="579.254" Width="877.835">
    <Grid Background="Gray" Margin="0,0,-4.8,-55">
        <Label Name="lblTime" FontSize="48" HorizontalAlignment="Left" Margin="297,22,0,0" VerticalAlignment="Top" Height="83" Width="269" RenderTransformOrigin="0.495,0.468"/>
        <Label Content="Ingrese las horas y los minutos" HorizontalAlignment="Left" Margin="324,105,0,0" VerticalAlignment="Top" FontSize="15px"/>
        <Label Content="Horas" HorizontalAlignment="Left" Margin="270,157,0,0" VerticalAlignment="Top" Height="44" Width="59" FontSize="15px"/>
        <TextBox Name="Horas" HorizontalAlignment="Left" Margin="363,157,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="-0.906,0.034" Height="29" Width="37" PreviewTextInput="textBoxValue_PreviewTextInput" DataObject.Pasting="textBoxValue_Pasting" MaxLength="2" FontSize="15px"/>
        <Label Content="Minutos" HorizontalAlignment="Left" Margin="445,157,0,0" VerticalAlignment="Top" Height="29" Width="71" FontSize="15px"/>
        <TextBox Name="Minutos" HorizontalAlignment="Left" Margin="544,157,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="-0.906,0.034" Height="29" Width="38" PreviewTextInput="textBoxValue_PreviewTextInput" DataObject.Pasting="textBoxValue_Pasting" MaxLength="2" FontSize="15px"/>

        <Label Content="Alarma 1" HorizontalAlignment="Left" Margin="171,207,0,0" VerticalAlignment="Top" RenderTransformOrigin="0.487,0.445"/>
        <Label Content="Horas" HorizontalAlignment="Left" Margin="25,253,0,0" VerticalAlignment="Top" Height="44" Width="59" FontSize="15px"/>
        <TextBox x:Name="Horas1" HorizontalAlignment="Left" Margin="118,253,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="-0.906,0.034" Height="29" Width="37" PreviewTextInput="textBoxValue_PreviewTextInput" DataObject.Pasting="textBoxValue_Pasting" MaxLength="2" FontSize="15px"/>
        <Label Content="Minutos" HorizontalAlignment="Left" Margin="200,253,0,0" VerticalAlignment="Top" Height="29" Width="71" FontSize="15px"/>
        <TextBox x:Name="Minutos1" HorizontalAlignment="Left" Margin="299,253,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="-0.906,0.034" Height="29" Width="38" PreviewTextInput="textBoxValue_PreviewTextInput" DataObject.Pasting="textBoxValue_Pasting" MaxLength="2" FontSize="15px"/>

        <Label Content="Alarma 2" HorizontalAlignment="Left" Margin="170,324,0,0" VerticalAlignment="Top" RenderTransformOrigin="0.487,0.445"/>
        <Label Content="Horas" HorizontalAlignment="Left" Margin="24,363,0,0" VerticalAlignment="Top" Height="44" Width="59" FontSize="15px"/>
        <TextBox x:Name="Horas2" HorizontalAlignment="Left" Margin="117,363,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="-0.906,0.034" Height="29" Width="37" PreviewTextInput="textBoxValue_PreviewTextInput" DataObject.Pasting="textBoxValue_Pasting" MaxLength="2" FontSize="15px"/>
        <Label Content="Minutos" HorizontalAlignment="Left" Margin="199,363,0,0" VerticalAlignment="Top" Height="29" Width="71" FontSize="15px"/>
        <TextBox x:Name="Minutos2" HorizontalAlignment="Left" Margin="298,363,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="-0.906,0.034" Height="29" Width="38" PreviewTextInput="textBoxValue_PreviewTextInput" DataObject.Pasting="textBoxValue_Pasting" MaxLength="2" FontSize="15px"/>

        <Label Content="Alarma 3" HorizontalAlignment="Left" Margin="385,421,0,0" VerticalAlignment="Top" RenderTransformOrigin="0.487,0.445"/>
        <Label Content="Horas" HorizontalAlignment="Left" Margin="249,473,0,0" VerticalAlignment="Top" Height="44" Width="59" FontSize="15px"/>
        <TextBox x:Name="Horas3" HorizontalAlignment="Left" Margin="342,473,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="-0.906,0.034" Height="29" Width="37" PreviewTextInput="textBoxValue_PreviewTextInput" DataObject.Pasting="textBoxValue_Pasting" MaxLength="2" FontSize="15px"/>
        <Label Content="Minutos" HorizontalAlignment="Left" Margin="424,473,0,0" VerticalAlignment="Top" Height="29" Width="71" FontSize="15px"/>
        <TextBox x:Name="Minutos3" HorizontalAlignment="Left" Margin="523,473,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="-0.906,0.034" Height="29" Width="38" PreviewTextInput="textBoxValue_PreviewTextInput" DataObject.Pasting="textBoxValue_Pasting" MaxLength="2" FontSize="15px"/>

        <Label Content="Alarma 4" HorizontalAlignment="Left" Margin="614,207,0,0" VerticalAlignment="Top" RenderTransformOrigin="0.487,0.445"/>
        <Label Content="Horas" HorizontalAlignment="Left" Margin="476,258,0,0" VerticalAlignment="Top" Height="44" Width="59" FontSize="15px"/>
        <TextBox x:Name="Horas4" HorizontalAlignment="Left" Margin="569,258,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="-0.906,0.034" Height="29" Width="37" PreviewTextInput="textBoxValue_PreviewTextInput" DataObject.Pasting="textBoxValue_Pasting" MaxLength="2" FontSize="15px"/>
        <Label Content="Minutos" HorizontalAlignment="Left" Margin="651,258,0,0" VerticalAlignment="Top" Height="29" Width="71" FontSize="15px"/>
        <TextBox x:Name="Minutos4" HorizontalAlignment="Left" Margin="750,258,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="-0.906,0.034" Height="29" Width="38" PreviewTextInput="textBoxValue_PreviewTextInput" DataObject.Pasting="textBoxValue_Pasting" MaxLength="2" FontSize="15px"/>

        <Label Content="Alarma 5" HorizontalAlignment="Left" Margin="614,324,0,0" VerticalAlignment="Top" RenderTransformOrigin="0.487,0.445"/>
        <Label Content="Horas" HorizontalAlignment="Left" Margin="477,363,0,0" VerticalAlignment="Top" Height="44" Width="59" FontSize="15px"/>
        <TextBox x:Name="Horas5" HorizontalAlignment="Left" Margin="570,363,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="-0.906,0.034" Height="29" Width="37" PreviewTextInput="textBoxValue_PreviewTextInput" DataObject.Pasting="textBoxValue_Pasting" MaxLength="2" FontSize="15px"/>
        <Label Content="Minutos" HorizontalAlignment="Left" Margin="652,363,0,0" VerticalAlignment="Top" Height="29" Width="71" FontSize="15px"/>
        <TextBox x:Name="Minutos5" HorizontalAlignment="Left" Margin="751,363,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="-0.906,0.034" Height="29" Width="38" PreviewTextInput="textBoxValue_PreviewTextInput" DataObject.Pasting="textBoxValue_Pasting" MaxLength="2" FontSize="15px"/>

        <Button Content="Aplicar Cambios" HorizontalAlignment="Left" Margin="351,552,0,0" VerticalAlignment="Top" Width="113" Height="28" Click="Button_Click"/>
    </Grid>
</Window>

最佳答案

这里的基本问题是,直到用户关闭了消息框,您才从计时器的Tick事件处理程序中返回。在您处理完当前事件之前,计时器不会发出另一个Tick事件。

您应该使用Dispatcher.BeginInvoke()方法异步显示消息框,而不是在事件处理程序本身中显示消息框:

    void timer_Tick(object sender, EventArgs e)
    {
        lblTime.Content = Convert.ToDateTime(lblTime.Content).AddSeconds(1).ToLongTimeString();
        int btr = sp.BytesToRead;
        if (btr != 0)
        {
            string alarma = char.ConvertFromUtf32(sp.ReadChar());

            Dispatcher.BeginInvoke((Action)(() =>
                MessageBox.Show("La alarma " + alarma + " se activo", "Alarma",
                    MessageBoxButton.OK, MessageBoxImage.Exclamation)));
        }
    }


这会将您的方法调用包装在一个委托中,该委托又被排队,以便稍后在同一线程(分派器线程)中执行。这允许Tick事件处理程序返回,以便计时器可以继续运行。

也就是说,您的代码不太正确。恕我直言,要解决的最明显,最重要的问题是计时器(所有计时器)不是很准确。如您所见,它们可能由于各种原因而被延迟,并且没有计划好精确地执行它们。随着时间的流逝,您的时钟很可能会与您要显示的实际时间发生偏差。

相反,您应该使用例如Stopwatch的实例,在您希望时钟启动时将其启动,将其Elapsed值添加到初始值(即new TimeSpan(0, intHoras, intMinutos + 2),您可以计算一次并为此存储在类字段中),并且用适当的显式格式字符串(例如"hh:mm:ss tt")显示该总和。


编辑:

这确实是原始问题的第二要因,但是既然您问过……

更好地跟踪时钟时间的方法如下:

1.向您的班级添加两个新字段:

private TimeSpan baseTime;
private Stopwatch elapsed;


2.启动计时器时初始化以下字段:

baseTime = new TimeSpan(0, intHoras, intMinutos + 2);
elapsed = Stopwatch.StartNew();


3.然后使用这些值在计时器的Tick事件处理程序中显示时间:

lblTime.Content = (baseTime + elapsed.Elapsed).ToString(@"hh\:mm\:ss");


自然,您将删除其他与时间显示相关的代码:初始化代码中的DateTimeTimeSpan局部变量,以及在lblTime.Content事件处理程序方法中设置Tick的现有语句。


最后,如果它能平息汉斯对Stopwatch的反对,则可以仅使用DateTime来实现上述内容。也就是说,代替以上内容,执行以下操作:

1.向您的班级添加两个新字段:

private TimeSpan baseTime;
private DateTime startTime;


2.启动计时器时初始化以下字段:

baseTime = new TimeSpan(0, intHoras, intMinutos + 2);
startTime = DateTime.UtcNow;


3.然后使用这些值在计时器的Tick事件处理程序中显示时间:

lblTime.Content = (baseTime + (DateTime.UtcNow - startTime)).ToString(@"hh\:mm\:ss");


请注意,UtcNow依赖于系统时钟,因此,如果更改它,将影响显示的经过时间,从而导致它不正确。例如,如果用户更改了设置时间,或者系统自动更新了NTP服务器的时钟(自动调整NTP服务器的时钟会改善显示时间的唯一方法是,如果系统时钟偏离时钟正确的时间,而不是启动程序中的计数器时已经漂移的时间……这不是很常见的情况)。

关于c# - 将数据发送到串行端口时的异步数字时钟,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30339717/

10-09 20:35
查看更多