Chapter 8 综合练习2

本文示例源码地址是: StdUnit.Tags.WPFDemo ,位于分支 eg-2 中

你可以直接使用StdUnit.Tags.Templates 模板,执行命令dotnet new tags.wpf来创建一个脚手架,并基于它来微调成这里代码。

在上一篇,我们讲述了外部意图的适用场景和工作机制。在这里,我们打算在综合练习一的基础上,演示如何使用意图在Logicet外部变更点位。

作为示例,我们将演示如何通过按钮在Logicet外部变更点位。之前我们都是基于dotnet/reactive进行演示,这次我们尝试使用Cysharp/R3来完成这个任务。

首先移除之前的StdUnit.Tags.RxExtensions依赖,改用StdUnit.Tags.R3Extensions:

<PackageReference Include="StdUnit.Tags.R3Extensions" Version="1.0.0" />
<PackageReference Include="R3Extensions.WPF" Version="1.3.1" />

这里的R3Extensions.WPF是R3官方为WPF平台开发的扩展包。

界面调整

我们把之前的示例改成左右两栏,左侧放心跳状态的监视页面,右侧放一个切换心跳请求的按钮:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    
    <Grid Grid.Column="0">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition />
        </Grid.RowDefinitions>

        <Label Grid.Row="0" Grid.Column="0">心跳请求</Label>
        <TextBlock  Name="txtReq" Grid.Row="0" Grid.Column="1" />

        <Label Grid.Row="1" Grid.Column="0">心跳响应</Label>
        <TextBlock Name="txtAck" Grid.Row="1" Grid.Column="1" />
    </Grid>

    <Grid Grid.Column="1">
        <Button x:Name="btnToggle" Click="btnToggle_Click">切换心跳</Button>
    </Grid>
</Grid>

这里单击事件btnToggle_Click是:

private async void btnToggle_Click(object sender, RoutedEventArgs e)
{
    var proj = this._ctrl?.Project;
    if(proj is null)
    {
        return;
    }
    var enqueue = proj.WriteIntent(
        entry:"IoBox", 
        intent: (grp, ct) => {
            var tag = proj.Tags.SelectTag("IoBox/通用状态/PLC/心跳请求");
            var old = tag.GetTagValue<bool>();
            tag.Value = !old;
            return ValueTask.CompletedTask;
        }, 
        out var task
    );
    await task;
}

在这里,我们通过proj.WriteIntent(entry, intent, out task)进行了外部意图的写入。

信号监听

为了让左侧的信号界面能如实反映当前的信号状态,我们还需要几行监视代码:

req.Watch()
    .ObserveOnCurrentDispatcher()
    .Subscribe(evt =>
    {
        var newvalue = evt.NewValue;
        this.txtReq.Text = newvalue?.ToString();
        this.txtReq.Foreground= newvalue is true ? Brushes.Green : Brushes.Black;
    })
    .AddTo(_disposables);

ack.Watch()
    .ObserveOnCurrentDispatcher()
    .Subscribe(evt =>
    {
        var newvalue = evt.NewValue;
        this.txtAck.Text = newvalue?.ToString();
        this.txtAck.Foreground = newvalue is true ? Brushes.Green : Brushes.Black;
    })
    .AddTo(_disposables);

至此,一个简单的信号监控程序完成了: