How can I dynamically clear all controls in a user control?
Is it possible to dynamically (and generically) clear the state of all of a user control's child controls? (e.g., all of its TextBoxes, DropDrownLists, RadioButtons, DataGrids, Repeaters, etc -- basically anything that has ViewState)
I'm trying to avoid doing something like this:
foreach (Control c in myUserControl.Controls)
{
if (c is TextBox)
{
TextBox tb = (TextBox)c;
tb.Text = "";
}
else if (c is DropDownList)
{
DropDownList ddl = (DropDownList)c;
ddl.SelectedIndex = -1;
}
else if (c is DataGrid)
{
DataGrid开发者_开发问答 dg = (DataGrid)c;
dg.Controls.Clear();
}
// etc.
}
I'm looking for something like this:
foreach (Control c in myUserControl.Controls)
c.Clear();
...but obviously that doesn't exist. Is there any easy way to accomplish this dynamically/generically?
I was going to suggest a solution similar to Task's except (as sixlettervariables points out) we need to implement it as 1 extension method and essentailly switch on the precise type of the control passed in (i.e. copy your logic that you posted in your question).
public static class ControlExtensions
{
public static void Clear( this Control c )
{
if(c == null) {
throw new ArgumentNullException("c");
}
if (c is TextBox)
{
TextBox tb = (TextBox)c;
tb.Text = "";
}
else if (c is DropDownList)
{
DropDownList ddl = (DropDownList)c;
ddl.SelectedIndex = -1;
}
else if (c is DataGrid)
{
DataGrid dg = (DataGrid)c;
dg.Controls.Clear();
}
// etc....
}
}
It is not particularly elegent looking method but your code in your page/control is now the more succinct
foreach (Control c in myUserControl.Controls) {
c.Clear();
}
and you can of course now call control.Clear()
anywhere else in you code.
You can do
foreach (Control c in myUserControl.Controls) {
myUserControl.Controls.Remove(c);
}
Because Controls is just a list, you can call Remove() on it, passing it what you want to remove.
EDIT: Oh I'm sorry, I didn't read it correctly. I don't know of a way to do this, maybe someone here who is good with Reflection could make it where you could do like
foreach (Control c in myUserControl.Controls) {
c = new c.Type.GetConstructor().Invoke();
}
or something, to turn it into a freshly made component.
I haven't tested it, but clearing viewstate for the usercontrol may work. You could expose a custom method on the user control as well:
usercontrol:
public void Clear()
{
this.ViewState.Clear();
}
page:
myUserControlInstance.Clear();
Now again I haven't tested. It's possible this will only clear the StateBag
for the UserControl container, and not its nested/child controls.. if the above doesn't work you could try using recursion to walk down the control tree to clear viewstate for all children:
usercontrol:
public void Clear()
{
ClearViewState(this.Controls);
}
private void ClearViewState(ControlCollection cc)
{
foreach(Control c in cc)
{
if(c.HasControls())
{
//clear the child controls first
ClearViewState(c.Controls);
}
//then clear the control itself
c.ViewState.Clear();
}
}
page:
myUserControlInstance.Clear();
Just an idea. I haven't tested it but I think in theory it could work. One implication would be to call Clear at the correct point in the page/controls lifecycle, otherwise it may not work.
Hope this helps!
myUserControl.Controls.ToList().ForEach(c => myUserControl.Controls.Remove(c));
However, be careful, because you modify the iterating list. This could lead to some strange behaviour.
Setting EnableViewState="false"
on the individual controls might save you the work, if it doesn't cause other problems for you in this instance.
What about the Control.ClearChildViewState method?
MSDN states
Deletes the view-state information for all the server control's child controls.
I have never used this though. So I am unsure if it will help you. Sounds good though, I think :)
Why not do as you suggest:
foreach (Control c in myUserControl.Controls)
c.Clear();
And then implement Clear:
public static class UserController
{
public static void Clear( this Control c )
{
c.Controls.Clear();
}
public static void Clear( this TextBox c )
{
c.Text = String.Empty;
}
}
That should do it.
精彩评论