Asp.Net: Dynamically switching UserControl - How? - c#

In Asp.Net is it possible to dynamically switch which user control gets loaded with the .aspx page.
Depending on the type of news story I would like to switch which control gets loaded.
Thanks
melt

Put a place holder in your page and in your code-behind file load the control on a if/then/else or switch/case logic method. That's the easiest way I see the implementation.

Use LoadControl(), which is an instance method on the Page class. Then simply add it to a container's Controls collection.
if (mytype=="news")
{
//load the required usercontol
ph.Controls.Add(LoadControl("~/usercontrols/news.ascx"));
}
else
{
ph.Controls.Add(LoadControl("~/usercontrols/somethingelse.ascx"));
}
With "ph" being an asp:PlaceHolder control.

Related

Sanity check: Master Page, Content Page and ASCX dependencies

I'd like someone to give what we're doing a glance-over and tell me whether we're going about it an odd way.
What I have:
We have a .master (Master Page), .aspx (Content Page) and an .ascx (User Control).
The User Control should appear on all pages, so we have placed it on the Master Page
The User Control should be initialised differently based on the Content Page it appears on. So, the Content Page has the resposibility of raising an event on the User Control, passing in some arguments, which initialises the control.
Questions:
In my mind, this removes any dependency between the User Control and either the Content Page or Master Page. Am I correct?
Is calling an event on the User Control the easiest way to pass arguments in and initialise the control accordingly?
Happy to clarify any further points, Thanks.
I would say that's OK, but I would like to seek a clarification: how does the user control subscribe to the event of the content page?
Alternatively, you could also consider creating an interface for the master page:
public interface IMyMaster
{
UserControlType Control { get; }
}
After applying this interface to the master, the interface can return a direct reference to the control. The content page can then do:
if (this.Page.Master is IMyMaster) {
((IMyMaster)this.Page.Master).Control.Initialize();
}
HTH.

Remove statically added controls at runtime

The Scenario: I have an asp.net website where I show a div popup on page load for taking a few user details. When a user inputs the details, or closes the popup, I set up a flag cookie so that the popup is not displayed again for the user. The div is in the MasterPage so that it is displayed no matter on which page a user lands first time. The div contains an UpdatePanel which has all the controls required for taking the details. This whole functionality is working fine.
The Problem: Now this div popup is not showing(by setting display:none) on subsequent postbacks(which I want), but the html markup is still loading with the page unnecessarily adding to the page size. What I would idealy want to do is: Check if flag cookie is set. If no, show the popup, else remove the popup's markup from the page.
Now since the div is not a server control, I cannot possibly remove it and the all the controls inside it. So, I thought of removing the UpdatePanel from the page:
protected void Page_Load(object sender, EventArgs e)
{
if (Request.Cookies["flag"] != null)
{
if (Page.Controls.Contains(updpnl_contact))
{
Page.Controls.Remove(updpnl_contact);
updpnl_contact.Dispose();
}
}
}
But I guess this tends to work with dynamically added controls only, and since the control is added at Design Time, it is not being removed.
Is there any way I can achieve this?
If you add a runat="server" attribute to your <div> element, it will be available in the code-behind. You'll need an id on it as well. Then you can just toggle the Visible property. If this property is false, the control won't be rendered to the client (i.e. no HTML markup).
What you're trying to do is not at all the usual workflow. I tend to think that it will not work as it would mess up control tree, maybe even corrupt the viewstate and so on.
As a possible solution, you can put it's visibility to hidden in the code behind. This, in the contrary to the usual 'gut feeling', doesn't work like the css propery 'display:none' for example - instead the control will not even be rendered into the page when it's not visible. This may be the workaround for you.
Happy coding.
A more efficient approach would be to create the panel as a UserControl and load it dynamically in codebehind when it's needed, then add it to your page. E.g, in code:
MyPopupControl popup = (MyPopupControl)Page.LoadControl("/path/to/usercontrol.ascx");
PopupPanel.Controls.Add(popup);
Where PopupPanel is an empty <asp:Panel>. Then, not even the markup will need to be loaded/processed except when its needed.
There is no reason that all the code you use to display and process this panel couldn't also be in the usercontrol, isolating it from the master page.
Can you build the panel dynamically, based on the cookie setting?

Web Control added in .master control type not found in child page

I have a Web Site project, and within it I have a user Web Control defined in an ascx file.
The control is added to the Site.Master, and it shows up correctly on the page and everything is fine.
I need to override some of the control's fields on one of the pages that derive from Site.Master.
// In OnLoad:
MyControlName control = (MyControlName) Page.Master.GetBaseMasterPage().FindControl("controlID"));
The issue is that MyControlName doesn't register as a valid Type on the child page. If I add a second instance of the control to the child page directly, the above works as needed, but if the control isn't placed directly on the page, and instead is only defined in the master page, the type is undefined. The control is not in a namespace, and is defined within the project, so I don't know why it is having such an issue location the appropriate type.
If I put a breakpoint in the OnLoad, the type listed for the control is ASP.my_control_name_ascx, but using that does not work either.
Why can't the child class reference the correct type? Can I fix this?
Thanks!
The control does not have global scope over the entire project. It will only be selectable as a type on pages where the control is registered. So you have to register the control on the child page:
<%# Register src="WebUserControl.ascx" tagname="WebUserControl" tagprefix="uc1" %>
You will need to add a register tag like above to the top of your child aspx page.
The other option is you could create an interface for the control which exposes the properties or methods you want to access, and put the interface in app_code or some other globally accessible place, then have the control implement the interface, and cast the control to the interface.
The following code works for me:
DropDownList ddlLanguage = (DropDownList)Page.Master.FindControl("ddlLanguage");
I take it GetBaseMasterPage() is your own method? What happens if you try:
MyControlName control = (MyControlName)Page.Master.FindControl("controlId");
?
Not a direct answer to your question, but you might find the #MasterType directive useful.
If you add a line like
<%# MasterType TypeName="ClientName.SiteName.MasterPages.SiteMaster" %>
to the top of your ASPX page, you should be able to refer to the master page in code without having to cast it. This might make it easier for the code to find your control, perhaps?
You could end up with a line like:
// In Page.OnLoad:
MyControlName control = Page.Master.MyControl;
and then expose a new property in your master page that wraps the FindControl call:
// In Site.master.cs
internal MyControlName MyControl
{
get { this.FindControl("controlID"); }
}
Hope this helps!

