Retrieving keys and NewValues within a Formview with manual data binding - c#

I have a Formview binded in the code file to a generic list. Now, upon editing of a record, I wish to access the Keys and NewValues out of the FormViewUpdateEventArgs parameter of the ItemUpdating event handler method.
From what I've tried and searched over the internet as of now, I've come to know that updated values are only available if the Formview is set a data source control on the markup page else they'd be null. Is this true?
Secondly, at this moment I am casting the sender object to formview and individually filling each object property by using FindControl method to find and retrieve values present in the controls. Is this the best way to do this task?
As an example, this is what I am doing atm:
FormView currentForm = (FormView)sender;
ListObject.ID = new Guid(((HiddenField)(currentForm.FindControl("hdnID"))).Value);
ListObject.Name = ((TextBox)(currentForm.FindControl("txtName"))).Text;
Thanks for the help fellas!

Based on what your doing I would suggest you not use a FormView. FormView's are brilliant when working with datasources, but fail, when dealing with manual bound data the way you are, your basically overriding and manually building the form, and it would be simpler to just create a HTML form and ASP.Net Server Side Controls.
FindControl is an expensive operation and can become unwieldily. Simple assigning a value during the loop of your data to a server side control will be faster.
Alternatively as suggested, use a ObjectDataSource and bind your data to the FormView in that way.

Related

Get all items from Repeater's datasource when using pagination

I've got a Repeater control, bound to a PagedDataSource, which datasource is a list of custom controls I've made. These custom controls contains a couple of text boxes.
I have a save button, and when it is clicked I want to save the data in all the custom controls to a database, no matter which page they are on - but currently I only got access to the custom controls displayed on the current page.
What I've tried to do is to, in the btnSave_Click event, create a new temporary datasource equal to the current one, except its not a PagedDataSource. That way my repeater contains all custom controls - BUT - the changes made in the textbox fields are no longer available. I then tried to add JavaScript onchange events on the textboxes in the custom control, so that a postback would be fired whenever text was changed, and the property in the user control codebehind would be updated. This didnt work either.
Any ideas?
save the changed values on each page index changing event (or prev /next buttons) into your persistance object (List)
http://www.dotnetfunda.com/articles/show/1611/how-to-select-multiple-records-from-multiple-pages-of-the-gridview-and
The reason your non-PagedDataSource is empty is because the changes in your text box exist in the client and not on the server - you'll need to synchronise the values from your controls with the empty slots in your repeater.
The Repeater does not have built-in Pagination (like the GridView or other complex controls) so it does not offer events such as the PageIndexChanging event. I assume therefore, that you have your own Page navigation implementation. You should therefore call the function you have presented within that implemented function.
Try Using a generic List and Skip and Take methods of that

Where to store web custom control data

I am creating a custom control extending WebControl. This web control allows the consumer to define a collection of columns in markup, something like this:
<Custom:CustomGrid>
<Columns>
<Custom:DataColumn HeaderText="FirstName" />
<Custom:DataColumn HeaderText="LastName" />
</Columns>
and put an IEnumerable in a DataSource property and this is rendered out to a table.
This control also allows paging. The IEnumerable in DataSource is the full list, and I display a page of the list at a time. I am already saving the current page, number of rows per page, etc. to viewstate. Should I also put the full list in viewstate? Maybe session?
This list can become a bit hefty. Maybe save in session with a random key, which is saved in viewstate?
What is the best practice here?
Edit: I don't think it's right to impose that all types in the IEnumerable be serializable. Is that fair? So do I need to copy the data source to some other data structure for serialization?
Edit 2: Even if I do use a base control instead of implementing RenderChildControls I will need to implement CreateChildControls, but I will still need to persist the data somewhere, or did I miss the point of the base class?
Indeed, not all IEnumerable instances will be serializable.
If the query is cheap to run I wouldn't persist the whole data set but just run the query again for a different page or a change in the sort order.
If you put the data in viewstate you'll end up with huge pages. Session state might be acceptable if you don't have many users, but large data sets with lots of users won't scale well. What if I bind a million rows to your control? Or what if your control was used in a repeater and shown 100 times on a page?
Are you sure you need to persist the data? This isn't premature optimisation is it?
Remember that your control is a UI component. The viewstate should hold enough information to maintain the UI state as it is. A change in state (e.g.: switching to a different page of results) is something for which your control should pass responsibility to the data source.
Take a look at good old GridView. It displays what you give it and remembers that. If you're using paging then it raises an event to say "the user has changed page; give me page x of data". For me, that's the best practice for a UI control.
For implementing databound control it is better to use base class which was designed to perform such task. For example in ASP.NET exist CompositeDataboundControl which can be used as a base class to implement custom data bound controls. I can advice to review the following Dino Esposito article:
http://msdn.microsoft.com/en-us/library/aa479016.aspx.
Basically if you create control like ASP.NET gridview then it is store values in viewstate. To be more clear it is create number of the DataRow controls which saved assigned values in viewstate. During postback it recreates the same number of rows and values are restored from viewstate. If you will save only datasource for example in session without using viewstate then you will need to redatabind data to your grid during every postback. So, if you create Server control similar to gridview then approach described in the Dino Esposito post will be very helpful because it shows how to create control similar to ASP.NET Server GridView control.

How do I show EmptyDataText only after the user submits the form?

