what will happen if we don't call base.createchildcontrols() - asp.net

I just would like to know what will happen if we don't put base.createchildcontrols() in the code. Will composite control be created without calling base.createchildcontrols()?
[ToolboxData("<{0}:Login runat=server></{0}:Login>")]
public class Login : CompositeControl
{
private TextBox txtUsername = new TextBox();
private TextBox txtPassword = new TextBox();
private Button btnLogin = new Button();
protected override void CreateChildControls()
{
txtUsername.ID = "txtUsername";
txtPassword.ID = "txtPassword";
txtPassword.TextMode = TextBoxMode.Password;
btnLogin.ID = "btnLogin";
btnLogin.Text = "Login";
Controls.Add(txtUsername);
Controls.Add(txtPassword);
Controls.Add(btnLogin);
base.CreateChildControls();
}
}

The short answer is... Nothing! You don't need to call the base implementation (although you can always try removing it to see what happens ;-)
Using ILSpy, we can see that CompositeControl inherits from WebControl which inherits from Control.
CreateChildControl() is defined on Control as:
protected internal virtual void CreateChildControls()
{
}
i.e. It is only there to be overriden.
Compare this with some other controls that inherit from Control, like BaseDataList and you can see that that method has a lot of functionality for checking and rendering the output.
This makes sense. Reading the MSDN documentation, here, we can see that it is for you to implement the rendering of any child controls. Only if the class you are inhereting from requires this method to be called, then you'll have to call it.

Related

ASP.NET ListView - How to set EmptyDataTemplate programmatically?

I have a class MyListView, it inherits from ASP.NET ListView. I would like to implement a default behaviour - if a programmer doesn't specify EmptyDataTemplate in aspx code, the MyListView will use a predefined default template (class MyEmptyDataTemplate).
What I have tried is this:
public class MyListView : ListView
{
protected override void CreateChildControls()
{
if (EmptyDataTemplate == null)
EmptyItemTemplate = new MyEmptyDataTemplate();
base.CreateChildControls();
}
}
The MyEmptyDataTemplate implements ITemplate interface. The problem is, that InstantiateIn() method of the MyEmptyDataTemplate is never called, and my default template never appears in case there are no records in datasource. Apparently I wrong understand the ListView component lifecycle and template should be set somewhere else.
Try to do this on the Init event:
public class MyListView : ListView
{
public MyListView()
{
this.Init += (o, e) =>
{
if (EmptyDataTemplate == null)
EmptyDataTemplate = new MyEmptyDataTemplate();
};
}
}
edit
After checking this again I realized that EmptyDataTemplate was checked if emtpy, but the template which has been assigned is EmptyItemTemplate. However both methods are good to instantiate the templates..

Can't FindControl when RenderControl ascx in RenderBeginTag while overriding Panel

I'm creating a container using Panel control as follows:
public class CustomContainer : Panel
{
public override void RenderBeginTag(HtmlTextWriter writer)
{
var control this.Page.LoadControl("web user control path.ascx");
control.ID = "userControlId";
control.RenderControl(writer);
base.RenderBeginTag(writer);
}
public void ShowMessage(string message)
{
var control = this.FindControl("userControlId"); // control here is null!!
var custom = control as CustomControl;
custom.Message = message;
}
}
when I try to find the control with id userControlId which I rendered, it always retuns null!
Does anyone know what's happening? How can I solve this issue?
BTW: I can't add the CustomControl in CreateChildControls method because if the CustomContainer has code block I got an exception!
The Controls collection cannot be modified because the control
contains code blocks (i.e. <% ... %>).
You're probably calling ShowMessage before the control is rendered. Try calling ShowMessage during OnPreLoad or OnLoad. Basically, anywhere after the Render.

Can't find control (ASP.NET, MS TEST)

The following test:
[TestClass]
public class MyTestClass
{
private TestContext _testContext;
protected TestContext TestContext
{
get { return _testContext; }
set { _testContext = value; }
}
[TestMethod]
[HostType("ASP.NET")]
[UrlToTest("http://localhost/MyPage.aspx")]
public void TestMyPage()
{
TextBox tb = TestContext.RequestedPage.FindControl("ControlId") as TextBox;
Assert.IsNotNull(tb);
}
}
fails, and using the string "ctl00$ContentPlaceHolder1$ControlId" as control Id provide a proper control... I know, ASP.NET contains "ClientID" property for web-controls, but is there any possibility to know in advance the control's client Id in the TEST (Under VS 2008)?
Thanks.
I don't think the ClientID is what you're after here. I think your problem is that FindControl is not doing what you think it is.
FindControl is not recursive. If your textbox is inside of a ContentPlaceHolder, then you need to call FindControl on the placeholder, not the Page.
Otherwise, I suggest writing a recursive FindControl function that will search the entire control heirarchy. You can see an example here.

How to communicate between ASP.net custom controls

