Asp.Net CreateChildControls() - Re create controls with Postback data - Event - asp.net

I have a WebPart custom control (Composite) in .Net, which gets created on page load to show a Chart using 'Dundas Charting Controls' (this is created by a user control inside the page). I get the properties for this control from the database.
I have another control, which is a Filter (outside webpart) and based on data of this filter control which the user selects and which I would get on postback after click of button, I have to show the filtered chart results. The problem is CreateChildControls() gets called before the postback data is available (which would be available only after the Page_Load event fires).
I'm unable to get this data in time to pass on the parameters for filtering the Chart Results.
The implementation os like this ...
Webparts
Page > User Control > Webparts > Composite Control/Chart
Filter
Page > User Control > Composite Control [I get this data on Postback]

It sounds like you are running into an event ordering issue. I always try to make my controles relatively dump - so they don't really know how they are being used.
Consider creating a method in your chart control to force an update of its data:
public void UpdateChart(-- arguments as needed --)
then create an event in your composit control (that has your filters) like
public event Eventhandler FiltersChanged;
Assign this to an event hander on parent page:
filterControl.FiltersChanged += new EventHandler(Filter_OnChange)
Then create an event handler that tells your chart control about the change
Filter_OnChange(Object sender, EventArgs e)
{
// get whatever data you need from your filter control
// tell the chart about the new data and have it reload/redraw
myChart.UpdateData( - filter options here -}
}
In doing so, you let the page direct the order of operations and do not rely on the order in which the child controls Load methods are called.

James - Thanks for your answer, but this does not seem to work in my scenario or rather I couldn't make it work, when I tried it. The controls seems to be doing too much and is getting data from every where, it has its own constructor implementation, Load() override etc so a single UpdateChart() function may not have done the trick in this case.
This is what I did, finally.
I fire an Ajax request with Filter Data and set the value in a Session Variable before page does a Postback, this way I get the data at all places/events, and pass on the same as parameter where required. I know it may seem weird way to implement this, but it saved additional Database calls (which in this case are many to create the controls again) even though it comes at the cost of an additional Server HTTP ajax request.
Let me know this implementation can have any negative impact.

Related

Should i make a call to DB or save value in viewstate

On asp.net page, I am using tabs and one of the tab has got user control on it.
On the first tab, data is being displayed from table A and the second tab (which has user control on it) is getting data from table B.
On the user control (second Tab), I need to show the column value of table A. It is just one string value.
I am wondering if there is any best way of displaying the value of a table A column without making a call to database?
The way code has been designed, I can’t access the user control’s textbox from the first tab.
I can only think of using view state or session but don’t know if I should use them instead of making call to DB.
I want value to live for the current page's lifecycle.
If you can save it in viewstate then go for it. But there are plenty of storage options in addition to just viewstate:
querystring (good for Ids, not great for strings)
cookie (pretty straight forward)
local storage (HTML 5 only)
cache (you could still appear to make the call but just have the results cached. you then have to deal with cache expiration as well)
session (as you mentioned, this is basically a per-person cache usage, but is not a bad option)
hidden field (basically what viewstate is)
Even with all of those options, the viewstate is going to be a pretty good one, but it just requires that you post back the viewstate every time you need that value.
How about using js to copy the data contents from tab1? Are you loading the usercontrols in tabs using ajax?
If you have a complex form and need to split into smaller chunks I would use a multiview control with as many views as you need to complete your task. If you design each view with its own controls, validation groups and logics .net will do the rest, you won't have to manually deal with states or saving middle steps
<asp:MultiView ID="MultiView1" runat="server">
<asp:View ID="View1" runat="server">
<asp:TextBox ID="txt1" runat="server" />
<asp:Button ID="Button1" runat="server" Text="Next" OnClick="NextStep_Click" />
</asp:View>
<asp:View ID="View2" runat="server">
<asp:TextBox ID="txt2" runat="server" />
<asp:Button ID="Button2" runat="server" Text="End" OnClick="EndProcess_Click" />
</asp:View>  
</asp:MultiView>
<asp:TextBox ID="txt3" runat="server" />
In code behind
protected void NextStep_Click(object sender, EventArgs e)
{
MultiView1.SetActiveView(View2);
txt2.Text = txt1.Text;
}
protected void EndProcess_Click(object sender, EventArgs e)
{
txt3.Text = txt1.Text + " " + txt2.Text;
}
you can go back and forth the times you want and won't have to worry with the values the users entered. Obviously, you have to put buttons to go back and just set the active view you want.

