提问人:Headshot 提问时间:11/3/2023 更新时间:11/4/2023 访问量:69
如何在WinForm中获取子控件的内容?
How to get content of sub-controls in WinForm?
问:
我有WinForm,它有很多控件(tabcontrol,tabpage,datagridview,...等)。我想在datagridview中获取数据。设计的结构是这样的(TabControl 将有许多 TabPages,每个 TabPage 将有一个 TabControl,每个 TabControl 将有许多 TabPages,每个 TabPage 将有一个 DataGridView)。
TabControlX
+TabPage
++TabControl
+++TabPage
++++DataGridView
+++TabPage
++++DataGridView
+TabPage
++TabControl
+++TabPage
++++DataGridView
+++TabPage
++++DataGridView
因此,我想获取每个 DataGridView 的数据。我不确定这些东西是正确的还是坏的。
foreach (TabPage tbp in tabControl_X.TabPages)
{
foreach (Control item in tbp.Controls)
{
foreach (TabPage sub_tab in item.Controls)
{
foreach (Control dgv in sub_tab.Controls)
{
//how to get data dgv?
}
}
}
}
答:
如果要获取 dgv 控件,它必须是:
- 在您需要的点,在代码中可访问
- 随心所欲地命名
因此,如果通过 TabControlX 控件的设计器添加了 dgv,则应该能够通过其名称访问它们。
如果要从 TabControlX 控件外部访问它们,则必须将 dgv 的内存标记为 或 。internal
public
除了设计器中的“属性”选项卡外,还可以尝试查看代码文件;在那里,您应该能够找到控件的变量。.Designer.cs
评论
要迭代 的 控制层次结构,请制作一个类似于以下内容的迭代器方法:Form
public partial class MainForm : Form
{
IEnumerable<Control> IterateControls(Control.ControlCollection controls)
{
foreach (Control control in controls)
{
yield return control;
foreach (Control child in IterateControls(control.Controls))
{
yield return child;
}
}
}
}
首先,通过列出所有控件来演示迭代器:
// Iterate all names
Debug.WriteLine("ALL CONTROLS");
foreach (var control in IterateControls(Controls))
{
Debug.WriteLine(
string.IsNullOrWhiteSpace(control.Name) ?
$"Unnamed {control.GetType().Name}" :
control.Name);
}
附加扩展按深度缩进输出,请参阅存储库。
您的问题是如何仅获取控件,因此请指定DataGridView
OfType()
// Iterate DataGridView only
Debug.WriteLine("\nDATA GRID VIEW CONTROLS");
foreach (var control in IterateControls(Controls).OfType<DataGridView>())
{
Debug.WriteLine(control.Name);
}
评论
另一种方法,使用反射。
此方法采用一个通用 T,该 T 受限于类。
设置为要查找的控件类型,并传递作为共同祖先的控件(可能是您的 )。
你可以把它变成一个扩展方法。Control
T
tabControl_X
例如:
var childControls = GetAllChildControlsOfType<DataGridView>(tabControl_X);
如果传递 Form 实例 (),则会获得将 Form 作为上级的所有子 Type 控件,依此类推。this
DataGridView
专为 .NET 6+ 构建,启用可为 null。
如果面向 .NET Framework,请删除所有?
!
using System.Reflection;
private ReadOnlyCollection<T> GetAllChildControlsOfType<T>(Control parent) where T : Control {
var flags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField;
var ctlList = new List<T>();
var form = parent is Form ? parent : parent.FindForm();
var childControls = form!.GetType().GetFields(flags).Select(fi => fi.GetValue(form))
.Where(obj => obj?.GetType() == typeof(T))
.Select(obj => obj as T);
foreach (T? ctl in childControls) {
if (HasAncestor(ctl, parent)) {
ctlList.Add(ctl!);
}
}
bool HasAncestor(Control? ctl, Control? parent) {
if (ctl is null || parent is null) return false;
while (ctl.Parent != null) {
if (ctl.Parent == parent) return true;
ctl = ctl.Parent;
}
return false;
}
return new ReadOnlyCollection<T>(ctlList);
}
评论