65.9K
CodeProject 正在变化。 阅读更多。
Home

BuilderHMI.Lite - 简单的拖放式WPF布局

starIconstarIconstarIconstarIconstarIcon

5.00/5 (30投票s)

2020 年 10 月 30 日

CPOL

7分钟阅读

viewsIcon

41683

.NET Core WPF 设计,像 WinForms 一样快速直观!听到了吗,微软?

背景

BuilderHMI 是一款用于工业操作员界面的低代码/无代码快速应用程序开发(RAD)工具。

无代码:UI 页面可以通过拖放方式快速轻松地设计,然后直接由应用程序运行。

低代码:可以生成包含完整 C# 源代码的完整 WPF 项目,以便在 MS Visual Studio 中进行自定义。

特点

  • 通过新建项目向导支持多项目
  • 能够独立运行(设计模式和运行模式)
  • 所有 UI 设计操作的撤销/重做堆栈
  • 无限 UI 页面,支持导航
  • 全套标准 WPF 控件
  • 嵌套的 Grid 和 Tab 控件
  • 用于工业 HMI 的 Stripchart 和其他专用控件
  • 带下载功能的运动程序文件编辑器控件
  • ButtonTextBlockBorder 等控件的样式选择
  • 将控件和完整页面保存到库以供重用
  • 与工业运动控制器进行可靠通信
  • 控件在点击时向运动控制器发送命令等
  • 警报、消息日志、用户登录系统
  • 支持外国用户进行国际化
  • 指定样式和配色方案(皮肤支持)
  • 类似浏览器的 Ctrl +/- 缩放 UI 屏幕
  • 带有直接编辑功能的实时 XAML 窗口
  • 可通过外部程序集(插件)进行自定义

BuilderHMI.Lite

BuilderHMI.Lite 是完整 BuilderHMI 应用程序的一个子集,专注于 WPF 屏幕设计和 Visual Studio 项目生成。该存储库包含应用程序的 .NET Core 和 .NET Framework 版本的源代码。

Visual Studio 兼容性:.NET Framework(非 Core)项目兼容 Visual Studio 2019 和 VS 2017,并使用 .NET 4.6.1。.NET Core 项目只能使用 VS 2019 并安装了“.NET 桌面开发”工作负载才能打开和构建。

YouTube 入门视频:

特点

  • 支持大多数常见的 WPF 控件类型
  • 添加控件后,左键拖动以移动,右键拖动以调整大小
  • 左/右/居中/拉伸水平对齐和顶部/底部/居中/拉伸垂直对齐
  • 编辑功能:剪切/复制/粘贴/删除,ToFrontToBack
  • 主窗口和所有控件的 WPF 样式支持
  • 从模板生成 Visual Studio WPF/C# 项目
  • 应用程序的 .NET Core 和 .NET Framework 版本
  • 两个应用程序都可以生成 .NET Core 和 .NET Framework VS 项目

 

添加您自己的图片:项目中未包含示例图片。您必须将 UI 所需的任何图片复制到“Images”子文件夹中。例如“BuilderHMI.Lite\bin\Debug\Images”。

控制方式

BuilderHMI.Lite 应用程序包含了大多数常见的 WPF 控件类型。支持的每种控件类型都实现为一个派生自“Hmi”的类,该类包含额外的设计时信息,例如初始大小和可调整大小的范围。派生类还负责管理控件的属性窗格并生成其 XAML。

每个派生类都必须实现 IHmiControl 接口,MainWindow 使用该接口来管理用户添加的控件集合。

public class HmiTextBlock : TextBlock, IHmiControl
{
    public HmiTextBlock()
    {
        Text = "TEXT BLOCK";
        SetResourceReference(StyleProperty, "TextBlockStyle");
    }

    public FrameworkElement fe { get { return this; } }
    public MainWindow OwnerPage { get; set; }
    public string NamePrefix { get { return "text"; } }
    public Size InitialSize { get { return new Size(double.NaN, double.NaN); } }
    public ECtrlFlags Flags { get { return ECtrlFlags.None; } }

    private static HmiTextBlockProperties properties = new HmiTextBlockProperties();
    public UserControl PropertyPage
        { get { properties.TheControl = this; return properties; } }

