//类型简介
AutoResetEventWindow 类:UI窗体
Port类:一个模拟串口的类型
Sender类:数据包
//成员简介
Port.ReceiveEvent:一个事件成员,模拟串口收到数据后通过事件触发一个回调
Port.Write():一个模拟串口写入数据的方法
程序运行思路
1、在UI窗体类中声明一个队列queue,用于存储下包数据包Sender的实例
2、在UI窗体类中声明一个producer线程,用于不断向队列queue中新增sender
3、在UI窗体类中声明一个customer线程,用于不断从队列queue中取出sender
4、将取出来的sender数据包下发给串口,然后利用AutoResetEvent 阻塞当前线程,直至在Port.ReceiveEvent事件的回调函数中松开阻塞器,再取出下一个sender发给串口…
5、如此循环…
6、可以通过按钮事件随时向队列queue中插入sender…(插队)
namespace WPF大全.View
{
/// <summary>
/// 发送对象
/// </summary>
public class Sender
{
public string Text = "";
public AutoResetEvent Auto = null;
public bool IsSuccess { get; internal set; }
}
public class Port
{
public event Action<Sender> ReceiveEvent;
public void Write(Sender sender)
{
Thread.Sleep(500);
sender.IsSuccess = true;
sender.Text = "已接收:" + sender.Text;
ReceiveEvent?.Invoke(sender);
}
}
/// <summary>
/// AutoResetEventWindow.xaml 的交互逻辑
/// </summary>
public partial class AutoResetEventWindow : Window
{
private Thread producer;
private Thread customer;
private Queue<Sender> queue = new Queue<Sender>();
private object queueLock = new object();
private AutoResetEvent Auto = new AutoResetEvent(false);
Port port = new Port();
public AutoResetEventWindow()
{
InitializeComponent();
port.ReceiveEvent += Port_ReceiveEvent;
producer = new Thread(Product);//生产者
producer.IsBackground = true;
producer.Start();
customer = new Thread(Custom);//消费者
customer.IsBackground = true;
customer.Start();
}
//回调函数中解析回传数据,并设置AutoResetEvent.Set()
private void Port_ReceiveEvent(Sender obj)
{
Dispatcher.Invoke(() =>
{
_richTextBox.AppendText("\n");
_richTextBox.AppendText(obj.Text);
_richTextBox.ScrollToEnd(); //自动滚动到底
Auto.Set();
});
}
/// <summary>
/// 消费者线程
/// </summary>
private void Custom()
{
while (true)
{
Sender item = null;
lock (queueLock)
{
if (queue.Count > 0)
{
item = queue.Dequeue();
}
}
if (item != null)
{
port.Write(item);
Auto.WaitOne();
}
Thread.Sleep(100);
}
}
/// <summary>
/// 生产者线程
/// </summary>
private void Product()
{
while (true)
{
Sender sender = new Sender();
sender.Auto = this.Auto;
sender.Text = DateTime.Now.ToString();
lock (queueLock)
{
queue.Enqueue(sender);
}
Thread.Sleep(1000);
}
}
//偶尔手动生产
private void Button_Click(object sender, RoutedEventArgs e)
{
Sender item = new Sender();
item.Auto = this.Auto;
item.Text = $"插入:{DateTime.Now.ToString()}";
lock (queueLock)
{
queue.Enqueue(item);
}
}
}
}
前端XAML代码
<Window x:Class="WPF大全.View.AutoResetEventWindow"
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:WPF大全.View"
mc:Ignorable="d"
Title="AutoResetEventWindow" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0">
<Button Content="插入一条消息" Margin="10" Click="Button_Click"/>
</StackPanel>
<RichTextBox Grid.Column="1" x:Name="_richTextBox"/>
</Grid>
</Window>