[英]How to find out windows form controls inside infragistics Tab Control?
[英]How to loop through all controls in a Windows Forms form or how to find if a particular control is a container control?
我會告訴我的要求。 我需要為Windows窗體表單中的每個控件都有一個keydown
事件。 如果我必須為所有keydown事件做的事情是相同的,那么最好這樣做而不是為所有控件手動執行它。
所以我基本上可以這樣做:
foreach (Control c in this.Controls)
c.KeyDown+= new KeyEventHandler(c_KeyDown);
但是在這里,foreach不會循環駐留在groupBox或tabControl中的那些控件。 我的意思是如果表單(this)包含groupBox或其他一些容器控件,那么我可以獲得該特定容器控件的keydown事件。 並且foreach
不會foreach
駐留在容器控件內的控件。
問題1:如何為表單中的“所有”控件獲取keydown事件?
如果上面的謎題得到解決,那么我的問題就結束了。
這是我可以做的事情:
foreach (Control c in this.Controls)
{
c.KeyDown += new KeyEventHandler(c_KeyDown);
if (c is Container control)
FunctionWhichGeneratesKeyDownForAllItsChildControls(c)
}
我知道如果組框內有組框,我將不得不多次通過FunctionWhichGeneratesKeyDownForAllItsChildControls(c)
來獲取所有控件的keydown。 我能做到。 我的問題是,
問題2:如何檢查c
是否為容器控件?
一個簡單的遞歸函數應該這樣做。
private void AddEvent(Control parentCtrl)
{
foreach (Control c in parentCtrl.Controls)
{
c.KeyDown += new KeyEventHandler(c_KeyDown);
AddEvent(c);
}
}
這與馬格努斯的正確答案相同,但更加充實。 請注意,這會將處理程序添加到每個控件,包括標簽和容器控件。 這些控件似乎不會引發事件,但您可能希望添加邏輯以僅將處理程序添加到接受用戶輸入的控件。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
RegisterKeyDownHandlers(this);
}
private void RegisterKeyDownHandlers(Control control)
{
foreach (Control ctl in control.Controls)
{
ctl.KeyDown += KeyDownFired;
RegisterKeyDownHandlers(ctl);
}
}
private void KeyDownFired(object sender, EventArgs e)
{
MessageBox.Show("KeyDown fired for " + sender);
}
}
以下是遍歷控件集合的一些非遞歸選項。 我的具體實現是進行界面驗證,但可以根據您的目的進行調整。
為什么甚至搞亂你說的非遞歸解決方案呢? 好吧,我在調試一天時遇到堆棧溢出錯誤,所以我看着用循環替換它(這要困難得多)。 事實證明,錯誤是一種僥幸,並且再也沒有發生過
//recursive
//This is the simplest implementation, but the most memory hungry
private IEnumerable<DataObjects.Error> CheckErrors(Control.ControlCollection controls, ErrorProvider errorProvider)
{
var errors = new List<DataObjects.Error>();
foreach (var control in controls.Cast<System.Windows.Forms.Control>())
{
//insert your own business logic in here
var error = errorProvider.GetError(control);
if (!string.IsNullOrEmpty(error))
{
errors.Add(new DataObjects.Error(error, DataObjects.ErrorLevel.Validation));
}
//recursive call
errors.AddRange(CheckErrors(control.Controls, errorProvider));
//insert your own business logic in here
}
return errors;
}
//Breadth first - Does NOT require child node to have knowledge of parent
//Read through the controls at a given level and then blindly delve
//deeper until you reach the end of the rainbow
//order(max-tree-level-size) memory usage?
//tree-level-size, as in the # of nodes at a given depth
private IEnumerable<DataObjects.Error> CheckErrors_NonRecursive_NeverLookBack(Control control, ErrorProvider errorProvider)
{
var currentControls = control.Controls.Cast<Control>();
var errors = new List<DataObjects.Error>();
while (currentControls.Count() > 0)
{
foreach (var currentControl in currentControls)
{
//insert your own business logic in here
var error = errorProvider.GetError(currentControl);
if (!string.IsNullOrEmpty(error))
{
errors.Add(new DataObjects.Error(error, DataObjects.ErrorLevel.Validation));
}
//insert your own business logic in here
}
//replace currentControls with ALL of the nodes at a given depth
currentControls = currentControls.SelectMany(x => x.Controls.Cast<Control>());
}
return errors;
}
//Depth first - Does NOT require child to have knowledge of parent
//Approximate recursion by keeping a stack of controls, instead of a call stack.
//Traverse the stack as you would have with recursion
//order(tree-branch-size) memory usage? tree-branch-size as in the number of nodes
//that it takes to get from the root to the bottom of a given branch
private IEnumerable<DataObjects.Error> CheckErrors_NonRecursive(Control.ControlCollection controls, ErrorProvider errorProvider)
{
var controlStack = new Stack<Control.ControlCollection>();
var controlIndicies = new Stack<int>();
var errors = new List<DataObjects.Error>();
controlStack.Push(controls);
controlIndicies.Push(0);
while(controlStack.Count() > 0)
{
while(controlIndicies.First() < controlStack.First().Count)
{
var controlIndex = controlIndicies.Pop();
var currentControl = controlStack.First()[controlIndex];
//insert your own business logic in here
var error = errorProvider.GetError(currentControl);
if (!string.IsNullOrEmpty(error))
{
errors.Add(new DataObjects.Error(error, DataObjects.ErrorLevel.Validation));
}
//insert your own business logic in here
//update the fact that we've processed one more control
controlIndicies.Push(controlIndex + 1);
if(currentControl.Controls.Count > 0)
{
//traverse deeper
controlStack.Push(currentControl.Controls);
controlIndicies.Push(0);
}
//else allow loop to continue uninterrupted, to allow siblings to be processed
}
//all siblings have been traversed, now we need to go back up the stack
controlStack.Pop();
controlIndicies.Pop();
}
return errors;
}
//Depth first - DOES require child to have knowledge of parent.
//Approximate recursion by keeping track of where you are in the control
//tree and use the .Parent() and .Controls() methods to traverse the tree.
//order(depth(tree)) memory usage?
//Best of the bunch as far as I can (in memory usage that is)
private IEnumerable<DataObjects.Error> CheckErrors_NonRecursiveIndicesOnly(Control control, ErrorProvider errorProvider)
{
var errors = new List<DataObjects.Error>();
var controlIndicies = new Stack<int>();
var controlCount = new Stack<int>();
Control currentControl = control;
var currentControls = currentControl.Controls;
controlCount.Push(currentControls.Count);
controlIndicies.Push(0);
while (controlCount.Count() > 0)
{
while (controlIndicies.First() < controlCount.First())
{
var controlIndex = controlIndicies.Pop();
currentControl = currentControls[controlIndex];
//insert your own business logic in here
var error = errorProvider.GetError(currentControl);
if (!string.IsNullOrEmpty(error))
{
errors.Add(new DataObjects.Error(error, DataObjects.ErrorLevel.Validation));
}
//insert your own business logic in here
//update the fact that we've processed one more control
controlIndicies.Push(controlIndex + 1);
if (currentControl.Controls.Count > 0)
{
//traverse deeper
currentControls = currentControl.Controls;
controlCount.Push(currentControl.Controls.Count);
controlIndicies.Push(0);
}
else
{
//allow loop to continue uninterrupted, to allow siblings to be processed
}
}
//all siblings have been traversed, now we need to go back up the stack
controlCount.Pop();
controlIndicies.Pop();
//need to check our position in the stack... once we get back to the top there is no parent of parent.
if (controlCount.Count() > 0)
{
currentControls = currentControl.Parent.Parent.Controls;
}
//do nothing, believe it or not once you've gotten to this level you have traversed the entire stack
}
return errors;
}
問題2的答案是使用您正在檢查的控件的GetType()方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.