自定义窗口
用 XAML 画出 WPF 窗口,并做简单的数据绑定和事件。此功能仍是预览,可能有 bug 或改动。只要填表,用 多字段表单。只要常驻按钮,用 自定义操作窗。要嵌网页,用 WebView2浏览器窗口。
需要基本的 WPF 知识。界面较复杂时,建议先在 Visual Studio 里调通再迁到 Quicker。
当前模块定义
sys:customwindow输入 13 · 输出 5 · 枚举 4
输入参数
- 操作类型
typeEnum必填4 个选项显示窗口并等待关闭、显示窗口、关闭窗口
显示窗口并等待关闭默认ShowAndWaitClose显示窗口Show关闭窗口Close获取窗口列表GetWindows - 窗口XAML代码
windowMarkupText必填窗口定义XAML代码
查看默认值
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:hc="https://handyorg.github.io/handycontrol" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:qk="https://getquicker.net" Width="637" Height="556" Title="Test Window" mc:Ignorable="d"> <Grid Margin="10"> <StackPanel> <TextBlock Margin="10,50,10,50" Text="Hello World!" FontSize="20" /> <Button Margin="10" qk:Att.Action="close:result" Style="{StaticResource ButtonPrimary}" Width="50"> 关闭 </Button> </StackPanel> </Grid> </Window> - 数据映射
dataMappingText必填将变量与窗口上下文数据进行映射。每行一个,格式为:"窗口数据项名称:{动作变量名}" 或 "窗口数据项:=表达式"
- 事件
eventsText必填详细说明请参考模块文档
- 辅助C#代码
cscodeText可选辅助处理窗口事件的代码,详见文档。
- 辅助C#引用DLL库
csReferenceText可选辅助 C# 代码要引用的 DLL 文件,每行一个。也可以在代码中使用 #r 指令。
- 窗口标识
windowIdText必填如需单独的步骤关闭窗口,需使用标识查找窗口。
- 自动关闭时间(S)
autoCloseTimeNumber必填自动关闭窗口的时间(秒数)。需大于0.5秒。
- 窗口位置
winLocationEnum可选在哪里显示选择窗口
15 个选项跟随鼠标(指针周围)、跟随鼠标(指针右下)、屏幕中间
跟随鼠标(指针周围)WithMouse1跟随鼠标(指针右下)WithMouse2屏幕中间默认CenterScreen屏幕左上TopLeft屏幕中上TopCenter屏幕右上TopRight屏幕左中LeftCenter屏幕右中RightCenter屏幕左下BottomLeft屏幕中下BottomCenter屏幕右下BottomRight全屏FullScreen最大化Maximized自定义位置Manual系统默认Auto - 窗口尺寸/位置
winSizeText可选设置选择窗口的最大尺寸,格式为:宽度,高度。支持像素数值或屏幕宽高百分比,详情请参考模块文档。 "窗口位置" 类型为 "自定义位置" 时用于指定显示位置,格式为:left,top,right,bottom
- 激活模式
activateModeEnum可选4 个选项支持激活,打开时抢占焦点、不支持激活(不占用焦点,仅能使用鼠标操作)、不支持激活,鼠标穿透
支持激活,打开时抢占焦点默认AutoActivate不支持激活(不占用焦点,仅能使用鼠标操作)NotActivatable不支持激活,鼠标穿透NotActivatableMouseThrough支持激活,打开时不抢占焦点NotActivated - 失去焦点后关闭窗口
closeWhenDeactivateText可选仅在窗口支持激活(获取焦点)的情况下有效。
是true否默认false在未置顶时closeIfNotTopmost - 失败后停止
stopIfFailBoolean可选失败后是否停止动作
输出参数
- 是否成功
isSuccessBoolean操作是否成功
- 窗口结果
resultText通过close:result返回的结果
- 窗口对象列表
windowListObjectIList<Window>对象
- 窗口句柄
windowHandleInteger - 关闭时窗口位置
windowLocationText
概述
换 操作类型 后显示对应参数。显示类操作要提供 XAML、数据映射和事件。
自定义窗口
参数说明
操作类型:
- 显示窗口并等待关闭:关掉窗口后再跑后面的步骤。默认。
- 显示窗口:弹出后立刻继续。
- 关闭窗口:按 窗口标识 关掉已打开的自定义窗口。
- 获取窗口列表:取出当前自定义窗口对象列表。
窗口XAML代码:仅显示两类操作。示例:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:qk="https://getquicker.net"
Width="637"
Height="556"
Title="CalcWindow"
mc:Ignorable="d">
<Grid Margin="10">
<StackPanel>
<TextBox Margin="10" Text="{Binding [number1]}" />
<TextBox Margin="10" Text="{Binding [number2]}" />
<WrapPanel Orientation="Horizontal">
<Button Name="BtnAdd" Margin="10">
加(子程序)
</Button>
<Button Margin="10" qk:Att.Action="operation=sp&spname=Multiply">
乘(声明式调用子程序)
</Button>
<Button Margin="10" qk:Att.Action="compute=true">
减(自动计算表达式)
</Button>
<Button Name="btnCompute"
Margin="10"
HorizontalAlignment="Center">
直角三角形斜边长(C#代码)
</Button>
<Button Name="btnCallSp"
Margin="10"
HorizontalAlignment="Center">
c#调用子程序
</Button>
</WrapPanel>
<TextBlock Text="Total:" />
<TextBlock Margin="10"
FontSize="40"
Foreground="Red"
Text="{Binding [total]}" />
<Button Margin="10" qk:Att.Action="close:result" Style="{StaticResource ButtonPrimary}" Width="50">
关闭
</Button>
<qk:OperationButtonList ButtonMargin="10"
OperationListStr="{Binding [buttons]}" />
</StackPanel>
</Grid>
</Window>
注意:
- 去掉
x:Class。 - XAML 里不能指定事件处理方法。
- 注册命名空间
xmlns:qk="https://getquicker.net"。
数据映射:把动作变量引进窗口。窗口数据存在一个词典里。
情况 1:关联动作变量,格式 窗口数据:{动作变量}。打开时从变量读入,关掉时写回。
情况 2:初始化一个内部数据项。
情况 3:用表达式动态计算内部数据项。
# 情况1:关联动作变量
# 格式:窗口数据:{动作变量}
# 窗口建立时,从动作变量取值放入窗口数据。窗口结束时,将窗口数据中的内容写回动作变量
number:{number}
buttons:{buttons}
# 情况2:初始化一个内部数据项
number1:=(int)0
number2:=(int)0
# 情况3:动态计算一个内部数据项
total:$= Convert.ToInt32(number1) + Convert.ToInt32(number2)
注意:
- 绑到文本框后,用户一改,该项往往会变成文本类型。
- 事先定好数据项名称,后期改名很麻烦。
窗口标识:内部 ID。单独一步「关闭窗口」时靠它查找。标识可以重复(相当于分组),新建同标识窗口时旧窗口不会自动关。需要时先用「关闭窗口」关掉旧的。
辅助C#代码:可选。回调参数:
win:当前窗口dataContext:窗口数据词典controlName:被点按钮的 NamecontrolTag:被点按钮的 Tag
using System.Text;
using System.Windows;
using System.Windows.Forms;
using System.Collections.Generic;
using MessageBox = System.Windows.Forms.MessageBox;
using Quicker.Public;
public static void OnWindowCreated(Window win, IDictionary<string, object> dataContext,
ICustomWindowContext winContext
){
dataContext["number1"] = 0;
dataContext["number2"] = 0;
}
public static void OnWindowLoaded(Window win, IDictionary<string, object> dataContext,
ICustomWindowContext winContext){
}
public static bool OnButtonClicked(string controlName, object controlTag, Window win, IDictionary<string, object> dataContext,
ICustomWindowContext winContext){
if (controlName == "btnCompute"){
dataContext["total"] =
Math.Sqrt(
Convert.ToDouble(dataContext["number1"])*Convert.ToDouble(dataContext["number1"])
+ Convert.ToDouble(dataContext["number2"])*Convert.ToDouble(dataContext["number2"])
);
return true;
}else if (controlName == "btnCallSp"){
var result = winContext.RunSp("Add", new Dictionary<string,object>{{"number1", dataContext["number1"]}, {"number2",dataContext["number2"]}});
dataContext["total"] = result["total"];
return true;
}
return false;
}
辅助C#引用DLL库:辅助代码要引用的 DLL,每行一个。也可以在代码里用 #r。
事件:给按钮或数据项挂操作。格式:
按钮名称.click:操作内容
菜单项名称.click:操作内容
窗口数据项.change:操作内容
操作内容见 按钮点击的操作内容代码。数据项变化可能连着触发,不要在里面做重活,也要避免循环改数据。
自定义窗口
自动关闭时间(S):多少秒后自动关。0 不自动关。需大于 0.5 秒才生效。适合纯提示窗。
激活模式:
- 支持激活,打开时抢占焦点:显示后立刻抢焦点。默认。
- 支持激活,打开时不抢占焦点:显示时不抢,点到窗口后可以输入。
- 不支持激活(不占用焦点,仅能使用鼠标操作):不占焦点。要往别的软件发按键、取选中文本时常用。这种窗口不能在输入框里打字。
- 不支持激活,鼠标穿透:不占焦点,鼠标点穿到后面。
不支持激活的窗口若抢了 Quicker 自己的焦点,可给要点的控件加 Focusable="False"。
窗口位置:跟随鼠标、屏幕各方位、全屏、最大化、自定义位置、系统默认。默认屏幕中间。
窗口尺寸/位置:与 窗口位置 配合。自定义位置时写坐标;其它情况写尺寸。可用百分比或像素,写法与 自定义操作窗 相同。
失去焦点后关闭窗口:仅窗口支持激活时有效。可选是、否,或「在未置顶时」。
失败后停止:失败是否中止。默认开启。
按钮事件
注册按钮事件
- 在 事件 里写
按钮名称.click:操作内容代码。按钮必须有 Name。 - 在 辅助C#代码 里写
OnButtonClicked,用controlName/controlTag区分控件。 - 在
OnWindowCreated或OnWindowLoaded里找到控件再挂事件:
public static void OnWindowLoaded(Window win, IDictionary<string, object> dataContext,
ICustomWindowContext winContext){
var btnOk = (Button)win.FindName("BtnOK");
btnOk.Click += (sender, args) => {
// Handle the click.
};
}
- 在 XAML 里加附加属性
qk:Att.Action="操作内容代码":
<Button Margin="10" qk:Att.Action="close:ok">
关闭
</Button>
XAML 属性值里的特殊字符要转义(尤其是 &):
| 特殊字符 | 字符实体 |
|---|---|
小于号 (<) | < |
大于号 (>) | > |
| & 符号 | & |
引号 (") | " |
按钮点击的操作内容代码
上面第 1、4 种写法可直接声明操作。
关闭窗口
close::关掉,窗口结果 为空。close:result:关掉并把result写到 窗口结果(换成你要返回的值)。
其它操作
用查询字符串,格式接近推送服务 / 连续搜索:
operation=操作类型&data=URL编码后的内容&action=动作名称或id&close=是否关闭窗口&compute=是否更新计算字段&spname=子程序名
各参数均可选。
- operation:
copy:把 data 写入剪贴板paste:把 data 粘贴到目标窗口(当前自定义窗口不能占焦点)action:跑动作,用 action 指定 ID 或名称open:打开 data 里的路径或网址sendkeys:按模拟按键 B 语法把 data 打到目标窗口(窗口不能占焦点)。1.27.3 前曾用input,请改用sendkeysinputtext:模拟键入 data 文本(窗口不能占焦点)sp:跑子程序,用 spname 指定名称。输入从窗口数据取(见 数据映射),输出按参数名写回窗口数据
- data:URL 编码后的待处理数据
- action:operation 为
action时的动作 ID 或名称 - close:
true/false,点完是否关窗 - compute:
true/false,点完是否重算 数据映射 里的表达式
数据绑定
窗口的 DataContext 就是保存窗口数据的词典。控件属性可写成:
<TextBox Margin="10" Text="{Binding [number1]}" />
如何运行子程序
声明式调用
方式 1:按钮附加属性
<Button Margin="10" qk:Att.Action="operation=sp&spname=Multiply&param1=value1">
乘(声明式调用子程序)
</Button>
operation=sp:点完跑子程序&:XAML 里的&spname=Multiply:子程序名param1=value1:给子程序输入param1
qk:Att.Action 调子程序时,还会传入 __sender、__e、__control,对应 click 的 sender、事件参数和 OriginSource。
方式 2:在事件里写
BtnAdd.click:operation=sp&spname=Add 表示点名为 BtnAdd 的按钮时跑 Add。
声明式调用时,子程序输入直接取自窗口数据,输出直接写回同名窗口数据。

上图里:窗口有 number1、number2、total;子程序 Add 对前两个求和写到 total;调用时 Quicker 从窗口取输入、把输出写回。
在 C# 里调用
在 辅助C#代码 的 OnButtonClicked 里按按钮名分支,再用 winContext.RunSp。

子程序会显示界面时,改用 RunSpAsync(string spName, object inputParams) 或 RunSpAsync(string spName, IDictionary<string, object> inputParams),避免死锁。
- 第一个参数:子程序名称
- 第二个参数:词典。Key 是子程序参数名,Value 是要传入的值(不必对应某个窗口数据)。1.24.28+ 也可用匿名对象。
- 返回值是词典。
输出
- 是否成功:操作是否成功。
- 窗口结果:仅「显示窗口并等待关闭」「关闭窗口」。由
close:result带回。 - 窗口对象列表:仅「获取窗口列表」,类型为
IList<Window>。 - 窗口句柄:仅「显示窗口」。
- 关闭时窗口位置:仅「显示窗口并等待关闭」。
限制与排障
- 预览功能,接口可能变。
- 不占焦点的窗口不能在输入框里打字;要往其它软件发按键时,不要用「打开时抢占焦点」。
- 数据项
.change可能连着触发,避免循环更新。 - 同标识旧窗口不会自动关,先关再开。
- 子程序要出界面时用
RunSpAsync,同步RunSp可能死锁。
示例
相关链接
更新历史
- 20240909 修改错别字。
更新于