Files
KJD/TEMUKJD/Extension/BindingExtensions.cs

150 lines
5.4 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TemuKJD.Extension;
public class DataContext<TSource> : BindingSource
{
public DataContext() { }
public DataContext(TSource dataSource) : base(dataSource, null) { }
// 强类型的 DataSource,避免调用方还要自己转型
public new TSource DataSource
{
get => (TSource)base.DataSource;
set => base.DataSource = value;
}
}
public static class BindingExtensions
{
/// <summary>
/// TSource 必须显式指定(因为无法从参数推断),TControl 自动从调用方控件推断
/// </summary>
public static Binding Bind<TSource, TControl>(
this TControl ctrl,
DataContext<TSource> dataSource,
Expression<Func<TControl, object>> controlPropertyExpr,
Expression<Func<TSource, object>> dataPropertyExpr,
DataSourceUpdateMode mode = DataSourceUpdateMode.OnPropertyChanged,
string format = null,
ConvertEventHandler parseHandler = null)
where TControl : Control
=> BindCore(ctrl, controlPropertyExpr.GetPropertyName(), dataSource, dataPropertyExpr, mode, format, parseHandler);
public static Binding Bind<TControl>(
this TControl ctrl,
BindingSource dataSource,
Expression<Func<TControl, object>> controlPropertyExpr,
string dataPropertyName,
DataSourceUpdateMode mode = DataSourceUpdateMode.OnPropertyChanged,
string format = null,
ConvertEventHandler parseHandler = null) where TControl : Control
=> BindCore(ctrl, controlPropertyExpr.GetPropertyName(), dataSource, dataPropertyName, mode, format, parseHandler);
// ---------- 共享的核心实现,不对外暴露 ----------
private static Binding BindCore<TSource>(
Control ctrl,
string controlPropertyName,
BindingSource bs,
Expression<Func<TSource, object>> dataPropertyExpr,
DataSourceUpdateMode mode,
string format,
ConvertEventHandler parseHandler) => BindCore(ctrl, controlPropertyName, bs, dataPropertyExpr.GetPropertyName(), mode, format, parseHandler);
private static Binding BindCore(
Control ctrl,
string controlPropertyName,
BindingSource bs,
string dataPropertyName,
DataSourceUpdateMode mode,
string format,
ConvertEventHandler parseHandler)
{
var binding = new Binding(controlPropertyName, bs, dataPropertyName, true, mode);
if (!string.IsNullOrEmpty(format))
binding.Format += (s, e) => e.Value = string.Format($"{{0:{format}}}", e.Value);
if (parseHandler != null)
binding.Parse += parseHandler;
ctrl.DataBindings.Add(binding);
return binding;
}
// ---------- TextBox ----------
public static Binding Bind<TSource>(
this TextBox ctrl,
BindingSource bs,
Expression<Func<TextBox, object>> controlPropertyExpr,
Expression<Func<TSource, object>> dataPropertyExpr,
DataSourceUpdateMode mode = DataSourceUpdateMode.OnPropertyChanged,
string format = null,
ConvertEventHandler parseHandler = null)
=> BindCore(ctrl, controlPropertyExpr.GetPropertyName(), bs, dataPropertyExpr, mode, format, parseHandler);
// ---------- CheckBox ----------
public static Binding Bind<TSource>(
this CheckBox ctrl,
BindingSource bs,
Expression<Func<CheckBox, object>> controlPropertyExpr,
Expression<Func<TSource, object>> dataPropertyExpr,
DataSourceUpdateMode mode = DataSourceUpdateMode.OnPropertyChanged,
string format = null,
ConvertEventHandler parseHandler = null)
=> BindCore(ctrl, controlPropertyExpr.GetPropertyName(), bs, dataPropertyExpr, mode, format, parseHandler);
// ---------- DateTimePicker ----------
public static Binding Bind<TSource>(
this DateTimePicker ctrl,
BindingSource bs,
Expression<Func<DateTimePicker, object>> controlPropertyExpr,
Expression<Func<TSource, object>> dataPropertyExpr,
DataSourceUpdateMode mode = DataSourceUpdateMode.OnPropertyChanged,
string format = null,
ConvertEventHandler parseHandler = null)
=> BindCore(ctrl, controlPropertyExpr.GetPropertyName(), bs, dataPropertyExpr, mode, format, parseHandler);
// ---------- ComboBox ----------
public static Binding Bind<TSource>(
this ComboBox ctrl,
BindingSource bs,
Expression<Func<ComboBox, object>> controlPropertyExpr,
Expression<Func<TSource, object>> dataPropertyExpr,
DataSourceUpdateMode mode = DataSourceUpdateMode.OnPropertyChanged,
string format = null,
ConvertEventHandler parseHandler = null)
=> BindCore(ctrl, controlPropertyExpr.GetPropertyName(), bs, dataPropertyExpr, mode, format, parseHandler);
// ---------- NumericUpDown ----------
public static Binding Bind<TSource>(
this NumericUpDown ctrl,
BindingSource bs,
Expression<Func<NumericUpDown, object>> controlPropertyExpr,
Expression<Func<TSource, object>> dataPropertyExpr,
DataSourceUpdateMode mode = DataSourceUpdateMode.OnPropertyChanged,
string format = null,
ConvertEventHandler parseHandler = null)
=> BindCore(ctrl, controlPropertyExpr.GetPropertyName(), bs, dataPropertyExpr, mode, format, parseHandler);
public static string GetPropertyName<TSource, TProperty>(
this Expression<Func<TSource, TProperty>> propertyExpr)
{
if (propertyExpr.Body is MemberExpression member)
return member.Member.Name;
// 处理值类型属性被隐式转换为 object 的情况(如 decimal -> object)
if (propertyExpr.Body is UnaryExpression unary &&
unary.Operand is MemberExpression unaryMember)
return unaryMember.Member.Name;
throw new ArgumentException("表达式必须是形如 x => x.PropertyName 的属性访问", nameof(propertyExpr));
}
}