跳到主要内容

WPF 适配器

通过 Dispatcher 把通道事件切到界面线程,并提供 TextBlock 绑定和可绑定源。

var attachment = this.AttachZeus(builder => builder.AddVirtualChannel("meter"));
var meter = attachment.Host.Channels.Get("meter");
meter.BindTo(EchoText);
DataContext = meter.AsBindingSource(this);
<TextBlock Text="{Binding LastText}" />
<TextBlock Text="{Binding StateText}" />

程序集:Zeus.Presentation.Wpf(目标框架 net8.0-windows)。

API

API作用
Window.AttachZeus(...)Loaded 时启动,Closed 时释放
BindTo / BindText写入 TextBlock.Text
BindState显示通道状态
AsBindingSource(element)用该元素的 Dispatcher 发布属性变更
points.BindTo("temperature", textBlock)把点表值写到文本块

ChannelBindingSource 的属性:NameStateStateTextLastTextLastHexReceivedCount

接入已有 WPF / Prism 项目

如果你的 WPF 项目已经使用 Prism、DryIoc、Unity 或自己的业务容器,不需要让 Zeus 接管整个应用。推荐做法是:应用容器继续管理窗口、导航和 ViewModel,Zeus 作为一个单例服务注册进去,Zeus 自己负责通道、设备、采集循环和释放。

下面只展示 App.xaml.cs 里和 Zeus 有关的部分:

using Prism.Ioc;
using System.Windows;
using Zeus;

public partial class App : PrismApplication
{
private IZeusHost? _zeus;

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
var zeus = ZeusHost.Create(builder =>
{
builder.AddSerialPort("meter", "COM3", 9600);
builder.AddAcquisition(TimeSpan.FromMilliseconds(500));
});

_zeus = zeus;
containerRegistry.RegisterInstance<IZeusHost>(zeus);
containerRegistry.RegisterInstance<IChannelRegistry>(zeus.Channels);
containerRegistry.RegisterInstance<IPointTable>(zeus.Points);
}

protected override async void OnInitialized()
{
base.OnInitialized();

if (_zeus is not null)
{
await _zeus.StartAsync();
}
}

protected override void OnExit(ExitEventArgs e)
{
_zeus?.DisposeAsync().AsTask().GetAwaiter().GetResult();

base.OnExit(e);
}
}

ViewModel 中优先依赖更窄的接口,而不是到处解析整个宿主:

public sealed class MeterViewModel
{
private readonly IChannel _meter;

public MeterViewModel(IChannelRegistry channels)
{
_meter = channels.Get("meter");
}

public Task SendAsync(byte[] payload) => _meter.WriteAsync(payload);
}

需要显示采集点时,再把 IPointTable 注入到 ViewModel。

如果你的业务服务需要被 Zeus 的注册回调使用,可以把它注册到 Zeus 自己的 builder.Services 中:

_zeus = ZeusHost.Create(builder =>
{
builder.Services.AddSingleton<AlarmService>();
builder.AddSerialPort("meter", "COM3", 9600);
});

这种情况下要注意边界:Prism 容器和 Zeus 的 builder.Services 是两个容器。默认推荐把 Zeus 注册进 Prism 容器,供界面和 ViewModel 使用;不要强行让两个容器互相解析,除非你明确知道生命周期和释放顺序。

常见问题

  • 绑定没有更新:属性名区分大小写,请对照上表。
  • 在后台线程创建 AsBindingSource:必须传入窗口或控件,才能拿到正确的 Dispatcher
  • 已有 Prism 容器怎么接:把 IZeusHostIChannelRegistryIPointTable 注册成 Prism 单例,在应用启动时启动 Zeus,在退出时释放。
  • 窗口正在关闭:此时的更新会被丢弃。