将数据发送到串行端口

时间:2015-05-20 03:21:07

标签: c# wpf

我有一个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>

1 个答案:

答案 0 :(得分:3)

这里的基本问题是,在用户取消消息框之前,您不会从计时器的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)));
        }
    }

这会将您的方法调用包装在一个委托中,该委托又被排队以便稍后在同一个线程(Dispatcher线程)中执行。这允许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局部变量,以及在{1}}中设置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服务器自动调整时钟的唯一方法是改善显示的时间,如果当你的程序中的计数器启动时,系统时钟已经从正确的时间漂移​​得更远......这不是一个非常常见的情况。)