in asp.net avoid rebinding of data to grid on every pageload

in asp.net suggest me a best way for storing and binding datatable to grid to avoid rebinding on each pageload
thanks
Grid values will be stored in ViewState automatically. You shouldn't need to be rebinding on every postback unless you're changing the data.
If you have a dataset that you're retrieving different "views" from each time, like custom paging or sorting, then you should evaluate using the Cache to store your dataset.
If viewstate is enable then you do not need to rebind.
If something is changing and you need to rebind you have a couple of options. Store your datasource in the viewstate or session. Then you don't need to hit the database each time you need to add a filter or paginate etc.
Eg.
// Load up date initially
public void LoadYourData()
{
// This gets your data however you are doing it, in this example I am returning
// a list of objects.
List<YourObjects> yourData = GetYourData();
// You then have the option to save it in the session or viewstate, I will
// demonstrate both. Make sure if you are using viewstate that your objects are
// serializable. You should probably also create helper classes to deal with
// getting and setting data from the ViewState object or Session.
Session["YourData"] = yourData;
ViewState["YourData"] = yourData;
}
// Then make a bind function that gets the data out of whatever store you have it in
public void BindYourGrid()
{
// I will assume you used session
grdYourGrid.DataSource = (List<YourObjects>)(Session["YourData"]);
grdYourGrid.DataBind();
}
So when you need to use it in your Page_Load you could just use the following:
GetYourData();
BindYourGrid();
If you need to apply something a filter you just need to pull the data out of your store (session or viewstate) and perform your manipulation and store it again. Then just call BindYourGrid();.
This way you are never actually hitting the DB unless you need to. There are other methods for caching your datasource's data as well and they all have pros and cons. Go with whatever works in your case though as I have only shown two methods.

Advice for Building a dynamic "Advanced Search" Control in ASP.NET

