ASP.NET usercontrol: check if usercontrol is visible - c#

My question is somewhat related to this thread: How to avoid Initialization of web user control inside aspx?
The UserControl should only be visible when a button is clicked.
So my usercontrol is set like this:
<example:usercontrol ID="idControl" runat="server" Visible="false" />
<asp:Button ID="showMyControl" runat="server" OnClick="ShowMyControl" /
And the usercontrol itself checks if he's visible:
protected void Page_Load( object sender, EventArgs e ) {
// only execute if the user control is visible
if ( this.Visible ) {
...
}
}
When I click the button I'm setting the property Visible of the usercontrol to true but when the postback occurs the Visible-property in the Page_Load of the usercontrol is still set to false.
My UserControl is probably loaded first and the Visible-property is set afterwards?
Is there an easy way to resolve this?
Thanks in advance!

The Load event of your control, which is being handled by your Page_Load event handler method if I understand correctly, gets fired before the Click event of your button control. Therefore, when the Page_Load method checks this.Visible, the property has not yet been changed because the Click event handler has not yet executed.
For this reason, I think that checking the Visible property of your control would be more appropriate in the PreRender event instead of the Load event.
I'm guessing that you're doing some sort of data retrieval or something that you wish to avoid if the control is not visible. Unfortunately, this sort of issue regarding the page life-cycle and the order in which events fire is sort of a common issue to deal with in ASP.Net programming.
If all of your initialization code can easily be moved into the PreRender event, then great. Problem solved (hopefully). If not (i.e. you need something to happen before the PreRender), you may need to come up with some other mechanism to ensure that your code executes at the right time. For example, you could expose a "SetVisible" method on your control which sets the Visible property to true and then also executes whatever initialization logic is needed. The downside of this is that you can't really guarantee that some code won't just set your control's Visible property to true outside of the SetVisible method that you provide.
Another idea is to actually override the Visible property and perform your initialization logic whenever that property gets set to true.

Put the code which you call in the Control's Page_Load event into the PostBack event. Make sure the button has autopostback set to true.

What you are looking for is the Control.EnsureChildControls method. This method exists for this very situation. It will ensure that all child controls have been created. Then you can set your visible property.

Related

VisibleChanged don't raise when not visible

I'm working on c# WinForm.
I have an custom UserControl : MyControl : UserControl, INotifyPropertyChanged. I attached a method on event on event VisibleChanged : this.VisibleChanged += new System.EventHandler(this.MyControl_VisibleChanged);
My application have some pages, each page is a control like MyControl. Top of MainWindows contains Button, used to switch tab.
My problem is that my function MyControl_VisibleChanged is called only when Visible is changing to true. I added a test in a tab to check MyControl.Visible, when I select the other tab, MyControl.Visible is false but no event is raised.
I've try to define a new property Visible for this control but value is never set, only the base value is modify.
Can you help me to find a solution ?
This is a quirk in the way Visible works, explained here. His solution was to use properties that he has complete control over, but you could instead have a method allowing the tab switches to tell their children to raise their VisibleChanged event that extra time.
The first two answers to this question may also be useful.

Force a post back when checkbox.checked value is set to true

I have a method that changes the checked attribute of a checkbox like this
checkbox1.checked = true;
and then I have the eventhandler method:
checkbox1_checkedChanged(object obj, EventArgs args)
However, when I perform the changing of checked attribute to true, the event handler does not fire up.
How can I achieve this?
I suspect that your function that does checkbox1.checked = true; is running server side, so could never cause a postback.
If this is the case, and you just wish to invoke the code in your checked changed handler, you could just call the function directly, or refactor the code out into a common function.
You need to set AutoPostBack to true on your element
<asp:CheckBox id="checkbox" runat="server" AutoPostBack="true" />
What you need to do is simply call the method handler you want fired because you're already server-side and so no event is going to fire because of a property value change. So, try this after setting checked to true:
checkbox1_checkedChanged(checkbox1, new EventArgs());
Well, you talk about "post back" so I assume you are creating a web page.
The AutoPostBack property only indicates that the post back event will fire when the control's property is changed through the control itself on the web page since the event handler is bound to the control only.
So, changing the control's property dynamically (with code on the server side) will never trigger the event handler. Instead, you could just call the handler right after the change (like what Justin Harvey said).

Why would my child controls be uninitialized at the time of event attachment?

