上篇博客中讲解了代码树分为Expression和Statement两种基本结构,比如a+b是个二分法表达式,而c=a+b;是个赋值语句,一个Statement或者expression,可以由多个expression组成。
代码节点expression和statement都要重载相应的方法,以获取节点的结构
Expression必须重载 Descriptor Descriptor { get; }方法
Statement必须重载 Descriptor Descriptor { get; }和 BlockDescriptor BlockDescriptor { get; }方法
Descriptor是代码基本结构的数组,比如a+b,基本结构包括三部分,表达式a,+号和表达式b,表达式显示控件会根据结构数组进行显示,比如表达式a和b用文本框显示,+号用文本标签显示,这样就完成了表达式的显示。
BlockDescriptor表示语句除了第一行后面的结构。
比如for循环,语句定义是
for(init; test; update){
statement block
}
要包含init、test和update三个表达式,和一个内部循环语句,具体代码定义如下:
public Expression Init { get; set; }
public Expression Test { get; set; }
public Expression Update { get; set; }
public BlockStatement Body { get; set; } = new BlockStatement();
Descriptor要定义第一行的结构,显示三个表达式
public override Descriptor Descriptor
{
get
{
Descriptor desc = new Descriptor();
desc.Add(new TextItemDescriptor(this, "for", true));
desc.Add(new TextItemDescriptor(this, "("));
desc.Add(new ExpressionDescriptor(this, "Init", "number") { AcceptVariableDeclaration = true }) ;
desc.Add(new TextItemDescriptor(this, ";"));
desc.Add(new ExpressionDescriptor(this, "Test", "boolean") { IsOnlyNumberAllowed = false });
desc.Add(new TextItemDescriptor(this, ";"));
desc.Add(new ExpressionDescriptor(this, "Update", "number"));
desc.Add(new TextItemDescriptor(this, ")"));
return desc;
}
}
BlockDescriptor定义循环代码,
public override BlockDescriptor BlockDescriptor
{
get
{
BlockDescriptor blockDescript = new BlockDescriptor();
blockDescript.Add(new BlockStatementDescriptor(this, "Body"));
return blockDescript;
}
}
这样Statement显示控件,根据Descritor显示第一行,然后根据BlockDescriptor显示后边结构,这样for语句就可以显示下边图片的样子。
由于Expression和Statement显示结构式一个数组,所以可以WPF的ItemsControl来负责显示,对于每种显示基本结构,可以通过DataTemplate定义其对应的显示,
比如文本可以通过一个TextBox负责其显示
<DataTemplate DataType="{x:Type script:TextItemDescriptor}">
<TextBlock Background="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background}"
Foreground="{Binding Path=IsKeyword, Converter={StaticResource KeywordForegroundConverter}}"
FontWeight="{Binding Path=IsKeyword, Converter={StaticResource KeywordFontWeightConverter}}"
VerticalAlignment="Center" Padding="0" HorizontalAlignment="Center"
Focusable="False" Margin="0" Text="{Binding Path=Text}"/>
</DataTemplate>
而表达式中的表达显示,除了显示表达式,还能能够接受表达式,也能显示文本
<DataTemplate DataType="{x:Type script:ExpressionDescriptor}">
<local:TextBoxExpressionHolder ExpressionDescriptor="{Binding}" BkColor="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background}"/>
</DataTemplate>
因此,我们用一个控件显示表达式(ExpressionControl),一个控件显示表达式中的表达式(TextBoxExpressionHolder),一个控件显示语句(StatementControl),得益于WPF的属性结构(和代码树结构相同)和显示等特性,很容易实现表达式的显示和操作。
作为一个图形编程编辑器,除了代码的显示,更重要的编辑,为了让编码更加简单,还需要非常多的功能,比如代码折叠、代码复制粘贴、函数调用和编辑等,所以还需要其他一些辅助类型。具体可以参考githup中的源码,代码地址WPF Blocky。实现的代码的显示、编辑、序列化和解释运行
同时,为了让图形代码更加强大,我们实现了面向对象、模块化(使用自己代码作为类库)、多线程、EV3和Arduino控制、Scratch、画板等,几乎涵盖了所有代码基础知识,也增加了很多有趣的例子,比如围棋和五子棋,让代码学习能够更加直观和有趣,可以从windows 10商店中下载使用