    public string ToXaml(int indentLevel, bool vs = false)
    {
        var sb = new StringBuilder();
        for (int i = 0; i < indentLevel; i++) sb.Append("    ");
        sb.Append(vs ? "<TextBlock Style=\"{DynamicResource TextBlockStyle}\"" : 
            "<HmiTextBlock");
        sb.AppendFormat(" Name=\"{0}\"", Name);
        if (!string.IsNullOrEmpty(Text)) sb.AppendFormat(" Text=\"{0}\"", 
            WebUtility.HtmlEncode(Text).Replace("\n", "&#10;"));
        OwnerPage.AppendLocationXaml(this, sb);
        sb.Append(" />");
        return sb.ToString();
    }
}

XAML 生成

每个“Hmi”派生类中的 ToXaml() 方法必须能够为派生类(用于剪切/复制/粘贴)以及基类(用于 VS 项目生成)生成 XAML。如果您在 BuilderHMI.Lite 设计表面上复制一个按钮,然后将其粘贴到文本编辑器中,您将看到类似以下的 XAML

<HmiButton Name="button1" Text="DELETE" ImageFile="delete.png"
 HorizontalAlignment="Left" VerticalAlignment="Top" Margin="192,344,0,0"
 Width="92" Height="72" />

但是,如果您生成一个 Visual Studio 项目并打开它,您将看到类似以下的 XAML

<Button Name="button1" Style="{DynamicResource ButtonStyle}"
 HorizontalAlignment="Left" VerticalAlignment="Top" Margin="192,344,0,0"
 Width="92" Height="72">
    <StackPanel>
        <Image Source="Images/delete.png" Stretch="None" />
        <TextBlock Text="DELETE" />
    </StackPanel>
</Button>

只有“Hmi”派生类可以粘贴到 BuilderHMI.Lite 设计表面。但是,标准的 WPF 控件类用于 Visual Studio 项目生成。

设计器工具窗口

设计器工具窗口非常直接:一个带有可用控件列表的“添加”选项卡,一个托管所选控件属性窗格的“编辑”选项卡,以及一个用于 Visual Studio 项目生成的“导出”选项卡。此窗口与 MainWindow 紧密耦合,主要在按钮被点击时调用 MainWindow 方法。

设计表面

设计表面由 MainWindow 类的代码隐藏实现

  • 添加新控件并生成唯一的初始名称
  • 控件选择、左键拖动以移动、右键拖动以调整大小和对齐方式更改
  • 热键功能剪切/复制/粘贴、删除、置顶、置底和箭头键微调
  • XAML 生成和 Visual Studio 项目生成

左键拖动以移动,右键拖动以调整大小

我选择左键拖动移动、右键拖动调整大小的方法,而不是使用抓手,因为我希望围绕所选控件的屏幕混乱度降至最低。Marker 类提供了包围所选控件的框以及移动时的对齐标记。Location0 类负责相对于初始控件和鼠标光标位置移动或调整控件大小。

对齐

WPF 使用 Horizontal 和 Vertical Alignment、Margin、Width 和 Height 属性将控件定位在 Grid 单元格内。BuilderHMI.Lite 应用程序管理 MarginWidthHeight,以无缝实现控件在设计表面上移动或调整大小,而不管其对齐选项的值如何。控件的水平或垂直位置始终可以用两个值来描述。但是,对于每个对齐选项,这些值是不同的。

样式

支持的控件类型的样式位于“Styles.xaml”,文件顶部有一个 Colors 部分。

<Style x:Key="TextBoxStyle" TargetType="TextBox">
    <Setter Property="Foreground" Value="{DynamicResource TextBrush}"/>
    <Setter Property="Background" Value="{DynamicResource TextBoxBackgroundBrush}"/>
    <Setter Property="BorderBrush" Value="{DynamicResource TextBrush}" />
    <Setter Property="MinWidth" Value="35" />
    <Setter Property="Padding" Value="2"/>
</Style>

所有资源引用都是动态的,这使得应用程序能够升级以支持实时皮肤更改。