I just created a basic ASP.NET website using Microsoft's walkthrough here. It has one page with a form that takes in some text input, runs a database query based on that, and results the results in a GridView. I added the EmptyDataText property to my GridView to explicitly show users when their search returns no results.
It all works as expected with one exception:
IIS shows my EmptyDataText of "No results found." even before the search form is submitted.
This defeats my purpose behind using EmptyDataText, which is to indicate to the user that the webpage successfully submitted their search but found no results, as opposed to took their search and threw it into the ether.
For example, a user who searches for something that cannot be found will see "No results found." both before and after their search, as opposed to nothing before and "No results found." after. The former behavior gives the impression that the search didn't work.
How can I configure my GridView to show the EmptyDataText only after the search form is submitted?
you are using sqldatasource that will bind automatically while loading the page. Bind the gridview programatically while clicking the search button
Don't bind your GridView until after the user has initiated a search. When you bind your GridView with a datasource that has 0 records, then the EmptyDataText will be displayed.
Chances are that you are binding it on Page_Load.
EDIT
Wherever a DataBind() is performed in your code (other than the action handler), remove it. Your DataBind() should only occur in the handler that receives the user action.
If Visual Studio is doing some voodoo behind the scenes with automatic binding, you can always default the grid to invisible. Make it visible when the user initiates a search.
Just don't databind it before the search, it will effectively be completely invisible until then.
UPDATE: maybe you are using a DataSourceID (which databinds automatically)?
UPDATE 2: First off, for what ever reason was the downvote (at least have a decency to leave a comment)? If it weren't for me the OP would still not have known where the problem lies - and secondly, just remove the DataSourceID property from the declaration, and set it back from codebehind when the user makes a search (you might want to call the GridView DataBind() method manually after that, but only if it doesn't do that on its own - try it without first).
As the other answers suggested, the GridView is being bound before the user makes a search because it has a DataSourceID attribute. As explained on MSDN, this attribute causes the GridView to automatically bind to the specified source:
To bind to a data source control, set the DataSourceID property of the GridView control to the ID value of the data source control. The GridView control automatically binds to the specified data source control and can take advantage of the data source control's capabilities to perform sorting, updating, deleting, and paging. This is the preferred method to bind to data.
To get the behavior I was looking for, I removed that attribute from the GridView and instead added an OnClick attribute to the submit button for my search form. The OnClick attribute refers to a method BindGridView that gets called only when the user submits the form.
All this method does is populate the DataSourceID with the same value it had before as an attribute:
public void BindGridView(object sender, EventArgs e)
{
GridView1.DataSourceID = "DataSourceID1";
}

C# WinForms: How to enforce the DataGridView to bind its data from the data source

I have a windows form that contains a gridView for some orders.
I aimed to have a constructor of the form that takes an order ID, and the constructor will be responsible for selecting that order in the gridView.
but I've noticed that the gridView -while the execution of code is in the constructor- is empty! although the InitialComponents() had invoked!
so, I want a way to enforce the gridView (or the dataSource) to bind their data (like the DataBind() method in web forms)
I know that I can achieve my goal in many ways, but I want this way to be used to improve my DataBinding information.
The dataSource type is ObjectDataSource and the object is LinqDataContext.
thanks..
Are you using a BindingSource object? If not, are you setting both:
(1) DataSource
(2) DataMember
appropriately?

How do you manually modify a bound object with a FormView?

I am using a FormView with an ObjectDataSource. When the save button is clicked, I would like to modify the data bound object before it gets set to the ObjectDataSources Update method.
I tried the FormView's Updating event as well as the Object Data Source's Updating event but I can't figure out how to access the data bound object. FormView.DataItem is null in those events.
Or in other words, I would like to intercept and modify the DataItem before it gets passed to the ObjectDataSource UpdateMethod.
To give a little more detail on why I want to do this, there are some values on the form which can't be databound with the build in functionality. One of the controls is the checkbox list. I am using the DataBinding event to populate the checks, but now I also need a way to update my object to reflect the form values. There are also other controls with similar situations.
I know this is an old question, but I had the same problem, and found the answer I think Bob's looking for.
The solution is to use the ObjectDataSource Updating event on the Web Form. The Updating event includes the ObjectDataSourceMethodEventArgs object as a parameter. The ObjectDataSourceMethodEventArgs class includes a propery named "InputParameters", and you can use that to access the data object and modify the contents before the update occurs. You need to convert the InputParameters object to an OrderedDictionary type first (full namespace is System.Collections.Specialized.OrderedDictionary)
It looks something like this:
protected void myObjectDataSource_Updating(object sender, ObjectDataSourceMethodEventArgs e)
{
OrderedDictionary parameters = (OrderedDictionary)e.InputParameters;
MyDataObject updatedData = (MyDataObject)parameters[0];
DropDownList myDropDown = (DropDownList)FormView1.FindControl("myDropDown")
updatedData.SomeDataValue = myDropDown.SelectedValue;
}
Why don't you just write your own business object (aka ObjectDataSource), and wrap the original ObjectDataSource object? You can then intercept anything you want, and modify it enroute to the original ObjectDataSource object's Save method.
DataItem is only available when DataBinding.
Data is then bound to controls inside your FormView.
Use myFormView.FindControl(string id) to access bound values before Updating.
If two-way databinding won't work for you, you should instanciate your object, populate manually the properties and then update or commit the changes.
Since you are in the Updating event, FormView.DataItem is null because data binding has not yet occurred. You have to access the data via the form control containing your data of interest.
Try applying your data modification during the OnDataBinding event of the relevant control.

Categories