ASP.Net - Two way databinding of a single entity - Options, best way...roll your own? - asp.net

I have been searching around to find the best option of doing this.
Basically, I want to do two way databinding of multiple controls (textbox, dropdownlist, checkbox, etc) to a single instance of custom class/entity, ie: Person.
It seems, the (only?) way to do this is using an like so:
<asp:FormView ID="FormView1" runat="server" DataKeyNames="OrderID"
DataSourceID="SqlDataSource1" DefaultMode="Edit">
<EditItemTemplate>
OrderID:
<asp:Label ID="OrderIDLabel1" runat="server" Text='<%# Eval("OrderID") %>' />
<br />
CustomerID:
<asp:DropDownList ID="CustomerIDDropDownList" runat="server"
DataValueField='CustomerID' DataSourceID="CustomerDataSource"
DataTextField="CompanyName"
SelectedValue='<%# Bind("CustomerID") %>'
/>
EmployeeID:
<asp:TextBox ID="EmployeeIDTextBox" runat="server"
Text='<%# Bind("EmployeeID") %>' />
<br />
Some issues:
- This is limited to using an ObjectDataSource control (ie: can't just use an instance of the desired class in the code behind)
- Forces you to define a second (likely identical layout) read only template....would be nice to have some some mechanism that could intelligently render a read-only view derived from the edit template.
- The binding declaration Text='<%# Bind("EmployeeID") %>' is loosely typed, so vulnerable to spelling errors
- etc
So my first question I guess is, is an asp:FormView the only way in ASP.Net to do declarative databinding of a single entity?
Secondly, how feasible would it be to hand roll some sort of a two way binding mechanism? I guess it would have to be reflection based, but I could live with that. Anyone recommendations on how one would declare the binding relationships in the aspx page? Would the proper way be like:
Text='<%# MySuperDuperBind("EmployeeID") %>'
And then somewhere (where?) my MySuperDuperBind implementation will get called as the page is rendered....how this is done is a bit beyond me though. And if I want to render in readonly, I can call a secondary function that will remove the editable UI control from the form and replace it with the corresponding read only version (ie: a Textbox is replaced with a Label).
Another alternative route is getting away from webforms and going to a client side templating solution such as this very nice looking solution:
http://weblogs.asp.net/dwahlin/archive/2009/05/03/using-jquery-with-client-side-data-binding-templates.aspx
However, I have no clue how to write the asp.net webservices properly in order to retrieve and save data in this type of an architecture.
Ideas?

is an asp:FormView the only way in
ASP.Net to do declarative databinding
of a single entity?
There's also DetailsView but it has the same issues.
I've mostly given up on 2-way databinding. It's great for prototyping and gets me 80-90% of the way to a complete solution but the last 10-20% is a nightmare. Binding any non-trivial object always seems to involve so many event handlers to customize behavior that it feels like spaghetti code to me.
I usually have two methods:
MapEntityToView(entity)
MapViewToEntity(entity)
that I call to display the entity and to populate from the page, respectively. It can be tedious to write but I don't have to wrestle with data binding issues.
I do use 1-way binding extensively for read only pages and displaying items in list controls.

Related

Asp.Net page rendering and UI controls modularity

the website I'm currently developing can display dynamically-built forms.
A form is composed of fields, which are created directly by the users and can be displayed as one of multiple types that we support (text box, list box, tickbox, radiobuttonlist etc.). The rendering logic uses a repeater that iterates over a collection of all the fields defined by the user.
Inside the repeater (directly in the aspx page), one instance of each of the types we support is defined.
<asp:Repeater ID="fieldRepeater" runat="server">
<ItemTemplate>
<asp:TextBox ID="textBox" runat="server" />
<asp:DropDownList ID="dropDownList" runat="server" />
<asp:CheckBox ID="checkBox" runat="server" />
<asp:RadioButtonList ID="radioButtonList" runat="server" />
[...]
</ItemTemplate>
</asp:Repeater>
During the loading, we figure out which control is required and actively hide all the other ones.
Being still new to the web based development world, this approach seems very odd to me. My guts would prefer keeping the UI clean and instanciate exactly the controls that are required in CodeBehind and not start "playing" with visibility... but the current approach has some obvious benefits as well.
Is it really how one would do it in a web app?
Are there some best practices here?
Thanks!
I have no idea what the best practice is here, but I have done something similar before in a previous project and tried both approaches. Both will work.
Creating the controls in code-behind can be fiddly, especially if you are having to deal with post-backs. The controls have to be created in OnInit, as otherwise they won't get the posted form values and viewstate populated. This will cause complications if any of the control creation is based on the values of other controls, as you won't known the values without manually delving into the posted form values.
The only practical disadvantage with your current approach that I can think of is that all four controls (TextBox, DropDownList etc.) have to be instantiated and processed server-side by ASP.Net, which is a bit of a waste of resources. But it's probably not too significant; maybe do some profiling to see. I do agree that it seems a bit odd though, it doesn't feel very "clean".
As you said you're new to web development, then I would recommend continuing with your current approach of including all the controls and hiding the irrelevant ones. I just found it simpler when I did, even though it may not seem as nice.
Good luck!

Reducing load times of ASP.NET WebForms page with large tables

I have a WebForms page with a treeview on the left and grids on the right. When the user clicks a treeview node, the corresponding grid is populated using a SqlDataSource and then displayed. The whole thing's in a single UpdatePanel.
Here's my setup:
<asp:GridView runat="server" ID='LocationsRowGrid' AutoGenerateColumns="false" DataSourceID="SqlDataSource_LocationRow">
<Columns>
<asp:TemplateField HeaderText="Location">
<ItemTemplate>
<asp:DropDownList runat="server" ID="NAME_LCTN" OnDataBound="dropdown_DataBound"
DataTextField="NAME_TO_LCTN" DataValueField="NAME_TO_LCTN" DataSourceID="SqlDataSource_LocationNames">
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Move Time (HR)">
<ItemTemplate>
<asp:TextBox runat="server" ID="STD_MOVE_TME_AMNT" Text='<%# Bind("STD_MOVE_TME_AMNT") %>'></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="LAST_UPDATED_BY" HeaderText="Updated By" Visible="true" />
<asp:BoundField DataField="LAST_REV_DT" HeaderText="Revision Date" Visible="true" />
</Columns>
</asp:GridView>
There are other (larger) grids, but this is basically the template. The largest grid has about twelve columns, about six of which are templatefields with textboxes and one of which is a templatefield with a dropdown list. The dropdown is databound to another table, which has about 150 elements. The grid itself has about 100 entries.
This is slow. It seems like the problem might have to do with the rendering of the HTML - the server isn't taking TOO long to respond, but the browsers (Chrome and IE) are nearly falling over trying to render the result. My first (obvious) guess is that rendering 100 html selects, each with > 100 elements, is going to slow - especially when done all at once inside tables tags like ASP.NET will do.
Does this seem like a reasonable guess at the cause of the slowness?
For this project I am (currently) not allowed to use jQuery (or presumably any other javascript library) and must justify any and all javascript I use. Basically, other developers don't want to need any real understanding of javascript to be able to maintain this application when I'm done with it.
Given these constraints, is there anything I can do to reduce the size of the returned HTML and/or the render times in the browser? Thanks in advance.
My thought is reduce the amount of bound data on the initial page and institute paging. Unless this is a "report", the user does not need to see every row at one time.
Another possibility is you have the page set to also use viewstate for the grid. If so, you are consuming time in the bind to create the viewstate prior to rendering (at least in the default situation).
Beyond that, I agree with #n8wrl that you need to troubleshoot by isolating whether it truly is the rendering that is the issue. I would probably do this through tracing rather than turning things off, but you do have to make sure the problem is the rendering. Another control, like a repeater, may work, but I only see this as a benefit with something like CSS, which reduces the amount of tagged data to produce output.
Compressing the response stream in IIS can also speed things up. Rendering time will still be the same, but you will eliminate the time to send the HTML to the browser, which is at least part of your problem.
Several thoughts for you:
'Turn off' the rendering to see how much of the response time is in server-side querying. You can do this by commenting out DataSoource= statements.
Browsers tend to wait until an entire table has made it before rendering any of it. You might try different layouts such that not everything is in a single table. Maybe a repeater where each item is a stand-alone table? Each can then render as the markup appears.
You can start to get a lot more fancy with jQuery and AJAX to page your content. Instead of 100 rows maybe 10 rows with page 1, 2, 3... links?

Is there a better way to prepopulate fields?

I am trying to create an edit form with the database values pre-populated in the front end. Right now I have lots of literal controls that act like placeholders and I assign the values for those on page load.
Is there a better way to do this? Or, is this the standard way of doing it?
Use databinding on the actual form fields. The syntax will vary depending on what your data source is, but in general it's something like this:
<asp:TextBox id="LastName" runat="server"
Text='<%# DataBinder.Eval(MyDataSource.LastName) %>'>
</asp:TextBox>

Two-way data binding of controls in a user control nested inside a FormView doesn't work

I'm trying to perform two-way data binding on the controls in my user control, which is hosted inside a FormView template:
<asp:ObjectDataSource runat="server" ID="ObjectDataSource"
TypeName="WebApplication1.Data" SelectMethod="GetItem" UpdateMethod="UpdateItem">
</asp:ObjectDataSource>
<asp:FormView runat="server" ID="FormView" DataSourceID="ObjectDataSource">
<ItemTemplate>
<uc:WebUserControl1 runat="server"></uc:WebUserControl1>
</ItemTemplate>
<EditItemTemplate>
<uc:WebUserControl1 runat="server"></uc:WebUserControl1>
</EditItemTemplate>
</asp:FormView>
The web user control:
<%# Control Language="C#" ... %>
<asp:TextBox runat="server" ID="TitleTextBox" Text='<%# Bind("Title") %>'>
</asp:TextBox>
The binding works fine when the FormView is in View mode but when I switch to Edit mode, upon calling UpdateItem on the FormView, the bindings are lost. I know this because the FormView tries to call an update method on the ObjectDataSource that does not have an argument called 'Title'.
I tried to solve this by implementing IBindableTemplate to load the controls that are inside my user control, directly into the templates (as if I had entered them declaratively). However, when calling UpdateItem in edit mode, the container that gets passed into the ExtractValues method of the template, does not contain the TextBox anymore. It did in view mode!
I have found some questions on SO that relate to this problem but they are rather dated and they don't provide any answers that helped me solve this problem.
How do you think I could solve this problem? It seems to be such a simple requirement but apparently it's anything but that...
My current workaround for this is, although rather cumbersome, to subclass the FormView class and use subclassed controls in it, implementing my own data binding logic (taking the data field name from a new property) instead of using the <%# %> syntax. Apparently, the code the latter generates is the real culprit here as it doesn't support this nested control scenario.
I ended up, using old asp include statement
<--%include file = "filename" -->
instead of using user controls for dealing with the code duplication issue.

How can I use the dropdownlist to populate/enter data?

Here's my existing code:
<asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="True"
DataSourceID="dsEmployees" DataTextField="Last_First"
DataValueField="EmpNum"
onselectedindexchanged="DropDownList1_SelectedIndexChanged">
</asp:DropDownList>
Yonita, you need some more moving parts. You need a datasource to bind to, for instance.
Have a look at the Data Access tutorials on the ASP.NET website:
http://www.asp.net/learn/data-access/
DropDownLists end up being rendered as <select> tags in HTML. These do not allow for data entry of new values. If you're looking for something similar to a ComboBox (a textbox and a listbox combined into the same control) then you'll need to find a third-party javascript implementation that is acceptable to you; there is no control which provides that functionality in HTML or the .net framework.

Resources