Change the Access Modifiers of ASP.NET controls

If I put a control in a .aspx file like this;
<asp:TextBox ID="protectedTextBox" runat="server">Some info</asp:TextBox>
I get a declared control in the page's .aspx.designer.cs file;
protected global::System.Web.UI.WebControls.TextBox protectedTextBox;
But I'd like to change the access modifier of the control to public. Is there any attribute or similar that I can set to change the access modifier?
Here's why I want to do it. I am trying to have cross-page postbacks work nice and neatly. I have two pages:
FirstPage.aspx
MyTextBox : textbox
MyButton : button, #PostbackUrl=Secondpage
SecondPage.aspx
MyLabel : label
When the user clicks FirstPage.MyButton, I want to write the value of FirstPage.MyTextBox.Text into SecondPage.MyLabel.Text. I could do it with Page.FindControl, but this seems like a poor substitute to casting the previous page as a FirstPage object and referring directly to the MyTextBox control on it. Something like this;
// on the page_load of SecondPage.aspx;
var previousPage = this.PreviousPage as FirstPage;
this.MyLabel.Text = previousPage.MyTextBox.Text;
Is there any way to change the access modifier?
You can just delete the declaration from the designer and put it in your code behind.
The comments around the declaration say to do this.
/// To modify move field declaration from designer file to code-behind file.
One option I've considered is writing a public property which exposes the original page;
public TextBox PublicTextBox { get { return this.MyTextBox; } }
Which would get the job done, but seems hacky.
Steve, exposing that page's controls would make sense if you'd need to manipulate those controls, but in your case you just need to pass some data (that string) to the other handler, so I would expose that and not the control itself.

How to access .Net element on Master page from a Content page?

Is it possible to access an element on a Master page from the page loaded within the ContentPlaceHolder for the master?
I have a ListView that lists people's names in a navigation area on the Master page. I would like to update the ListView after a person has been added to the table that the ListView is data bound to. The ListView currently does not update it's values until the cache is reloaded. We have found that just re-running the ListView.DataBind() will update a listview's contents. We have not been able to run the ListView.DataBind() on a page that uses the Master page.
Below is a sample of what I wanted to do but a compiler error says
"PeopleListView does not exist in the current context"
GIS.master - Where ListView resides
...<asp:ListView ID="PeopleListView"...
GISInput_People.aspx - Uses GIS.master as it's master page
GISInput_People.aspx.cs
AddNewPerson()
{
// Add person to table
....
// Update Person List
PeopleListView.DataBind();
...
}
What would be the best way to resolve an issue like this in C# .Net?
I believe you could do this by using this.Master.FindControl or something similar, but you probably shouldn't - it requires the content page to know too much about the structure of the master page.
I would suggest another method, such as firing an event in the content area that the master could listen for and re-bind when fired.
Assuming the control is called "PeopleListView" on the master page
ListView peopleListView = (ListView)this.Master.FindControl("PeopleListView");
peopleListView.DataSource = [whatever];
peopleListView.DataBind();
But #palmsey is more correct, especially if your page could have the possibility of more than one master page. Decouple them and use an event.
Option 1 :you can create public property of your master page control
public TextBox PropMasterTextBox1
{
get { return txtMasterBox1; }
set { txtMasterBox1 = value; }
}
access it on content page like
Master.PropMasterTextBox1.Text="SomeString";
Option 2:
on Master page:
public string SetMasterTextBox1Text
{
get { return txtMasterBox1.Text; }
set { txtMasterBox1.Text = value; }
}
on Content Page:
Master.SetMasterTextBox1Text="someText";
option 3 :
you can create some public method that works for you
these approach is not so useful but it helps if you just want to use some limited and predefined control
One think to remember is the following ASP.NET directive.
<%# MasterType attribute="value" [attribute="value"...] %>
MSDN Reference
It will help you when referencing this.Master by creating a strongly typed reference to the master page. You can then reference your ListView without needing to CAST.
you can access with the code this.Master.FindControl(ControlID) which control you wish. It returns the reference of the control, so that the changes are effective. about firing an event could not be possible each situation.
Assuming your master page was named MyMaster:
(Master as MyMaster).PeopleListView.DataBind();
Edit: since PeopleListView will be declared protected by default, you will either need to change this to public, or create a public property wrapper so that you can access it from your page.

Categories