jQuery和Css的控件选择器用起来非常畅快,相信用过的人都会有这种感觉,而WinForm则是通过Name来实现窗体中控件的选择,在选择单个控件的时候是很方便,但是当选择具有一类特征的控件时,则显得有些乏力。于是我仿照jQuery和Css来实现了一个WInForm的控件选择器,而且是用扩展方法实现,这样只需要添加一个命名空间就可以方便的使用了。下面是实现的源码及一些简单的示例代码。
/// <summary>
/// WinForm控件选择器
/// </summary>
public static class Selector
{
//内部辅助函数,用于获取指定控件内所有子控件,采用yield return可以减少代码编写量
//由于该函数是延迟加载,如果在实际使用过程中直接返回IEnumerable<Control>可能会产生一些问题
//因此在选择器的公开函数中均返回数组
//另外从常理来说,由于在选择的子控件数量应为固定的,因此没有返回List,而且数组对系统资源的消耗要小于List
static IEnumerable<Control> AllNative(this Control ctrl)
{
foreach (Control c in ctrl.Controls)
{
yield return c;
foreach (Control sub in c.AllNative())
{
yield return sub;
}
}
}
/// <summary>
/// 返回控件中所有子控件
/// </summary>
public static Control[] All(this Control ctrl)
{
return ctrl.AllNative().ToArray();
}
/// <summary>
/// 返回控件中所有符合条件的子控件
/// </summary>
/// <param name="predicate">筛选条件</param>
public static Control[] All(this Control ctrl, Func<Control, bool> predicate)
{
return ctrl.AllNative().Where(predicate).ToArray();
}
/// <summary>
/// 返回控件中所有指定类型的子控件
/// </summary>
/// <typeparam name="T">需要选择的子控件类型</typeparam>
public static T[] All<T>(this Control ctrl)
where T:Control
{
return ctrl.All().OfType<T>().ToArray();
}
/// <summary>
/// 返回控件中所有指定类型且符合条件的子控件
/// </summary>
/// <typeparam name="T">需要选择的子控件类型</typeparam>
/// <param name="predicate">筛选条件</param>
public static T[] All<T>(this Control ctrl, Func<T, bool> predicate)
where T : Control
{
return ctrl.All().OfType<T>().Where(predicate).ToArray();
}
}
在一个Form中添加若干控件,如下图所示
添加三个按钮事件做测试:
private void button1_Click(object sender, EventArgs e)
{
foreach (var b in this.All<Button>(b => b.FlatStyle == FlatStyle.Flat))
{
b.BackColor = Color.Red;
} } private void button2_Click(object sender, EventArgs e)
{
foreach (var c in this.groupBox1.All())
{
c.BackColor = Color.Blue;
} } private void button3_Click(object sender, EventArgs e)
{
foreach (var c in this.All())
{
c.Text = "haha";
}
}
下面一次是点击三个按钮之后的效果
从结果来看,代码是按照设计意图来运行的。