多窗体:新建 / 删除窗体,项目 1 登录示例;标识符支持中文

- 新建窗体:生成与 VS 新建窗体相同的 X.cs 和 X.Designer.cs,沿用工程命名空间;
  删除窗体(启动窗体不能删)
- 标签页按窗体分组,启动窗体排在最前并默认打开
- 运行时点哪个窗口哪个到最前;消息框始终在所有窗口之上
- 示例:项目 1 任务 1 登录与增加用户,两个窗体的 Designer.cs 由设计器引擎生成;
  修正书上未声明的 change 变量、关闭后重复 Show 已释放窗体的问题
- 设计器的正则支持中文控件名、类名、命名空间
- 修正:切换窗体时属性窗口的名称没有刷新
- 测试:多窗体端到端测试;新窗体模板测试

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
xuyueandClaude Opus 5.5 committed 2026-10-22 11:23:37 +08:00
1 parent 02d2f0eabc
commit 8feda289de
19 files changed
+739 -36

No files matched your search

+4 -4
View File
@@ -236,7 +236,7 @@ export function renameControl(doc: DesignerDocument, from: string, to: string):
case 'layout':
return s.target === from ? { ...s, target: to, text: undefined } : s
case 'raw':
return s.text.includes(`this.${from}`) ? { kind: 'raw', text: s.text.replace(new RegExp(`\\bthis\\.${from}\\b`, 'g'), `this.${to}`) } : s
return s.text.includes(`this.${from}`) ? { kind: 'raw', text: s.text.replace(new RegExp(`(?<![\\p{L}\\p{N}_])this\\.${from}(?![\\p{L}\\p{N}_])`, 'gu'), `this.${to}`) } : s
}
}
next.prologue = next.prologue.map(fix)
@@ -245,7 +245,7 @@ export function renameControl(doc: DesignerDocument, from: string, to: string):
if (block.name === from) block.name = to
block.stmts = block.stmts.map(fix)
}
next.tail = next.tail.replace(new RegExp(`(private [\\w.]+ )${from};`), `$1${to};`)
next.tail = next.tail.replace(new RegExp(`(private [\\p{L}\\p{N}_.]+ )${from};`, 'u'), `$1${to};`)
return next
}
@@ -336,7 +336,7 @@ function ensureLayout(doc: DesignerDocument, target: string, op: 'SuspendLayout'
// ---------- 字段声明 ----------
const FIELD = /^([ \t]*)private ([\w.]+) (\w+);[ \t]*$/gm
const FIELD = /^([ \t]*)private ([\p{L}\p{N}_.]+) ([\p{L}\p{N}_]+);[ \t]*$/gmu
function addField(tail: string, type: string, name: string, eol: string) {
const fields = [...tail.matchAll(FIELD)]
@@ -354,7 +354,7 @@ function addField(tail: string, type: string, name: string, eol: string) {
}
function removeField(tail: string, name: string) {
return tail.replace(new RegExp(`^[ \\t]*private [\\w.]+ ${name};[ \\t]*\\r?\\n`, 'm'), '')
return tail.replace(new RegExp(`^[ \\t]*private [\\p{L}\\p{N}_.]+ ${name};[ \\t]*\\r?\\n`, 'mu'), '')
}
/** 窗体或控件的显示名:窗体用类名 */