一文读懂函数式组合编程:从 XchyUI 实战源码,看透现代 UI 开发新范式
在桌面端开发中,WPF 凭借强大的自定义能力占据主流,但繁琐的 XAML、复杂的数据绑定、高昂的学习成本也让开发者备受困扰。近年来,函数式组合编程凭借简洁、高效、统一的优势,成为 Jetpack Compose、SwiftUI、Flutter 等新一代 UI 框架的核心思想,也成为 C# 桌面开发的革新方向。
本文将从概念、优势、源码实战、统一 API四个维度,结合 XchyUI 的 Switch 开关 和 IconButton 图标按钮 真实源码,带你彻底理解:函数式组合编程到底是什么、强在哪里。
一、什么是函数式组合编程?
函数式组合编程,是一种以函数为基础单元、以组合为核心思想、以状态驱动 UI的声明式开发范式。
简单来说:
- 一个函数 = 一个 UI 组件
- 复杂界面 = 多个函数嵌套组合
- UI 不再手动创建,而是状态自动渲染
- 全程纯代码描述 “界面长什么样”,而非命令式操作控件
它的核心特征:纯代码构建 + 函数嵌套 + 链式调用 + 状态驱动 + 无副作用
二、函数式组合编程的 5 大核心优势
1. 纯 C# 一体化开发,告别 XAML 与逻辑割裂
传统 WPF 必须使用 XAML 布局 + C# 逻辑 双语言模式,而函数式 UI:布局、样式、动画、交互全部使用 C# 实现结构更内聚,维护更简单。
2. 积木式组件组合,复用成本极低
所有界面都由原子函数(Box、Row、Column、Icon、Text等等)拼接而成,小函数拼大组件,一次封装,随处使用。
3. 状态驱动自动刷新,告别繁琐绑定
状态改变 → UI 自动刷新无需实现 INotifyPropertyChanged、无需依赖属性、无需处理绑定失效。
4. 大一统链式 API,所有组件样式写法完全统一
任何 UI 元素:容器、按钮、图标、文字等等都可以用同一套 API 设置:背景、边框、圆角、阴影、大小、边距、点击事件等。
三、XchyUI 核心能力:所有组件通用链式 API
在 XchyUI 中,所有 UI 组件都基于 XViewBuilder 构建,因此:
任何组件都能链式调用以下样式:
csharp
运行
.Background() // 背景色
.Border() // 边框
.Radius() // 圆角
.Shadow() // 阴影
.Size() // 宽高
.Padding() // 内边距
.Margin() // 外边距
.Alpha() // 透明度
.Click() // 点击事件
... 还有很多常用的方法
一套 API,全框架通用这是传统 WPF 无法比拟的统一体验。
四、实战源码解析 1:Switch 开关组件(函数式典范)
我们直接看源码,逐点理解函数式组合如何实现开关。
Switch 功能
- 带动画滑动效果
- 状态选中 / 未选中
- 支持禁用状态
- 统一样式:背景、圆角、阴影、边框
Switch 完整源码
public static XViewBuilder Switch(bool isSelected, XFunction<bool>? onSelected = null, bool disable = false)
{
// 1. 响应式状态:选中状态
var selectedState = StateValueOf(isSelected);
// 2. 动画状态
var visibleState = StateValueOf(false);
// 动画值
var animiateValue = AnimateFloatOf(visibleState);
var dist = 32; // 滑动的距离
// 3. 函数嵌套构建UI:Box外壳 + Space圆形滑块
return Box(() =>
{
Space(30)
.Circle() // 绘制圆形
// 4. 动画绑定:滑块自动滑动
.Binding(animiateValue, (builder, value) =>
{
// 计算元素的margin
var marginX = selectedState.Value ? (float)dist : 0f;
if (visibleState.Value)
{
marginX = selectedState.Value ? value * dist : (1 - value) * dist;
}
builder.Margin(left: (int)marginX);
}, needLayout: true) // 改变子元素布局参数需要触发布局
// 5. 状态绑定:滑块颜色自动更新
.Binding(selectedState, (builder, isSelected) =>
{
builder.Background(xTheme.Light.BlankFill);
})
.Shadow(xTheme.Shadows.MinCard); // 阴影(链式API)
})
.ContentAlignment(XAlignment.LeftCenter)
// 6. 状态绑定:开关背景色自动切换
.Binding(selectedState, (builder, isSelected)
=> builder.Background(isSelected ? xTheme.Colors.Primary : xTheme.Colors.BaseBorder))
.Radius(33) // 圆角(链式API)
.Size(66, 33) // 大小(链式API)
.Padding(horizontal:2)
.EnableEvent(!disable) // 是否禁用
.Alpha(disable ? xTheme.Colors.DisabledAlpha : 1) // 禁用下设置透明度,也可以封装成一个Disable()扩展方法里面调用EnableEvent和Alpha就行
// 7. 点击交互:只改状态,UI自动刷新
.Click((builder, info) =>
{
selectedState.Value = !selectedState.Value; // 触发是否选中
onSelected?.Invoke(selectedState.Value); //选中函数透出
visibleState.Value = true; // 开始动画
});
}
Switch 函数式设计亮点
- 无 XAML、无模板、无继承,纯函数实现
- 状态驱动:修改状态自动刷新 UI
- 动画自动播放:无需手动管理
- 链式样式 API:圆角、背景、阴影统一调用
- 组件结构清晰:Box 包含 Circle,一目了然
五、实战源码解析 2:IconButton 图标按钮(业务级组件)
IconButton 是最常用的业务组件,支持:图标 + 文字、横竖布局、Loading 状态。
IconButton 完整源码
public static XViewBuilder IconButton(int resId, string text, int? iconSize = null, int? fontSize = null, XColor? tint = null, XColor? fontColor = null, bool isVerticel = false, XState<bool>? loadingState = null)
{
iconSize = iconSize ?? 20;
fontSize = fontSize ?? xTheme.Sizes.Body;
fontColor = fontColor ?? xTheme.Colors.RegularText;
tint = tint ?? fontColor;
// 1. 函数式UI结构
XFunction function = () =>
{
if (loadingState != null)
{
// 2. 绑定加载状态
Box(loadingState, loading =>
{
// 如果是加载状态显示颜色环形进度条,这个自带动画
if (loading)
{
ColorLoading(fontColor.Value, iconSize.Value, 2);
}
else
{
// 否则显示一个图标
Icon(resId).Size(iconSize.Value).Color(tint.Value);
}
});
}
else
{
Icon(resId).Size(iconSize.Value).Color(tint.Value);
}
// 3. 文字组件
Text(text)
.FontSize(fontSize.Value)
.FontColor(fontColor.Value);
};
// 4. 自动适配横向/纵向布局
var builder = isVerticel ? Column(function) : Row(function);
// 5. 统一链式样式API(所有组件通用)
return builder
.Background(xTheme.Colors.BlankFill)
.Border(xTheme.Colors.BaseBorder, 1.5f)
.Radius(xTheme.Radius.Middle)
.HorizontalAlignment(XHorizontalAlignment.Center)
.VerticalAlignment(XVerticalAlignment.Center)
.Space(10) // 子元素之间的间距
.Padding(horizontal: xTheme.Sizes.Space20 - 10, vertical: xTheme.Sizes.Space12);
}
// 加载动画组件(纯函数组合)
public static XViewBuilder ColorLoading(XColor color, int size, int borderSize)
{
return Space(size)
.Circle()
.OnDraw(builder => {
// 添加自定义绘图,直接透出SKCanvas 中间没有任何链路,直连SKCanvas绘图,你想怎么画就怎么画
var canvas = (SKCanvas)RenderImp.GetCanvas();
var paint = PaintCache.GetBackground(builder.View.Style.Background);
paint.Color = color.ToSKColor();
paint.IsStroke = true;
paint.StrokeCap = SKStrokeCap.Round;
paint.StrokeWidth = borderSize.AsPx();
var rect = builder.View.RenderRect;
var skRect = rect.ToSKRect();
// 设定渐变
paint.Shader = DrawConverter.ToShader(rect, new XBrush()
{
StartColor = color,
EndColor = color.Copy(0f),
Direction = XGradientDirection.Round
});
// 绘制扇形
canvas.DrawArc(skRect, 5, 350, false, paint);
}).CircleProgress(); // 开始圆形360度旋转动画
}
使用实例
Column(() =>
{
Switch(true);
IconButton(SvgRes.Goods, "商品");
var loadingState = StateValueOf(false);
IconButton(SvgRes.Search, "查询", loadingState: loadingState).Click(()=>
{
loadingState.Value = !loadingState.Value;
});
})
.Size(500)
.VerticalAlignment(XVerticalAlignment.Center)
.Border(XColors.Red, 1, XDashType.Dash)
.Space(10);
下面的是图
点击查询后 查询图标自动变成加载动画
IconButton 函数式亮点
- 状态自动切换 Icon/Loading,无需手动改 UI
- Row/Column 函数一键切换横竖布局
- 所有样式均使用统一链式 API
- 一个函数就是一个组件,可在任何地方调用
- 无模板、无样式重写、无控件继承
六、函数式组合 UI vs WPF 直观对比
表格
| 维度 | 函数式组合(XchyUI) | 传统 WPF |
|---|---|---|
| 开发方式 | 纯 C# 函数声明 | XAML + C# 分离 |
| 样式 API | 所有组件统一链式调用 | 各控件独立属性,学习成本高 |
| UI 刷新 | 状态改变自动刷新 | 绑定 + 通知,易失效 |
| 组件复用 | 封装函数即可 | 复杂控件模板 + 样式 |
| 代码量 | 少、简洁、直观 | 冗余代码多 |
| Bug 概率 | 低(无副作用) | 高(绑定 / 内存 / 样式) |
七、总结
函数式组合编程,是新一代 UI 开发的主流范式,它用最简洁的方式解决了传统框架的核心痛点。
通过 XchyUI 的 Switch 和 IconButton 两大组件源码可以看出:
函数式组合的核心价值:
- 函数即组件,像搭积木一样构建 UI
- 状态驱动自动刷新,告别繁琐绑定
- 所有组件统一链式 API:背景、边框、圆角、阴影完全通用
- 纯 C# 开发,无 XAML,结构更清晰
- 低代码、低耦合、低 Bug、高复用
如果你厌倦了传统框架的沉重与繁琐,渴望一套 ** 轻量、现代、高效、纯 C#** 的桌面 UI 开发方案,函数式组合编程(如 XchyUI)绝对是未来的主流方向。