I have a page and a user control — we'll call them Detail.aspx and Selector.ascx.
Let's say the page shows the details of individual records in a database. The user control basically consists of a DropDownList control and some associated HTML. The DropDownList displays a list of other records to switch to at any time.
When the DropDownList fires its SelectedIndexChanged event, I'd like the parent page, Detail.aspx in this case, to handle it. After all, he'll need to know what was selected so that he can appropriately change the URL and the details shown, etc.
To do that, I've done what I usually do, which is also what the top answer says to do in this StackOverflow question:
public event EventHandler DropDownSelectedIndexChanged
{
add
{
MyDropDownList.SelectedIndexChanged += value;
}
remove
{
MyDropDownList.SelectedIndexChanged -= value;
}
}
The above code appears in the Selector.ascx.cs codebehind file.
As a result, on Detail.aspx, I can use it like so:
<cc1:RecordSelector ID="RecordSelector1" runat="server"
OnDropDownSelectedIndexChanged="RecordSelector1_DropDownSelectedIndexChanged" />
So far nothing fancy or surprising.
Here is my problem:
This causes a NullReferenceException when the browser hits Detail.aspx.
Debugging the problem shows that when the page is first hit, the public event I've shown above tries to add the event, but MyDropDownList is null, thus throwing the exception. From what I can tell, the events are added (or attempted to be added) before the Selector user control's Load event fires and thus also before the DropDownList's Load event fires.
Curiously, if I omit the OnDropDownSelectedIndexChanged attribute from Detail.aspx and instead put the following in the Page_Load event in Detail.aspx.cs:
protected void Page_Load(object sender, EventArgs e)
{
RecordSelector1.DropDownSelectedIndexChanged += new EventHandler(RecordSelector1_DropDownSelectedIndexChanged);
}
It works exactly as expected. The events are attached and handled just fine. No problems.
But this means several bad things:
I have to remember not to use the designer to add said event onto my user control
I have to remember not to add the event via attributes when working in source view
Worst of all, as the control's author I need to make sure everybody else using my control knows 1 and 2
So what am I doing wrong? Every example I've seen thus far shows similar usage of exposing child controls' events through a user control.
The reason this works:
protected void Page_Load(object sender, EventArgs e)
{
RecordSelector1.DropDownSelectedIndexChanged
+= new EventHandler(RecordSelector1_DropDownSelectedIndexChanged);
}
and this does not:
<cc1:RecordSelector ID="RecordSelector1" runat="server"
OnDropDownSelectedIndexChanged="RecordSelector1_DropDownSelectedIndexChanged" />
is because the first one adds the handler after the control has been initialized (via the page's Init). The second example gets parsed much earlier and as such the page is attempting to add the handler before the control has initialized.
Due to the nature of the page's life cycle I think you may have to live with adding the event handler in the code-behind. There will be no way to add the handler before the control is initialized because that control will always be null prior to initialization.

Programmatically adding a user control in ASP.NET

I have a user control that needs to load a child control when a button is clicked.
The trouble is that it has to request the control from another class.
So in the button click event, I call the function to get me my control, and add it to the page, like this:
UserControl ctrl = ExampleDataProvider.GetControl(some params...);
myDetailPane.Controls.Add(ctrl);
The GetControl method looks like:
public static UserControl GetControl(some params...)
{
ExampleDetailPane ctrl = new ExampleDetailPane();
ctrl.Value = "12";
ctrl.Comment = string.Empty;
return ctrl;
}
This isn't working due to the page's lifecycle - the Page_Load of the child control gets fired and its controls are null.
I kind-of know that my approach is wrong and why, but don't know the best way to go about fixing it! Could anyone help?
Dynamic controls must be re-created on every postback, this Article is a good link about how to persist dynamic controls and their state.
If you want to access your control in PostBack or you want to bind Event, you have to create them in CreateChildControls() method.
private UserControl _uc = null;
/// <summary>
/// Creates all controls.
/// </summary>
/// <remarks>All the controls must be created in this method for the event handler</remarks>
protected override void CreateChildControls()
{
_uc = new UserControl ();
this.Controls.Add(_uc);
base.CreateChildControls();
}
Create your control in Page_Init. Then make it visible on your Button_Click event.
(CTRL+C/CTRL+V from some other question I answered last week):
Everything that has to be maintained between page cycles should be declared in Page_Init, not Page_Load.
All the initialization, like adding event handlers, and adding controls should be added during initialization, as the state is saved between page cycles. Handling with the content of controls and the viewstate, should be done in Load.
Check also http://msdn.microsoft.com/en-us/library/ms178472.aspx.
Init
Raised after all controls have been initialized and any skin
settings have been applied. Use this
event to read or initialize control
properties.
.
Load
The Page calls the OnLoad event method
on the Page, then recursively does the
same for each child control, which
does the same for each of its child
controls until the page and all
controls are loaded.
Use the OnLoad event method to set
properties in controls and establish
database connections.
Two possible approaches:
Have the control in the page but not loaded with anything until they click their button. Then you can populate the values in the control. This has the benefit of being within the page life cycle. Note, you can always use the "display: none" style setting for the that your user control is in. Then, as part of the OnClick for the button, you can reveal the div making your control visible.
You could pop up another window, though obviously this has the potential for being blocked by popup blockers.

.net Page events firing order changing

Ok this is a really annoying bug that I have been having issues with all morning!.
I have a custom control that we have used on many project that has properties that are set and stored in Viewstate by the calling pages onload. the control sets up childcontrols with propertes on the CreateChildControls() method of the custom control.
Normally as usual on a postback the Page_Load event is fired then the CreateChildControls method of the control on the page is fired.
The strange thin though is we have a login system (custom membership provider) on the site and when a user is logged in the opposite happens first the CreateChildControls() method fires then the Page_Load so the control properties are wrong (set from the previous postback)
How could the events be firing in a different order? I thought all page events happened in the same order no matter what and I don't see how being logged in would change that order.
UPDATE: It seems the issue is I'm not calling EnsureChildControls() but I'm not sure where it should be called? If several properies are set on the control which are used in setting up the child controls when should I call EnsureChildControls(), I guess I don't fully understand what EnsureChildControls() does?
CreateChildControls is called whenever the ASP.NET page needs them. There is no specific point in the page cycle for that. It can happen in the Init event, it can happen in the Load event. If you want to make sure your child controls are available, then call EnsureChildControls() method of your control. You can do that in the control's Init event to make sure you have child controls through the whole lifecycle or you can do it whenever you need a reference to one of the child controls - e.g. in the getter/setter of a property of your control.
When creating properties of a server/user control that need access to contained child controls I use the following:
public Whatever SomeProperty
{
get
{
EnsureChildControls();
<more code here>
}
set
{
EnsureChildControls();
<more code here>
}
}
This ensures your control consumers are free to work with your control at various stages of the page lifecycle.

Categories