试着创建一下吧

在 Extension (RC+自定义) 中,提供了用于将菜单项添加、项目文件管理、显示停靠窗口等功能集成到 Epson RC+ 的机制 (扩展点)。
这些功能通过将 Extensions API 提供的扩展点接口,作为 .NET 内置扩展框架 Managed Extensibility Framework (MEF) 的 Export 实现来运行。
在创建 Extension 项目时,可以将所需的扩展点作为 Initial Feature 进行选择,项目创建后也可以作为新项进行添加。

这里将介绍扩展点实现方法的一个示例,并说明从创建 RC+ Extensions 项目到在 Epson RC+ 中使用的流程。

以下步骤中,将在 Extension 的停靠窗口中配置按钮,并创建用于通过 Extension API 接口执行控制器连接/断开的示例。

  1. 按照 [开始使用] 的步骤,创建新的 Extension 项目。

    • 名称设为 ConnectControllerSample。
    • 初始功能勾选 Main menu and tool bar item、和 Docking window
    • 在 ARM64 版 Windows 上,请将配置设置为 x64。
  2. 在 Visual Studio 上进行构建和调试,确认功能正常运行。

    • 在 Epson RC+ 主菜单的扩展标签下,菜单项中会新增 ConnectControllerSample (xx)(xx 为显示语言名),选择菜单项后若能显示停靠窗口,则表示正常。
  3. 模板确认已完成,关闭 Epson RC+。

  4. 在 Visual Studio 上编辑 DockingWindow 文件夹下的 DockingWindowContent.xaml 文件。

    • 在自动生成配置的 TextBlock 下方的 Grid 内,新增用于控制器连接的 Button 以及用于控制器断开的 Button。
    • 请关注 TextBlock 的 Text。它绑定到 Captions[WindowHeader].Value。在 Extension 中,需要根据 Epson RC+ 的显示语言进行本地化的字符串记述在 Captions.xlsx 中。详细内容后述,通过使用 Captions.xlsx 的 symbol 列中定义的名称(本例中为 WindowHeader)以相同方式进行绑定,即可根据 Epson RC+ 的显示语言实现本地化。
    <UserControl x:Class="ConnectControllerSample.DockingWindow.DockingWindowContent"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                 xmlns:local="clr-namespace:ConnectControllerSample.DockingWindow"
                 mc:Ignorable="d"
                 d:DesignHeight="450" d:DesignWidth="800">
    
        <UserControl.DataContext>
            <local:DockingWindowContentViewModel />
        </UserControl.DataContext>
    
        <DockPanel
            Background="White"
            LastChildFill="True">
    
            <TextBlock
                Margin="3,0,0,0"
                DockPanel.Dock="Top"
                FontSize="24"
                FontWeight="Bold"
                Foreground="DarkBlue"
                Text="{Binding Captions[WindowHeader].Value}" />
    
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>
    
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>
    
                <Button
                    x:Name="ConnectButton"
                    Grid.Row="0"
                    Grid.Column="0"
                    Margin="4"
                    HorizontalAlignment="Left"
                    VerticalAlignment="Top"
                    Command="{Binding ConnectCommand}"
                    Content="Connect Controller" />
    
                <Button
                    x:Name="DisconnectButton"
                    Grid.Row="0"
                    Grid.Column="1"
                    Margin="4"
                    HorizontalAlignment="Left"
                    VerticalAlignment="Top"
                    Command="{Binding DisconnectCommand}"
                    Content="Disconnect Controller" />
            </Grid>
    
        </DockPanel>
    
    </UserControl>
    
  5. 编辑 DockingWindow 文件夹下的 DockingWindowContentViewModelAddition.cs 文件。

    • 在 .xaml 中新增绑定到控制器连接与断开 Button 的 ConnectCommand 以及 DisconnectCommand 命令。
    • 通过参照 IRCXControllerConnectionAPI(控制器连接 API)的 IsOnline 属性,可以确认与机器人控制器的连接状态。IsOnline 在连接建立时为 true,断开时为 false,其他 (如正在尝试连接等中间状态) 为 null。
    • 与机器人控制器的连接通过调用 IRCXControllerConnectionAPI 的 ConnectControllerAsync 方法实现。与机器人控制器的断开通过调用控制器连接 API 的 DisconnectControllerAsync 方法实现。
    • 消息框的显示通过调用 IRCXWindowAPI(窗口 API)的 ShowMessageBox 方法实现。
    • 在构造函数中,通过 Main 类的 GetAPI 方法,从 MEF 容器中获取 IRCXControllerConnectionAPI 以及 IRCXWindowAPI 的实例。
    (前略)
    namespace ConnectControllerSample.DockingWindow
    {
        /// <summary>
        /// Extension : Docking Window (Specific Part)
        /// </summary>
        internal partial class DockingWindowContentViewModel
        {
            /// <summary>
            /// Connect controller command
            /// </summary>
            public AsyncReactiveCommand ConnectCommand { get; } = new AsyncReactiveCommand();
    
            /// <summary>
            /// Disconnect controller command
            /// </summary>
            public AsyncReactiveCommand DisconnectCommand { get; } = new AsyncReactiveCommand();
    
            /// <summary>
            /// Window-related API
            /// </summary>
            private IRCXWindowAPI _windowAPI;
    
            /// <summary>
            /// Controller Connection API
            /// </summary>
            private IRCXControllerConnectionAPI _connectionAPI;
    
            /// <summary>
            /// Constructor
            /// </summary>
            public DockingWindowContentViewModel()
            {
                _windowAPI = Main.GetAPI<IRCXWindowAPI>();
                _connectionAPI = Main.GetAPI<IRCXControllerConnectionAPI>();
    
                ConnectCommand.Subscribe(OnConnect);
                DisconnectCommand.Subscribe(OnDiscconect);
            }
    
            private async Task OnConnect()
            {
                if (_connectionAPI.IsOnline == false)
                {
                    var result = await _connectionAPI.ConnectControllerAsync();
    
                    _windowAPI.ShowMessageBox(
                        new RCXCaption(Main.CommonId, Caption.ExtensionName),
                        new RCXCaption(result ? "Controller connection succeed." : "Controller connection failed."),
                        IRCXWindowAPI.ButtonType.OK,
                        IRCXWindowAPI.IconType.Information);
                }
                else
                { 
                    _windowAPI.ShowMessageBox(
                        new RCXCaption(Main.CommonId, Caption.ExtensionName),
                        new RCXCaption("The controller cannot be connected."),
                        IRCXWindowAPI.ButtonType.OK,
                        IRCXWindowAPI.IconType.Warning);
                }
            }
    
            private async Task OnDiscconect()
            {
                if (_connectionAPI.IsOnline == true)
                {
                    await _connectionAPI.DisconnectControllerAsync();
                }
                else
                {
                    _windowAPI.ShowMessageBox(
                        new RCXCaption(Main.CommonId, Caption.ExtensionName),
                        new RCXCaption("The controller cannot be disconnected."),
                        IRCXWindowAPI.ButtonType.OK,
                        IRCXWindowAPI.IconType.Warning);
                }
            }
    
            /// <inheritdoc />
            public Task WindowCreated()
            {
                return Task.CompletedTask;
            }
        }
    }
    
  6. 编辑项目文件夹根目录下的 Captions.xlsx 文件。

    • 修改 symbol 列为 WindowHeader 的行中各语言的标题。

  7. 重新构建和调试。

    • 在启动的 Epson RC+ 中,点击已开发 Extension 的菜单或工具栏图标,显示所创建的 DockingWindow。
    • 确认在画面上部显示 Captions.xlsx 中设置的、对应当前 Epson RC+ 语言的标题。
    • 确认可通过 [Connect Controller] 按钮和 [Disconnect Controller] 按钮连接和断开控制器。
  8. 在 Visual Studio 上编辑 PackageItems 文件夹中的 manifest.rcxmanifest。

    • 修改 Vendor Info、Extension Name、Summary、Description 行中各语言的字符串。

  9. 按照 [Extension 的分发] 步骤,在扩展功能管理器中显示已开发的 Extension。

    • 确认画面上显示 manifest.rcxmanifest 中设置的、对应当前 Epson RC+ 语言的信息。
  10. 按照 [Extension 的使用] 步骤,启用 Extension,并确认可以使用已开发的功能。