public HmiTextBox()
{
    SetResourceReference(StyleProperty, "TextBoxStyle");
}

Visual Studio 项目生成

当你第一次考虑编写一个能够生成完全可构建的 Visual Studio WPF/C# 项目的应用程序时,这似乎是一项艰巨的任务。令人高兴的消息是,它非常简单。首先,使用 VS 创建一个代表性项目,然后将该项目的各种源文件添加到你的应用程序项目下的 Template 文件夹中。关键是这些源文件的构建操作设置为复制到输出目录设置为如果较新则复制

.NET Framework 和 .NET Core 项目之间只有很小的差异。每种项目类型的模板文件都包含在单独的Template 文件夹中。

用“__PROJECT_NAME__”之类的标签替换实际的项目名称、项目命名空间等。现在,你的 VS 项目生成器只需在执行一些文本替换的同时将这些模板文件复制到新项目文件夹即可。

// Generate AssemblyInfo.cs from the template:
string path = Path.Combine(templateFolder, "AssemblyInfo.cs");
string text = File.ReadAllText(path).Replace("__PROJECT_NAME__", projectName);
path = Path.Combine(projectFolder, "Properties");
Directory.CreateDirectory(path);
path = Path.Combine(path, "AssemblyInfo.cs");
File.WriteAllText(path, text);

当然,对于 BuilderHMI.Lite 来说,关键步骤是生成“MainWindow.xaml”。用户添加的每个控件都必须以 XAML 格式并按 Z 顺序写出。

// Generate xaml for all controls in Z-order:
var sortedChildren = new SortedList<int, IHmiControl>(gridCanvas.Children.Count);
foreach (object child in gridCanvas.Children)
{
    if (child is IHmiControl control)
        sortedChildren[Panel.GetZIndex(control.fe)] = control;
}
var sb = new StringBuilder();
foreach (IHmiControl child in sortedChildren.Values)
    sb.AppendLine(child.ToXaml(2, true));

关注点

从 WPF 开发者的角度来看,我认为这些是项目中 J最有趣方面

  • 在 Grid 单元格中直观地通过鼠标拖放布局 WPF 控件
  • 能够独立于位置更改控件的对齐属性
  • XAML 生成,同时支持复制粘贴操作和 VS 项目生成
  • 通过模板文件实现出乎意料简单的 Visual Studio 项目生成

Grid 与 Canvas:我最初是以最自然的方式开始开发拖放布局——使用 WPF Canvas。毕竟它就是为此而生的,对吧?然而,当我深入研究实现超出 Left-Top 的对齐方式时,我意识到我正在复制 WPF Grid 中已经存在的优雅对齐系统!然后我回到了绘图板(字面意义上的),并梳理了对齐、边距和控件维度之间的关系,以便将对齐与位置解耦。这项工作的成果就是你现在看到的!

.NET Core:微软在 .NET Core 和 .NET Framework 的兼容性方面做得非常出色。将此应用程序移植到 .NET Core 几乎是一个小插曲。我只需创建一个新的 .NET Core WPF 项目,复制源文件,然后构建并运行。无需更改源代码。如果这就是 .NET 的未来,那么我报名!

结论

让我们设想一下,你的企业需要定期创建核心 WPF 应用程序的定制版本。我所在领域的例子是工业机械制造商,每台机器都可以订购不同的选项,例如切割头、传感器或运动轴的数量。

在这种情况下,该项目将非常有用。它可以轻松修改以生成你企业应用程序的核心源代码,并且可以在 UI 设计框架中添加额外的控件类型。

  • 这样就可以更快、更可靠地生成核心应用程序的定制版本。
  • UI 屏幕可以由没有 WPF/C# 经验的人员来设计。

完整版的 BuilderHMI 通过支持以前保存的控件和整个 UI 页面的库进行重用,进一步扩展了这个想法。

历史

  • 版本 1,发布于 2020 年 11 月 1 日
  • 版本 2,发布于 2020 年 11 月 12 日
    • .NET Core 版应用程序和 .NET Core 项目生成
  • 版本 3,发布于 2020 年 11 月 18 日
    • 支持其他控件
    • 澄清说明
© . All rights reserved.