第一个 WPF 应用
这一篇带你做一个最小 WPF 上位机窗口:输入文本,点击发送,虚拟通道回显,界面显示通道状态。
先运行示例
在仓库的 code 目录执行:
dotnet run --project samples/Zeus.Samples.Wpf.QuickStart
窗口打开后:
- 状态应显示
Open。 - 输入框默认是
PING。 - 点击“发送”。
- 回显区域应显示
PING。
如果能看到回显,说明 Zeus 宿主、虚拟通道和 WPF Dispatcher 封送都正常。
你的项目需要哪些包
dotnet add package Zeus.Communications --prerelease
dotnet add package Zeus.Presentation.Wpf --prerelease
项目文件需要是 Windows 桌面目标:
<TargetFramework>net8.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
XAML 界面
<Window x:Class="MyApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Zeus WPF QuickStart"
Height="260"
Width="520">
<Grid Margin="16">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="发送" />
<TextBox x:Name="InputBox" Grid.Row="0" Grid.Column="1" Text="PING" />
<Button Grid.Row="1" Grid.Column="1" Content="发送" Click="OnSendClick" />
<TextBlock Grid.Row="2" Grid.Column="0" Text="状态" />
<TextBlock x:Name="StateText" Grid.Row="2" Grid.Column="1" />
<TextBlock Grid.Row="3" Grid.Column="0" Text="回显" />
<TextBlock x:Name="EchoText" Grid.Row="3" Grid.Column="1" />
</Grid>
</Window>
后台代码
using System.Text;
using System.Windows;
using Zeus;
public partial class MainWindow : Window
{
private readonly IChannel _meter;
public MainWindow()
{
InitializeComponent();
var attachment = this.AttachZeus(builder => builder.AddVirtualChannel("meter"));
_meter = attachment.Host.Channels.Get("meter");
_meter.BindState(StateText);
_meter.BindTo(EchoText);
}
private async void OnSendClick(object sender, RoutedEventArgs e)
{
await _meter.WriteAsync(Encoding.UTF8.GetBytes(InputBox.Text));
}
}
这段代码怎么理解
| 代码 | 作用 |
|---|---|
this.AttachZeus(...) | 把宿主挂到 WPF 窗口生命周期上,窗口加载时启动,关闭时释放 |
AddVirtualChannel("meter") | 声明一条不用硬件的虚拟通道 |
Channels.Get("meter") | 取出通道对象 |
BindState(StateText) | 把通道状态写入 TextBlock |
BindTo(EchoText) | 收到数据后把文本写入 TextBlock |
WriteAsync(...) | 点击按钮时发送输入框内容 |
为什么不用自己 Dispatcher.Invoke
通道收到数据时,事件可能来自 IO 线程。WPF 控件只能在 Dispatcher 线程更新。
BindTo 和 BindState 已经封装了 Dispatcher 切换,所以你不需要在每次接收数据时手写 Dispatcher.Invoke。
想用 XAML 数据绑定怎么办
如果你不想直接绑定到 TextBlock,可以用:
DataContext = _meter.AsBindingSource(this);
常用属性包括:
| 属性 | 含义 |
|---|---|
LastText | 最近一次收到的数据,按文本显示 |
LastHex | 最近一次收到的数据,按十六进制显示 |
StateText | 通道状态文本 |
ReceivedCount | 已收到的次数 |
换成真实串口
先只改这一行:
var attachment = this.AttachZeus(builder => builder.AddSerialPort("meter", "COM3", 9600));
界面绑定和发送代码不变。如果串口打不开,先回到虚拟通道确认界面逻辑,再检查端口和设备参数。