asp.net: When is the Visible property of child controls automatically set?
Example 1:
<asp:Panel Visible="false" runat="server">
<asp:TextBox ID="textbox" runat="server" />
</asp:Panel>
Here, textbox.Visible
returns false
in code (even though TextBox.Visible
was n开发者_StackOverflowot set explicitly; it seem to "inherit" the property from its invisible parent).
Example 2:
<asp:DataGrid ID="grid" runat="server" AutoGenerateColumns="false">
<Columns>
<asp:TemplateColumn Visible="False">
<ItemTemplate>
<asp:TextBox ID="textbox" runat="server" />
</ItemTemplate>
</asp:TemplateColumn>
</Columns>
...
</asp:DataGrid>
Here, ((TextBox)grid.Items[0].FindControl("textbox")).Visible
returns true
(under the assumption that the DataGrid has at least one row).
Question: Is this inconsistent behaviour by design? In both cases, the TextBox is not rendered because some parent element is invisible.
(Granted, in the second case the textbox is inside a template, but I'm not querying an abstract TextBox in the template definition, I'm querying the specific, concrete TextBox in row number 0.)
Background: TextBox is a smart control: It only saves its Text property in the ViewState if it's invisible. That makes sense: If the TextBox is visible, it's rendered as a HTML <input>
control and its current Text
value is submitted on a postback - no need to submit it again via the ViewState. Of course, if the TextBox is invisible, it is not rendered, and, thus, any changes to the Text
property would be lost.
Now, Example 2 is giving us some trouble. textbox
thinks that it's being rendered (according to IL spy, it checks its own Visible
property in TextBox.SaveTextViewState
), so it doesn't use the ViewState and all changes to textbox.Text
done in code are lost. I'm now wondering whether this is bug or not.
Related question: How to get the set/real value of the Visible property in Asp.Net.
EDIT: I've created a Microsoft Connect Bug Report on this:
- Webforms: Control.Visible does not recognize that the control is within an invisible DataGrid column
TextBox
and Panel
both inherit from WebControl
, which inherits from Control
. Control
has the following definition for the Visible
property:
public virtual bool Visible
{
get
{
return !this.flags[16] &&
(this._parent == null || this.DesignMode || this._parent.Visible);
}
set
{
if (this.flags[2])
{
bool flag = !this.flags[16];
if (flag != value)
{
this.flags.Set(32);
}
}
if (!value)
{
this.flags.Set(16);
return;
}
this.flags.Clear(16);
}
}
Since Visible
is not implemented directly on TextBox
, it will always return false
if the Visible
property of the parent is false (at runtime and if there is a parent specified). So to answer the question asked in the title, the Visible
property is not automatically set to false
at any point in time, it's just evaluated when it is accessed. In the case of the GridView
where TextBox.Visible
returns true
, it stands to reason that the parent control of the TextBox
is not the TemplateColumn
, or at least the parent does not have its Visible
property set to false.
EDIT
So, using your example grid in the question, if you walk the chain of controls up, you'll see that all of the parent controls for the TextBox
are Visible
. I used the code below, and here's the output:
TextBox (ClientID = grid_textbox_0, Visible = True)
TableCell (ClientID = grid_ctl00_0, Visible = True)
DataGridItem (ClientID = grid, Visible = True)
ChildTable (ClientID = grid_ctl00, Visible = True)
DataGrid (ClientID = grid, Visible = True)
HtmlForm (ClientID = form1, Visible = True)
Code:
protected void btnSubmit_Click(object sender, EventArgs e)
{
var control = grid.Items[0].FindControl("textbox");
while(control != this && control != null)
{
Response.Write(string.Format("{0} (ClientID = {1}, Visible = {2})",
control.GetType().Name, control.ClientID, control.Visible));
Response.Write("<br />");
control = control.Parent;
}
}
It seems to me that the DataGrid
and the Visisble
properties are working as expected.
精彩评论