alt text http://img3.imageshack.us/img3/1488/advancedsearch.png
I'm building an "Advanced Search" interface in an ASP.NET application. I don't need SO to write this thing for me, but I'm stuck on a specific problem regarding dynamic controls and ViewState. I would like some direction for how to approach this. Here's my situation:
Ingredients:
A serviceable set of API objects representing entities, fields, and searches, which handles constructing a search, generating SQL, and returning the results. So that's all taken care of.
ASP.NET 3.5
Desired Interface Functionality:
(1) On initial page load, the interface gets a preconfigured Search object with a set of SearchCriterion objects. It binds them into a set of controls (see image above.)
Some search items are simpler, like:
Field (DropDownList) | Operator (DropDownList) | Value (TextBox)
Search Criterion controls for some field types have important information stored in viewstate, like:
Field (DropDownList) | Operator (DropDownList) | Value (DropDownList) where the "Value" dropdownlist is populated by a database query.
Some fields are lookups to other Entities, which causes a chain of field selectors, like:
Field (DropDownList) Field (DropDownList) | Operator (DropDownList) | Value
(2) The user modifies the search by:
Adding and Removing search criteria by clicking respective buttons
Configuring existing criteria by changing the Field, Operator, or Value. Changes to Field or Operator will require the control to reconfigure itself by changing the available operators, changing the "Value" input control to a different type, or adding/removing DropDownLists from the "Fields" section if Lookup-type fields are selected/unselected.
(3) Finally, the user hits "Search" to see their results.
The Problem:
As you probably already know if you're answering this question, controls added dynamically to the page disappear on postback. I've created a UserControl that manipulates the control collection and neatly accomplishes step (1) above as you can see in the attached image. (I'm not concerned about style at this point, obviously.)
However on Postback, the controls are all gone, and my Search API object is gone. If I could get the dynamically generated control collection to just play nice and stick in ViewState, I could examine the controls on postback, rebuild the Search object, then handle control events neatly.
Possible Solutions
I could make the Search object serializable and store it in viewstate. Then on page load I could grab it and reconstruct the control collection at page load time. However I'm not sure if this would play nicely with controls raising events, and what happens to the viewstate of Drop-down lists that contain data from the database - could I get it back? It's highly undesirable for me to have to re-query the database on every postback.
I could develop a custom server control (see this link) for this kind of thing... but that is a new topic for me and would involve some learning, plus I'm not totally sure if a custom server control would work any more nicely with non-fixed control collections. Anybody know about that?
I was thinking that I might be able to accomplish this using databound controls - for example I could bind my criterion collection to a repeater which has a fixed control collection (maybe hide the non-used "value" controls, use an inner repeater for the "Field" drop-down lists). Then all the information would stay in ViewState... right?
Any new ideas would be greatly appreciated.
thanks for your help.
b.Fandango
I've been coding for about a day and I got this working beautifully using the third option I suggested in my question - old-school databound controls. Actually I only thought of the idea when I was forced to write out the question in detail - doesn't that just happen to you all the time?
I put my SearchCriterionControl into an asp:Repeater and bound it to my object collection. For the Field Chooser I put an asp:DropDownList inside a nested asp:Repeater and bound the Field array to that. Everything works beautifully, keeps state, actually required very little code. So I never had to dynamically add controls to the page, thank goodness.
Thanks for your suggestions, Ender, Matt and andrewWinn.
Since no one else has taken a stab at this for 2 hours, I'll throw my hat in the ring with a solution that does not rely on viewstate at all (or the ASP.NET model of postbacks).
What if you grabbed all the input values with jQuery and instead of doing a post-back did a post against the page (or a new results.aspx page)? Or, you could make the entire thing asyncrhonous and do an Ajax request against a web method, get fed the results, and populate on the client side as needed?
The unfortunate thing here is you have to reconstruct which type of controls were used to figure construct your search query since that data wont be passed with the viewstate. But I imagine you were already going to have to do some kind of translation of your input data into a query form anyway.
Read here for more information about using jQuery to hit an ASP.NET page method. Remember - page methods must be static (it's an easy oversight).
I'm not sure what you're doing server side to construct your query - but I would highly recommend LINQ. I did a similar "advanced search" function previously, and after a few different attempts found that LINQ was a wonderful tool for this problem, regardless of whether I was hitting SQL with LINQtoSQL or just hitting an in-memory collection of objects.
This worked so well because 1) LINQ is deferred execution and 2) A LINQ query returns another queryable object. The implication here is that you can chain your LINQ queries together as you construct them from your input, instead of having to do a single massive clause translation to SQL or whatever backstore you are using (one of my attempts was constructing SQL clauses with strings, but still passing input data via SQLParameters for SQL injection protection - it was messy and complicated when hand crafted LINQ was orders of magnitude easier to understand and implement).
For example:
List<string> data; // or perhaps your a DB Context for LINQtoSQL?
var query = data.Where(item => item.contains("foo"));
if( {user supplies length search option} )
query = query.Where(item => item.Length < 5);
// etc, etc.
// LINQ doesn't do anything until the query is iterated, at which point
// it will construct the SQL statement without you worrying about details or parameter binding
foreach(string value in query)
; // do something with the results
Because of deferred execution and the queryable return type, you can concatenate LINQ queries to this expression all day long and let it worry about the implementation details (such as converting to a SQL query) at execution time.
I can't provide you with the exact steps that you will need to do, but I HIGHLY suggest looking into asp.net page life cycle. I created a user control as a DLL one time. I had to capture postback data at specific steps in the lifecycle and recreate and rebind the data at other steps. Additionally thinkgs like viewstate are only available at certain points also. I know that I had to override On_init, On_prerender and some other methods.
Sorry I couldn't be more help, but I don't have the code with me (its with an old employer). I hope this helps.
If you are adding controls to the controls tree dynamically, you need to add them on postpack as well. Just call the method that builds the control on Page_Load or Page_Init and the controls should stay on the page on postback.

