c# - 读出按钮被按下的时间(串行通信 C#,WPF)
问题描述
我刚开始在 C# 中进行串行通信,所以也许这是一个非常简单的问题,但是我花了最后三天的时间在谷歌上搜索,我的问题仍然没有解决,所以希望你能帮助我。
我有一个设备(它是一种特殊的手风琴),上面有很多按钮。当我按下按钮时,获取数据没有问题。对于每个按钮,我都会收到一段不同的 ASCII 码。
我的问题是:我需要知道时间,我按下按钮的时间。但是我只有在按下按钮时才会获取数据(而不是在释放按钮时)。
有没有可能找出来?
下面你会看到我编写的程序,只是为了了解串行通信的工作原理。
我的 Commport 课程:
class MyCommPort : INotifyPropertyChanged
{
//Implementierung von "INotifyPropertyChanged"
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
//Felder
private SerialPort _serialPort = null;
private SolidColorBrush fillColor1 = Brushes.LightBlue;
private SolidColorBrush fillColor2 = Brushes.LightBlue;
private string text = null;
//Eigenschaften
public SerialPort SerialPort
{
get { return _serialPort; }
set { _serialPort = value; }
}
public SolidColorBrush FillColor1
{
get { return fillColor1; }
set
{
fillColor1 = value;
OnPropertyChanged("FillColor1");
}
}
public SolidColorBrush FillColor2
{
get { return fillColor2; }
set
{
fillColor2 = value;
OnPropertyChanged("FillColor2");
}
}
public string Text
{
get { return text; }
set
{
text = value;
OnPropertyChanged("Text");
}
}
//Konstruktor
public MyCommPort()
{
//Neuer Port wird angelegt
SerialPort = new SerialPort("COM3", 115200);
//Port wird geöffnet
SerialPort.Open();
//Wenn Daten am Port ankommen wird Event gefeuert
SerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
}
//Destruktor
~MyCommPort()
{
//Port wird geschlossen
SerialPort.Close();
}
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
Thread.Sleep(10);
//Neuer Port (Kopie von serialPort) wird angelegt ==> sender ist serialPort!
SerialPort sp = (SerialPort)sender;
//string DataIN = null;
string DataIN = sp.ReadExisting();
switch (DataIN)
{
case "(D07084)":
FillColor1 = Brushes.Red;
break;
case "(D04081)":
FillColor2 = Brushes.Red;
break;
default:
break;
}
Text = DataIN;
DataIN = null;
Thread.Sleep(200);
FillColor1 = Brushes.LightBlue;
FillColor2 = Brushes.LightBlue;
}
}
我的观点:
<Window x:Class="USB.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:USB"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Ellipse Grid.Row="0" Fill="{Binding Path=FillColor1}" />
<Ellipse Grid.Row="1" Fill="{Binding Path=FillColor2}" />
</Grid>
<TextBox Grid.Column="1" Text="{Binding Text}" Height="50" Width="200"/>
</Grid>
视图的代码隐藏:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MyCommPort();
}
}
解决方案
我要写的答案可能看起来很不可靠;然而,在有人想出一些绝妙的主意之前,这就是你所得到的。
由于您无法到达按钮释放的那一刻,因此当(且仅当)您的设备一直发送相同的键数据时(且仅当)只要按住键就可以完成一个技巧。
您需要定义一个间隔,该间隔对于人类来说太小不能按两次键,而对于机器来说太大而不能发送两次按下的键数据。在此示例中,我假设您的关键代码是int
,并且我会将预定义的时间间隔视为75
(毫秒)。
private delegate void SerialPortKeyUpHandler(int keyCode, TimeSpan timeHeld);
private event SerialPortKeyUpHandler SerialPortKeyUp;
CancellationTokenSource cancellationTokenSource;
private int keyCode;
private const int accuracy = 75; //the interval I'm talking about
private void StartCapturing(int keyCode)
{
this.keyCode = keyCode;
DateTime start = DateTime.UtcNow;
cancellationTokenSource.CancelAfter(accuracy);
ParameterizedThreadStart threadStart = new ParameterizedThreadStart((object cancellationTokenObj) =>
{
CancellationToken cancellationToken = (CancellationToken)cancellationTokenObj;
while (!cancellationToken.IsCancellationRequested) ; //wait until we make sure no more of the same key data is being sent
SerialPortKeyUp?.Invoke(keyCode, DateTime.UtcNow.Subtract(start));
});
Thread thread = new Thread(threadStart);
thread.Start(cancellationTokenSource.Token);
}
private void KeyDownCallback(object sender, KeyEventArgs e)
{
if (cancellationTokenSource == null || cancellationTokenSource.IsCancellationRequested)
{
cancellationTokenSource = new CancellationTokenSource();
StartCapturing(e.KeyValue);
}
else
{
if (e.KeyValue == keyCode)
{
cancellationTokenSource.CancelAfter(accuracy);
}
else
{
cancellationTokenSource.Cancel();
cancellationTokenSource.Dispose();
cancellationTokenSource = new CancellationTokenSource();
StartCapturing(e.KeyValue);
}
}
}
private void KeyUpCallback(int keyCode, TimeSpan heldTime)
{
Debug.WriteLine($"Key {keyCode} is up. The key was held for {heldTime.TotalSeconds.ToString("#.00")} second(s).");
}
现在您有一个SerialPortKeyUp
要注册的活动;为此,请在某处输入
SerialPortKeyUp += KeyUpCallback;
推荐阅读
- java - ANTLR 2 令牌流多路复用:为什么我的令牌出现故障?
- azure-devops - 在 Azure Devops 中运行顺序构建管道作为拉取请求分支策略的一部分
- java - 微调器值未显示正确值(改造)
- python - 在期权计算中正确指定无风险利率
- linux - 如何在 openhpi 安装期间解决 openssl 问题?
- python - 如何解决 Pycharm 中的 Visual Studio 问题
- ios - 在情节提要中注册笔尖
- c - 这个反向循环在 C 中是否正确?
- r - 如何在 R 包中的说明中添加参考作者?
- c++ - 为什么我的 C++ 程序的汇编输出充满了没有汇编代码的 .ascii?