ASP.NET 2.0: Specifying an instance of an object for an ObjectDataSource - asp.net-2.0

I'm using an ObjectDataSource to bind data to a GridView; it works fine except that it always creates a new object to use as a data source. I can do all the setup just fine but I cannot use an instance of an existing object to specify as the "data source" for it. Is it possible to do this? If so, how?
If it's not possible, why?
EDIT: Here's the gist of what's going on (object types changed): On the first page you are editting the attributes for a dog. One of the attributes is "has puppies" and if it's true, the next page you specify the names of those puppies. What's happening in my case is that those puppies are not getting linked to the original dog but to a "new" dog. (The implication that my problem is a "female dog" was coincidental. ;-) )

Create an event handler for the ObjectCreating event on the ObjectDataSource.
You can assign the instance to using the ObjectDataSourceEventArgs property
protected void ObjectDataSource1_ObjectCreating(object sender, ObjectDataSourceEventArgs e)
{
e.ObjectInstance = myObject;
}
Wire this event up in the markup too
<asp:ObjectDataSource OnObjectCreating="ObjectDataSource1_ObjectCreating" />

As I just discovered in my own question here, items stored in the Application Cache are going to pass themselves as a reference for use. You may consider storing your data there (or potentially in the Session as well) and pass items that way.

Related

How do I reference the databound control from an ObjectDataSource event?

Take for example a DetailsView control with an ObjectDataSource as its datasource.
Normally in the DetailsView.ItemUpdated event I would grab a reference to the details view by casting the sender:
DetailsView dv = (DetailsView)sender;
In certain situations it becomes necessary to handle the event inside the ObjectDataSource.ItemUpdated event. In this case sender is now of type ObjectDataSource. What I want to be able to do is write clean code that isnt hardcoded like
Label label1 = DetailsView1.FindControl("Label1");
I looked over the documentation and also did some searches but couldnt find how I would write some code like the following:
protected void ObjectDataSource1_Inserted(object sender, ObjectDataSourceStatusEventArgs e)
{
ObjectDataSource ods = (ObjectDataSource)sender;
DetailsView dv = (DetailsView)ods.SOMETHING_HERE;
}
Does anyone know what I should be putting in the SOMETHING_HERE in the snippet above?
That's happen because the "OnInserted" event is suppose to be an event examine the values of a return value or output parameters, or to determine whether an exception was thrown after an Insert operation has completed. The return value, output parameters, and exception handling properties are available from the ObjectDataSourceStatusEventArgs object that is associated with the event.
What you can do here is just call ObjectDataSource.select() that returns the view in this case but I don't think it's a good choice.
You should review you business logic and try to manage it somewhere it makes more sense
Anyway your code should look like the below:
ObjectDataSource ods = YourDataSource.select();
DetailsView dv = (DetailsView)ods;
Considering the example you provided, I don't think there is anything you can replace for Something_Here. It is the ODS linked to DV and not the other way. Also one DataSource can be linked to several DataBound Controls.
So as far as I know it is simply not possible.

How to bind to a control within an ASP.NET ListView