I'm using two custom controls. One gathers the criteria for a search, and the other displays a list. These two controls need to remain seperate for the time being.
What is the best method of transfering data from the search control, to the list control?
I'm thinking of ViewState, Session or wrapping both within a UpdatePanel and using custom events??
Maybe you can create a delegate and an event to pass a list of searchvalues? This way you can easily add another or multiple display controls in case that ever becomes necessary.
Note that this is just some quick sample code that should be optimized/improved.
public class SearchControl
{
public delegate void SearchEventHandler(object sender, Dictionary<string, string> SearchValues);
public event SearchEventHandler OnSearch;
public SearchControl()
{
btnSearch.Click += new EventHandler(Search);
}
protected void Search(object sender, EventArgs e)
{
if (OnSearch != null)
{
Dictionary<string, string> searchValues = new Dictionary<string, string>();
searchValues.Add("name", "John");
searchValues.Add("age", "24");
OnSearch(this, searchValues);
}
}
}
public class DisplayControl
{
public void ShowResults(Dictionary<string, string> SearchValues)
{
// Some logic here...
}
}
public class YourWebPage
{
SearchControl searcher = new SearchControl();
DisplayControl displayer = new DisplayControl();
public YourWebPage()
{
searcher.OnSearch += new SearchControl.SearchEventHandler(searcher_OnSearch);
}
public void searcher_OnSearch(object sender, Dictionary<string, string> SearchValues)
{
displayer.ShowResults(SearchValues);
}
}
Expose a public property of the type of data you have, then a public method to bind the data to your list
If the controls are separate, they should probably not be communicating directly. After all - most other .NET controls don't communicate directly either. I can only think of two exceptions - child/parent controls sometimes communicate basic information; and data-bound controls sometimes communicate directly with a DataSource. But that's largely it.
If you need to hook up two adjacent controls then the "normal" way of doing it is that their container takes care of it. Like, if a button click affects the text on the label, it is the Page (container for them both) that handles the Click event and sets the Text property.
Alternatively you could also give your ListControl a property called FindControl and assign it in Page_Init or something. But if the coupling is so tight, you might wonder if it would not be better to merge the controls too.
It depends on where the search is performed and what data is transferred between the controls. In my opinion, it is probably best to just pass the criteria to the page and have the page run the search bind them to the list control to display the results.

Set Server Side OnClick() event Programmatically

I am looking for a way to programmatically set the OnClick event handler for a TableCell object. The ASP equivalent of what I'm trying to do will look like this:
<asp:TableCell OnClick="clickHandler" runat="server">Click Me!</asp:TableCell>
In the above example, "clickHandler" is a server-side function defined in the .cs CodeBehind.
public virtual void clickHandler(object sender, EventArgs args) {...}
However, for my situation, this TableCell object needs to be created dynamically, so setting it in an ASP tag is not an option. I am trying to do something like the following in the CodeBehind:
System.Web.UI.WebControls.TableRow row = new System.Web.UI.WebControls.TableRow();
System.Web.UI.WebControls.TableCell cell = new System.Web.UI.WebControls.TableCell();
cell.Text = "Click Me!";
cell.Attributes.Add("onClick", "clickHandler");
row.Cells.Add(cell);
Unfortunately, in this situation:
cell.Attributes.Add("onClick", "clickHandler");
the "clickHandler" only works as a client-side javascript function. What I'm looking for is a way to link the server-side clickHandler() function, defined in the .cs CodeBehind, to this table cell.
After an afternoon of searching, I have been unable to come up with a working solution. Thanks in advance for any help.
After a lot of work and research, I was able to cobble together a working solution, but it seems like an awful lot of work for something that should already be built-in. What I did was to extend the System.Web.UI.WebControls.TableCell object to include a handle for the OnClick event:
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace MyWebApp
{
public class ExpandableTableCell : TableCell, IPostBackEventHandler, INamingContainer
{
private static readonly object click_event = new object();
public ExpandableTableCell()
{
}
// public handles for adding and removing functions to be called on the click event
public event EventHandler Click
{
add
{
Events.AddHandler(click_event, value);
}
remove
{
Events.RemoveHandler(click_event, value);
}
}
// define parent function that will be called when the container is clicked
protected void Click(EventArgs e)
{
EventHandler h = Events[click_event] as EventHandler;
if (h != null)
{
h(this, e);
}
}
// specify the "post back event reference" or id of the click event
protected override void AddAttributesToRender(HtmlTextWriter writer)
{
base.AddAttributesToRender(writer);
writer.AddAttribute(HtmlTextWriterAttribute.Onclick,
Page.ClientScript.GetPostBackEventReference(this, "custom_click"));
}
// link the custom click id to the click function
void System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(string eventArgument)
{
if(eventArgument == "custom_click")
{
this.OnClick(EventArgs.Empty);
}
}
}
}
Here is how I use my new class (almost exactly like the stock TableCell):
System.Web.UI.WebControls.TableRow row = new System.Web.UI.WebControls.TableRow();
ExpandableTableCell click_cell = new ExpandableTableCell();
click_cell.Text = "Click Me!";
click_cell.Click += clickHandler;
// extra little touch for mouseover event
click_cell.Attributes.Add("onmouseover", "this.style.cursor='pointer'");
row.Cells.Add(click_cell);
As I have said, it seems like going through the trouble of extending the class to set the OnClick method in the codebehind is excessive. If anyone has any other ideas or any ways to clean up or legitimize the code above, please let me know.
I don't know if this is relevant to your problem, but I was trying to add a server-side function to a LinkButton and found the following (VB) code: AddHandler cell.Click, AddressOf clickHandler, which worked for me.
According to this code conversion service, this translates to cell.Click += clickHandler; in C#.
Hope this helps!

Resources