ASP.NET: Why is "_requestValueCollection" empty on PostBack?

Why is "_requestValueCollection" empty on PostBack?
I have a really strange problem with post backs. In some cases on post backs (this.Request.RequestType == "POST") have null "_requestValueCollection" member. And for ASP.NET that means this.IsPostBack == false.
So I have modified the Page_Load in the following way:
protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack && this.Request.RequestType != "POST")
{
//REGULAR INIT STUFF
}
else
{
//REGULAR SITE POSTBACK STUFF
}
}
What is possible danger of this approach? So far everything is doing OK (and is pretty rich and complicated page).
It isn't clear from your example what you are attempting to do with this code, so this is mostly a short in the dark.
You probably don't need the second part of the if statement. Checking IsPostBack alone should be sufficient.
_requestValueCollection is not a property, it is a field and probably isn't a good place to get at the data submitted by the client. I suggest instead that you consider using the Form property (this.Request.Form) or the Headers property (this.Request.Headers) depending on what you are looking for. Keep in mind that most of the time you can just get form values from the asp.net controls on the form directly.
You may also want to look at the Request.HttpMethod property if you need to determine the exact http method used to invoke the page.
Edit: Adding info about _requestValueCollection
The mechanics behind the _requestValueCollection being loaded are quite complex, but I took a look at the MS source and from what I can determine the page calls on every control on the page that implements the IPostBackDataHandler interface. For each of these it will call the LoadPostData method which adds the data for that control to the collection.
The main things that I can think of off the top of my head that might cause the collection to be null would be:
no server controls on the page implement IPostBackDataHandler
there is no server form, or the contents of the form weren't sent by the client
Alternately, the page may be using query strings to convey the data to the server, and the query string doesn't contain anything
As I said, this is a bit fuzzy. The Page class is very complex internally and so there could be other ways data gets put into that collection too, but this was all I could find on a casual examination.

Javascript interaction between ASP.NET web controls

I have a UserControl A which contains
a dropdown
a placeholder
At runtime the placeholder will be populated with some UserControl B.
There are certain times which I need to trap the javascript onchange event in the dropdown to call a javacript function in B (to do a clientside update of B). What is a good design/practice for how to do this?
The naive way is to make the asp:dropdownlist a public member then send it into a public method of B:
// In controlling code
...
userControlB.Initialize(userControlA.TheDropDownList);
...
// In usercontrol B
public void Initialize(DropDownList dropdownFromA)
{
dropdownFromA.Attributes.Add("onchange", "myBfunction()");
}
But something smells bad with this approach. I would like to keep A and B as loosely coupled as possible. Any better ideas?
To keep them really decoupled you could introduce an observer pattern such as described here. I would have the drop down register it's own change event which would notify the observer that a change occured. Then if any other controls on the client are interested they will enlist to be notified when a specific observation is made.
Edit
Well you could name the variables based on a logical name for the observation, then you'd just check to make sure the observer exists before registering with it.
A different system I have seen used, would be more like an event dispatcher, essentially when you subscribe you provide a name for the event, then you fire you would include two arguments the name of the event, and the data for the event. In this model you would only have a single dispatcher on a page.
Within the DOM I'm fairly sure that all controls are accessible so making the dropdown public isn't really relevant, particularly as control a and control b are members of the same page and so are accessible to each other in your code-behind.
I'd think a more loosely coupled approach would be to have control B register it's method as an event listener on control a's change event. I'm not sure how much more loosely coupled you could make two controls where one depends on changes from another.

Resources