I have a list that I need to bind to a List I get from an API. The list looks like this:
struct DataItem { int level; string name; Guid key };
List<DataItem> myList = API.GetList();
ListView1.DataSource = myList;
ListView1.DataBind();
All this works fine for display. However, the table must edit the level value. I am unsure how to make that happen. I have tried event handlers on the listView, but they are never called. I have tried a text box for the level field (with both Bind and Eval) and an event handler OnTextChanged, but the event handler is never called. (I have tried with various combiniations of AutoPostBack and ViewState enabled.)
How can I programatically edit this data structure?
Two way data binding you are trying to implement here won't work like this - List doesn't implement INotifyPropertyChanged (someone correct me if I'm wrong).
You may consider using a plain old DataTable which can be two-way-bound out-of-the-box. If performance is not a highly critical issue, converting your List to a DataTable (and back, depending on what you want to do with the modified data) is simple enough, rather than struggling with custom implementations of list types.

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.

Is there a good way to store enums from the database?

I am new to ASP.NET, experienced with WinForms and WPF. Go easy on me.
When my page loads, it hits the database and queries a table for choices to put in a drop down list. Now if you do a postback on the page, do you reload the values in the form_load? It seems unnecessary to hit the database twice. My assumption is that I put the form_load, I hit the database for the enums, then fill the drop down with the values I found.
You control what is called during postback with Page.IsPostBack Property. It returns a boolean indicating when the page is in a postback. Ex:
public partial class _Default : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e) {
if (!this.IsPostBack) {
// fill the enums
}
}
}
Use the Cache object and store the database results in the cache.
I assume you're talking about a "lookup table", basically something that has a schema of {Id, Name} and is referenced as a foreign key from another table, correct?
This is an age-old question, and there's no "right" answer.
If your enumeration is likely to change at all (perhaps it's controlled by an administrative user), you won't be able to use #Andrei Rinea's suggestion, as you'll need to refresh the value from the database. Ultimately, you'll be best off doing as Keltex suggests and Cache the results with a short expiration -- probably as little as 5 minutes. Just that small amount of caching could increase performance quite a bit, if you're under a heavy load.
If your enumeration is unlikely to change... particularly if it's not modifiable through the UI by an administrator, there's a fun trick that I like to do, which is to map the enumeration to an actual C# enumeration, with the value of the enum tied directly to the primary key of the enumeration table. In this way, you never have to hit the database at all to get a list of possible values.
The drawback to this trick is that a new enumeration item requires a new compilation of your code and a new deployment. This may or may not be ideal, so use the trick with caution.
These can be loaded at application startup in the Application object. I suppose they won't change too often.
Then used from there. For such 'catalogs' that rarely change (once per year or less) I often hardcode them into an enum type too.
Edit :
For enums such as PaymentStatus or such, which change rarely or never a c# enum mapped to the catalog having the same numeric values, as Randolpho said is ok. For others cache in the HttpRuntimeCache object ("Cache") and put either an absolute expiration either an SqlDependency

asp:DropDownList Error: 'DropDownList1' has a SelectedValue which is invalid because it does not exist in the list of items

I have a asp.net 2.0 web site with numerous asp:DropDownList controls.
The DropDownList control contains the standard info city, state, county etc... info.
In addition to the standard codes the site also has custom codes that the users can configure themselves.
For example a animal dropdown may contain the values Dog, Cat, Fish, ect...
I am popluating the DropDownList from a SQL 2005 table that I created e.g. tblCodes
Everything works great and users are able to add orders using the numerous DropDownList controls to choose items from the list.
The problem occurrs if a user wants to change one of their custom dropdowns. For example a user would like to change the verbage
on a animal type control from Dog to K9. This is where the problem starts.
For all new orders the drop down works fine. When the user retrieved an old order
I get the following error in the C# codebehind
"'DropDownList1' has a SelectedValue which is invalid because it does not exist in the list of items."
What's happening is the old order has a database field value of Dog and the DropDownList no longer has Dog in its list since the user changed it to K9.
Any ideas on a workaround?
Is there a way to make the asp:DropDownList accept items not seeded in its list?
Is there another control I could use?
I solved this exact same problem just two days ago. First, I moved the code that set the SelectedValue to a PreRender handler for the DropDownList. Then, I add logic to first check to see if the value is in the drop down list. If not, I add it.
Here's my code. ddSpecialty is my drop-down list, populated with "specialties" from the database. registration.Specialty is the specialty that the user chose, which may or may not be in the drop down, since that particular specialty may have been deleted since they last chose it.
protected void ddSpecialty_PreRender(object sender, EventArgs e)
{
if (!ddSpecialty.Items.Contains(new ListItem(registration.Specialty)))
ddSpecialty.Items.Add(registration.Specialty);
ddSpecialty.SelectedValue = registration.Specialty;
}
I've become very fond of the following little snippet for setting DropDownList values:
For non-DataBound (eg Items added manually):
ddl.SelectedIndex = ddl.Items.IndexOf(ddl.Items.FindByValue(value));
For DataBound:
ddl.DataBound += (o,e) => ddl.SelectedIndex = ddl.Items.IndexOf(ddl.Items.FindByValue(value));
I sure do wish though that ListControls in general didn't throw errors when you try to set values to somthing that isn't there. At least in Release mode anyways it would have been nice for this to just quietly die.
Your SelectedValue should be a unique id of some sort, that doesn't change. The Text value that gets displayed to the user is something seperate, and can change if necessary without affecting your application, because you associate the id with your Order, not the displayed string value.
I'm not sure it's the same issue, but I had a similar sounding issue with trying to bind a DropDownList that I wanted to contain in a GridView. When I looked around I found a lot of people asking similar questions, but no robust solutions. I did read conflicting reports about whether you could intercept databinding, etc events. I tried most of them but I couldn'f find a way of intercepting or pre-empting the error.
I ended up creating a subclass of the ddl, intercepting the error from there hacking a fix.
Not tidy but it worked for my needs. I put the code up on my blog in case it's of help. link text
Check this:
http://www.codeproject.com/Tips/179184/ASP-dropdownlist-missing-value-error.aspx
Ran into this myself. Oddly, ddl.ClearSelection(); didn't work. Had to use ddl.SelectedValue = null
Also noticed, that this must come AFTER I clear the items from the list ddl.Items.Clear(); which also seems weird. Setting the SelectedValue to null, then clearing the items still threw the error.
Once this is done, re-bind the list and re-select with new value.
Try this:
if (ddl.Items.Contains(new ListItem(selectedFacility)))
ddl.SelectedValue = selectedFacility;
I have made a workaround after having this problem very often. Unfortunate that MS still did not recovered this issue.
Anyway, my workaround is as follows.
1) I bind the data to the ToolTip property of the DropDownList
<asp:DropDownList ID="edtDepartureIDKey" runat="server" CssClass="textbox"
ToolTip='<%# Eval("DepartureIDKey") %>' DataSource="<%# DLL1DataSource() %>" DataTextField="DisplayField" DataValueField="IDKey"
onprerender="edtDepartureIDKey_PreRender">
2) On the prerender event i check the availibilty of the data, and if it is not in the list I simply add it, then set the selectedindex to the data valuei which I saved in ToolTip property
protected void edtDepartureIDKey_PreRender(object sender, EventArgs e)
{
DropDownList ddl = (sender as DropDownList);
if (ddl.Items.FindByValue(ddl.ToolTip) == null)
{
//I am pulling Departure Data through the ID which is saved in ToolTip, and insert it into the 1st row of the DropDownList
TODepartureData v = new TODepartureData(DBSERVER.ConnStrName);
TODeparture d = v.Select(Convert.ToInt32(ddl.ToolTip));
ddl.Items.Insert(0, new ListItem(d.DeptCode, ddl.ToolTip));
}
ddl.Items.FindByValue(ddl.ToolTip).Selected = true;
}

Resources