ASP - Georgenet.net

baasopchoppyΑσφάλεια

5 Νοε 2013 (πριν από 3 χρόνια και 9 μήνες)

134 εμφανίσεις


1

http://www.takempis.com/aspnet_fundamentals.asp


ASP.Net

Fundamentals

It's not Magic
-

It's Slight
-
of
-
Hand!

by Uncle Chutney


Table of Contents:




Introduction




HTTP Thin
-
client Applications




HTTP State Considerations




How ASP Maintains State




How
ASP.Net

Maintains State




How ViewState Works




ASP.Net

and Events




A
SP.Net

Controls




Conclusions


Introduction:
After working with
ASP.Net

for over a year, and participating in the Microsoft
ASP.Net

newsgroups for
quite awhile,
I have observed that many people who are new to
ASP.Net

are having some fundamental difficulties
understanding how it actually
works
. This is particularly important with
ASP.Net
, much more so than with
ASP
. Why?
Because
ASP
has a fairly straightforward app
roach to creating dynamic content, and is procedural.
ASP.Net

is object
-
oriented, and has a number of features built in which seem to confuse people. For example, with
ASP
it was fairly
obvious to most of us that there is an impenetrable gulf between the s
erver and client, because HTTP is stateless,
meaning that the browser and server only respond to individual page requests, and do not maintain any kind of state
between requests. But Microsoft did some fancy tap
-
dancing, and came up with an event
-
driven ob
ject model which
seems

to eliminate this gulf, when, in fact, it does not. It simply
works around

the gulf. For some, understanding
object
-
oriented programming

concepts has turned out to be very difficult. However, as Internet programming
becomes more and
more powerful, the organization that
object
-
oriented programming

affords will prove out. For
those of you unfamiliar with
object
-
oriented programming
, check out my
ASP Programming Fundamentals

art
icle.

The purpose of this article is to give a little look "under the hood" of
ASP.Net
, to familiarize you with the similarities
and differences between
ASP.Net

and
ASP
. You may be surprised to discover that the 2 technologies are not really
that much dif
ferent. If you are unfamiliar with the fundamentals of
ASP
, you should read the beginning
ASP
tutorials
on this web site first, as this article will not reiterate those points, but will focus instead on the similarities and
differences between
ASP
and
ASP.
Net
. We will begin, however, with a review of the underlying technology, including
the basics of
HTTP Thin
-
client Applications
.

HTTP Thin
-
client Applications:

HTTP is a protocol for transferring data between a web server and an HTTP client
application. The

most commonly
-
used
HTTP client application

is a Web Browser. A Web Browser is a "
thin client
"
meaning that it contains virtually no code for doing much of anything but making requests to a
server
, executing
certain kinds of code, such as
JavaScript
, in an

HTML page, and displaying HTML documents. The concept of a
thin
-
client application

is that the
server
does all of the processing work, and delivers content in the form of HTML to
the client, which simply renders the HTML output from the server. The
client

browser can have HTML elements in it
for uploading data with its request to the server, such as
Forms
,
Query Strings
, and
Cookies
. But, other than some
client
-
side
JavaScript
(or
Java Applets
,
ActiveX Controls
,
SWFs
, etc.), the browser does very little pr
ocessing.

HTTP State Considerations:
HTTP is stateless, meaning that when the browser makes a request for a page, script,
or whatever, it retains no knowledge of the currently loaded document, nor does the
server
. Each document is loaded
into memory by its
elf as it is received from the server, and unloaded with the next request. The
server
, likewise,
keeps no record of the past requests, but receives each request as if it were brand new. This means that maintaining
state (persisting data between page reques
ts) is a problem. A number of workarounds have been developed over the
years, for the purpose of
emulating

state between requests. These include
Cookies
, passing data in
Query String


2

parameters, Form post data, and the concept of
Sessions
.
Sessions
are a b
it different, however, as they reside on
the
server
. A
Cookie
is created on the client with the
Session ID
, to maintain the
Session ID

from one request to the
next, and the actual
Session

data is stored on the
server
. However, note that each of these solut
ions doesn't actually
bridge

the client
-
server gap, but
emulates

a bridge, by

passing data back and forth

between the
client
and
server
.
This is possibly the most important concept that you can grasp here, as much of what follows is built on this
foundatio
n.


Now, while state can't be maintained on the
client
side, it
can

be maintained on the server side, via a couple of
possible alternatives:

1.

Data
passed back
from

clie
nt
browser is passed back
to

client
browser.

2.

Data
can be stored in memory on the
server
:
Application State
,
Session State
, other
Cache
objects,
database
, file system

Note that so far, we are talking about both
ASP
and
ASP.Net
, as the environment hasn't c
hanged; only the
programming model. This is very important to keep in mind!

How ASP Maintains State:
One of the biggest differences between
ASP
and
ASP.Net

is that in order to do
something as simple as maintaining the selected index of a drop
-
down list box

("
select
" object), you had to cook up
your own code to do it. What you would do is to use the
Request Collection

to get the selected item from the drop
-
down list box, and write
ASP/HTML

code that wrote "selected" as an attribute of the appropriate drop
-
do
wn list box in
your HTML. See the following code illustration:

<%

Dim strSelection


strSelection = Request.Form("mySelect")


%>

<select size="1" name="mySelect">



<option value="This" <%if strSelection = "This" then Response.Write "selected"%>>This




</option>



<option value="That" <%if strSelection = "That" then Response.Write "selected"%>>That



</option>



<option value="The Other" <%if strSelection = "The Other" then Response.Write
"selected"%>>The



Other</option>


3

</select>

As you c
an see, this is fairly straight
-
forward, but if you have a lot of state to maintain, it can get quite verbose.

How
ASP.Net

Maintains State:
When Microsoft developed
ASP.Net
, they analyzed the various types of common
functionality which ASP programmers have

had to incorporate into their applications, and developed the
ASP.Net

object model around this. Because
ASP.Net

is object
-
oriented and event
-
driven, classes were developed which would
handle this sort of thing automatically. For this reason, and several o
thers we will explore later, Microsoft developed
Web Controls

and

HTML Controls
. We will see that all of the differences in the programming interface add up to the
same basic operation as
ASP
for maintaining state.

ASP.Net

adds a hidden form field to a
Web
Form
, called "
__VIEWSTATE
". This form field corresponds to a
server
-
side

object called
ViewState
. The
ViewState
object is a
Collection
of values from the form, which includes the
values of all
Web Controls

and
HTML Controls

which have been set to maintain
their state
1

between
PostBacks

(a
"
PostBack
" is simply the posting of the
WebForm
back to itself).

How ViewState Works:

Here's how it's done. When the
WebForm's

HTML output is streame
d to the browser, the
hidden "__VIEWSTATE" field is added to the form. When the form is posted back to the server, the
Request.Form
Collection

(same as
ASP
) contains the values of the posted form. The
Server Control

reads the form POST data,
extracts the v
alues, and updates (rewrites) the
ViewState
value to be sent back to the client. At the same time, the
Server Control
adds the appropriate HTML to the HTML object text to "set" it in it's proper (remembered) state, that
is, the state the form field was in
when the form was posted. In essence,
ASP.Net

is doing the same thing that
ASP

does, although you don't have to write all that code to make it so.


ASP.Net

and Ev
ents:

Another new feature of
ASP.Net

is
Events
.
Events
have been around for quite awhile in terms
of
object
-
oriented

programming, but as
ASP
was not
object
-
oriented
, this was not available. An
Event
is a
message, of sorts. Basically, what happens is this:
When something happens, whether it is something a User has
done through an interface, or something internal to a program's logic, the
object
which hosted the action sends a
message

to the
Platform
. This message is in the form of an
Event
object, which cont
ains certain data about the
object which spawned the
Event
. Any
object
which hosts an
Event Handler Method f
or that object's Event will be
notified of the
Event
by the
Platform
, and the
Event Handler Method

is fired when the
Event
is "raised."

Of course, t
his brings up the question: How can an
Event
which occurs in a
client
-
side

browser, which is
disconnected from the
server
, be recognized by the
server
, and handled appropriately by both the
server
and the
browser? And of course, the answer is obvious: An
E
vent
is a message. The browser sends a "message" to the
server with each
Request
. The
Event
can be communicated to the
server
in the
Request
. And the
server
can then
render the appropriate HTML back to the browser according to the
Event Handler
, thus havin
g the browser "react" to

4

the
Event
as well.

In fact, this is exactly what Microsoft designed into
ASP.Net
. When you create a
WebForm
page with Server Controls
in it,
ASP.Net

adds several other hidden form fields to the page, as well as
JavaScript
"
onclick
"

(for the most part
-

a
select object, for example, has an "onchange"

Event Handler

added to it))
Event Handlers

that call a
JavaScript
function called "
__doPostBack()
"
2
. The form fie
lds are called "
__EVENTTARGET
" and "
__EVENTARGUMENT
". The
following code was copied from the HTML of an
ASPX
page:

<input type="hidden" name="
__EVENTTARGET
" value="" />

<input type="hidden" name="
__EVENTARGUMENT
" value="" />

<input type="hidden" name="__VI
EWSTATE" value="dDwxMzkwODg5OTYwO3Q8O2

w8aTwxPjs+O2w8dDw7bDxpPDE+O2k8NT47aTw3Pjs+O2w8dDxwPGw8aW5uZXJodG1sOz47

bDxTYXR1cm4gb2YgS2Fuc2FzIENpdHk7Pj47Oz47dDw7bDxpPDE+Oz47bDx0PDtsPGk8MT4

7PjtsPHQ8O2w8aTwwPjtpPDE+Oz47bDx0PDtsPGk8MT47PjtsPHQ8dDw7O2w8aTwwPjs+Pjs

7
Pjs+Pjt0PDtsPGk8MT47PjtsPHQ8dDw7O2w8aTwwPjs+Pjs7Pjs+Pjs+Pjs+Pjs+Pjt0PHA

8cDxsPFZpc2libGU7PjtsPG88dD47Pj47Pjs7Pjs+Pjs+PjtsPHJhZGlvU25hcDtyYWRpb1

Njcm9sbEhvcml6O3JhZGlvU2h1dHRlcklyaXM7cmFkaW9EaXNzb2x2ZTtyYWRpb1Njcm9sb

FZlcnQ7cmFkaW9TaHV0dGVySG9yaXo7Pj4KEPaAB
1EZ35xbda79s7LeNJzpXw==" />


<script type="text/javascript">

<!
--

function __doPostBack(eventTarget, eventArgument)

{

var theform = document.Form1;

theform.__EVENTTARGET.value = eventTarget;

theform.__EVENTARGUMENT.value = eventArgument;

theform.submit();

}

//
--
>

</script>

When you add a
server
-
side

Event
to a
Server Control

or
HTML Control
, for example, an "
onclick
" event to a
button,
ASP.Net

automatically adds a

client
-
side

"
onclick
" event handler to the HTML for the object
2
. The
Event
Handler
calls the __doPostBack() method, passing the
id
of the
Control
which fired the event in the
"
__EVENTTARGET
" field, along with any special "
__EVENTARGUMENT
" data that may be needed on the server

side. Note that the
__doPostBack() Method

submits the form back to the
server
, creating a
Request
which contains
the event data in the hidden form fields.

When the
server
-
side Page Class instance

receives the
Request
, it sees the data in those hidden form

fields, and
reacts accordingly, raising a
real

(
server
-
side
)
Event
, which can then be handled by the
Event Handler Method

you
have developed (if any).


5

ASP.Net Handle
s
Events">

ASP.Net

Controls:

We have been using the word "control" fairly frequently here, and now would be a good time to
explain the concept of
ASP.Net

Controls. In the
Common Language Runtime (CLR)
, all classes of objects which are
used in
ASP.Net

inte
rfaces (the HTML document rendered) are derived from
System.Web.UI.Control

in some form
or fashion. The origin of this term can probably be traced back to
Windows Forms
. All interface elements in a
Windows Form

are called
Controls
. The idea of
ASP.Net Cont
rols
is basically the same: A Control is a class which
has back
-
end processing, and renders a User Interface. In
Windows Forms
, the interface and back
-
end are in the
same memory space, part of the same
Application
. In
ASP.Net
,
Controls
have back
-
end proces
sing, and render an
HTML interface in the Page. The main difference is that the HTML interface is separated from the back
-
end
processing by the
client
-
server

"gulf".

Even the
ASP.Net

Page

class inherits System.Web.UI.Control, just as a Windows Form inherit
s from Control. A Page
has back
-
end processing and renders an interface in the browser. Like any other Control, it has a Controls Collection.
It has the same sequence of Events that any other Control has, plus a few others derived from
System.Web.UI.Templa
teControl
, which is its immediate Base class.

What seems to confuse people who are new to
ASP.Net

is that while the conceptual model has changed, the platform
has not. We're still dealing with HTTP and HTML here, and the control's interface element is just

text streamed to the
browser. Part of the problem that people have may stem from the way that these controls appear in
Visual
Studio.NET
, and how they appear in the source code for an
ASP.Net

page. In
Visual Studio.NET's
IDE
, the HTML
for
Controls
is
rend
ered
, making it look like there's actually something there. But there's not. If you view the code for
the control in the HTML view, you will notice that there is NO HTML for the
Control
in the page. This is because the
Control
renders

HTML to the
Page
when

the
Page
is
executed
. One of the
Event Methods

that a
Control
has is
the

Render() Method
. This
Method
literally
writes

HTML for the
Control
into the HTML output stream of the
Page
.

Don't let this confuse you, however. Underneath it all,
ASP.Net

is simply
automating much of what you had to hand
-
code into your ASP applications. It is still writing HTML to the output stream to the browser. Part of the output stream,
however, is certain types of HTML elements, such as the client
-
side event handlers that call t
he __doPostBack()
function, the ViewState hidden form field, and __doPostBack()
JavaScript
, which are used to emulate the link
between the
client
and
server
, enabling
client
-
side Events

to trigger
server
-
side Event Handlers
.

By creating the idea of a
WebFo
rm
, all of this is brought together into a
programming model

which acts much like a
Windows Form
. A
Windows Form

handles its own events. A
WebForm
does this too, by sending event messages
with a
POST
to the server, which then streams back the updated state

of the
WebForm
. This is why a
WebForm
always posts back to itself.

Conclusions:

In many ways,
ASP.Net

is an entirely different animal than
ASP
. But underneath it all,
ASP.Net

is still

6

doing everything that ASP does, just in a more organized and
object
-
ori
ented

way.
ASP.Net

automates many of the
common tasks demanded from an
ASP
developer, and hides much of the automation from the developer, as any
good
object
-
oriented

technology should.

A
WebForm
(
Page Class
) is the
ASP.Net

equivalent of a
Windows Form
. It

has similar programming characteristics
to a
Windows Form
. The back
-
end and interface elements, however, are separated by the "gulf" of the Internet and
stateless
HTTP protocol
. To bridge that gap, elements have been introduced on the
client
-

and
server
-
s
ides
, to
enable
Event
and state messaging between the
client
interface and
server

code.







Footnotes:

1.


Server Controls must have their "EnableViewState" property set to True in order to use the ViewState

2. This is true only for Controls which hav
e server
-
side events, and have their "AutoPostBack" property set to True




http://scribble
bin.com/post/2011/08/19/Error
-
DropdownList
-
has
-
a
-
SelectedValue
-
which
-
is
-
Invalid
-
because
-
it
-
does
-
not
-
exist
-
in
-
the
-
list
-
of
-
values.aspx




How to e
asily modify multiple Images >>


Error: DropdownList has a SelectedValue which is Invalid
be
cause it does not exist in the list of values

19. August 2011 10:57 by
Tmac

in
Coding

//

Tags:
asp.net
,
error
,
dropdownlist
,
coding
,
development

//


Comments (0)


A while ago I was working on a proje
ct where I needed to add a new record in a gridview control, but I kept getting the
error:


"
DropdownList has a SelectedValue which is Invalid because it does not exist in the list of values
"

One of fields in the row was bound to a dropdownlist and it was
causing the error because control was trying to bind to
a null value.


I was able to fix this issue easily

by checking to see if the field I was binding to was null and if so set the
selected value to the desired item in the dropdownlist


<asp:DropDownList

ID="ddAddTimePeriod" runat="server" DataSourceID="TimePeriodDS"

DataTextField="Text" DataValueField="Value" AppendDataBoundItems="true"

SelectedValue='<%# Eval("TimeTypePeriod") != null ? (int)Eval("TimeTypePeriod") : 1 %>'
>

</asp:DropDownList>

So in the

example above I check the "TimeTypePeriod" and if it is not null I use it as the selectedvalue otherwise I set
the selected value to 1 (which is the default value of an item in my dropdownlist).


hope this helps....






7






http://www.jeffgaroutte.net/2008/7/9/The
-
DropDownList
-
the
-
DataBind
-
and
-
the
-
Missing
-
Value




The DropDownList, the DataBind and the Missing Value

By Jeff on 7/9/2008 12:17:00 AM

I sat there and blinked at the ArgumentOutOfRangeException.


It was just a DropDownList that had the selected value data
bound inside a FormView.


How ca
n we prevent this from happening?


I did a little digging on how to handle this odd "spot" and I
found this
article

on a subclass of the DropDownList control.


It is an interesting article, and I

almost went this route but it has a
draw back I did not like.


The articles solution is to add the missing value to the DropDownList in an over
-
ridden OnDataBinding
method.



It is a clean solution and it works.


It could be easily compiled into an assemb
ly and if you were feeling really ambitious it could
modified to fire a "ValueNotFoundEvent" where you could change the value or bubble up an exception that includes the value
that the drop down list does not have; with those features added and removing th
e reference to DataRowView so it could work
with an ObjectDataSource I think it would be a useful control in everyone's toolbox.

Consider the following DropDownList and FormView


<asp:FormView ID=
"FormView1"

runat=
"server"

DataSourceID=
"ObjectDataSource1"
>


<ItemTemplate>


<asp:DropDownList ID=
"ddlSomething"

runat=
"server"


SelectedValue=
'<%# Bind("Value") %>'
>


<asp:ListItem>
-
choose
-
</asp:ListItem>


<asp:ListItem>one</asp:ListItem>


<asp:ListItem>two</asp:ListItem>


<asp:ListItem>three</asp:ListItem>


<asp:ListItem>five</asp:ListItem>


</asp:DropDownList>


</ItemTemplate>


</asp:FormView>


<asp:ObjectD
ataSource ID=
"ObjectDataSource1"

runat=
"server"


OldValuesParameterFormatString=
"original_{0}"

SelectMethod=
"GetTest"


TypeName=
"UserInterface.TestSource"
>

</asp:ObjectDataSource>

For reference, test and TestSource are as follows


name
space

UserInterface


{


[DataObject(
true
)]


public

class

test


{


public

test(String
value
)


{


8


_value =
value
;


}



private

string

_value;



[DataObjectField(
false
,
false
,
false
)]



public

string

Value


{


get {
return

_value; }


set { _value =
value
; }


}


}


[DataObject]


public

class

TestSource


{


[DataObjectMethod(DataObjectMethodType.Select)]



public

test GetTest()


{


test result =
new

test(
"four"
);



return

result;


}


}

}

Please make note, I'm not going into detail on DataSources, the DataObjectAttribute or how many of my own (or common
best)
practices I violated in the samples in this article, let's leave it at I feel like I need a shower having written it and move

on.

If you're in a crunch and cant add a custom control to your solution there is a way to handle this with an event.

Alter

the DropDownList to look this...


<asp:DropDownList ID=
"ddlSomething"

runat=
"server"


SelectedValue=
'<%# Bind("Value") %>'


OnDataBinding=
"DropDownList_DataBinding"
>

and add the following into the pages code behind...


1:
protected

void

DropDownList_DataBinding(
object

sender, EventArgs e)


2:

{


3:

DropDownList theDropDownList = (DropDownList)sender;


4:

theDropDownList.DataBinding
-
=
new

EventHandler(DropDownList_DataBinding)
;


5:

try


6:

{


7:

theDropDownList.DataBind();


8:

}


9:

catch
(ArgumentOutOfRangeException)


10:

{


9


11:

UserInterface.test item =
(UserInterface
.test)((IDataItemContainer)theDropDownList.NamingContainer).DataI
tem;


12:

//do whatever here, in this case we will just add the
item


13:

theDropDownList.Items.Add(item.Value);


14:

}


15:

}

Now
you will get the list and "four" will be added and selected.


Replace line 13 with whatever you would like to do for checks
and tests.

Ar
gumentOutOfRangeException does have a property called "ActualValue" but the .net framework does not fill this this
property when throwing the exception.



The ActualValue property is not used within the .NET Framework class library. It carries a null valu
e in all the
ArgumentOutOfRangeException objects thrown by the .NET Framework class library. The ActualValue property is provided so
that applications can use the available argument value.

Why does this work? The DataBinding event fires before the DataBind

happens.




On line 3 we type cast the sender as a DropDownList, because the event is wired into the DropDownList on the aspx
page we know this the case (you could add a type check if you wanted).




On line 4 we remove the event handler to avoid an infinit
e loop because calling DataBind on the DropDownList (line 7)
will fire the DataBinding event again.




With line 5 to 8 we try to DataBind the DropDownList.


Line 9 catches the only exception we are interested in, the ArgumentOutOfRangeException.


Any other

exception should
bubble up.


you could add a 2nd catch block under the ArgumentOutOfRangeException block like catch(Exception) and
handle it there if you did not want it to bubble up.


Notice I do not use the ArgumentOutOfRangeException that was
thrown an
ywhere and that I did not make a variable for it.


This avoids the warning "variable err is declared but never
used" that you get when you use "
catch
(ArgumentOutOfRangeException err)".


Line 11 get the current UserInterface.test item that the FormView is a
ttempting to bind.


By replacing
UserInterface.test with the correct object you can reuse this snip of code. In theory one should be able to use generics
with this but I have not tested or tried that.


If I was going to reuse this enough to try generics; I

would just subclass the
DropDownList, override the DataBinding method and fire a custom event when the value was not in the items collection
instead of tinkering with Generics.


If ActualValue actually had the value in it, this this would be unneeded, dec
laring
the variable on line 9 would allow us to use err.ActualValue.


Line 13 adds the value to the DropDownList.

This hack is quick and clean.


It leaves a very small footprint in the code; but you can not change the value, it does not work.


Really, a s
ub classed DropDownList that fires off an event that is able to return back the new value to use is a better solution to
the problem.

How does that look? I declared the class within the UserInterface namespace


public

class

DataBindDropDownList :
Syst
em.Web.UI.WebControls.DropDownList


{


public

class

ValueNotFoundArgs : EventArgs


{


public

ValueNotFoundArgs(
string

value
)


:
this
(
value
,
false
)


{


}



public

Va
lueNotFoundArgs(
string

value
, Boolean addNewValue)


10


:
base
()


{


_addValue = addNewValue;


_value =
value
;


_displayName =
value
;


}



private

string

_value;



public

string

Value


{


get {
return

_value; }


set { _value =
value
; }


}



private

Boolean _addValue;



public

Boolean AddValueIfItDoesNotExist


{


get {
return

_addValue; }


set { _addValue =
value
; }


}



private

string

_displayName;



public

string

DisplayName


{


get {
return

_di
splayName; }


set { _displayName =
value
; }


}


}


public

delegate

void

ValueNotFoundEventHandler(
object

sender,
ValueNotFoundArgs e);



public

event

ValueNotFoundEventHandler ValueNotFound;



private

string

_cachedValue =
""
;


public

override

string

SelectedValue


{


get


{


return

base
.SelectedValue;


}


set


{


base
.Selecte
dValue =
value
;


_cachedValue =
value
;


}


}



11


private

void

ThrowArgumentOutOfRangeException(
string

paramName,
string

value
)


{


throw

new

ArgumentOutOfRangeException(paramName,
value
,
n
ull
);


}



protected

override

void

OnDataBinding(EventArgs e)


{



try


{


base
.OnDataBinding(e);


}


catch

(ArgumentOutOfRangeException err)


{



if

(ValueNotFound !=
null
)


{


ValueNotFoundArgs notFoundArgs =
new

ValueNotFoundArgs(_cachedValue,
false
);


ValueNotFound(
this
, notFoundArgs);



this
.ClearSele
ction();



System.Web.UI.WebControls.ListItem item =
this
.Items.FindByValue(notFoundArgs.Value);


if

(item !=
null
)


item.Selected =
true
;


else

if

(notFoundArgs.AddVal
ueIfItDoesNotExist)


{


item =


new

System.Web.UI.WebControls.ListItem(notFoundArgs.DisplayName,
notFoundArgs.Value);


item.Selected =
true
;



this
.Items.Add(item);


}


else


{


ThrowArgumentOutOfRangeException(err.ParamName,
notFoundArgs.Value);


}


}



else


{


ThrowArgumentOutOfRangeException(err.ParamName,
_cachedValue);


}


}


}


12


}

and the aspx becomes...

<cc1:DataBindDropDownList ID=
"ddlSomething"

runat=
"server"

OnValueNotFound=
"DataBindDropDownList_ValueNotFound"


SelectedValue=
'<%# Bind("Value") %>'

>


<asp:ListItem>
-
choose
-
</asp:ListItem>


<asp:ListItem>one</asp:ListItem>


<asp:ListItem>two</asp:ListItem>


<asp:ListItem>thre
e</asp:ListItem>


<asp:ListItem>five</asp:ListItem>


</cc1:DataBindDropDownList>

and in the pages code behind...


protected

void

DataBindDropDownList_ValueNotFound(
object

sender,
UserInterface.DataBindDropDownList.ValueNotFoundArg
s e)


{


e.AddValueIfItDoesNotExist =
false
;


e.Value =
"6"
;


}

The aspx and page code behind do not look a whole lot different.


Depending on your assemblies/app_code directory the tags in
your aspx may look dif
ferent.


I can still get the same ArgumentOutOfRangeException as before; expect now I get the
ActualValue property populated when the exception is thrown.



Change the page code behind slightly...



protected

void

DataBindDropDownList_ValueNotFound(
objec
t

sender,


UserInterface.DataBindDropDownList.ValueNotFoundArgs e)


{


e.AddValueIfItDoesNotExist =
true
;


e.Value =
"6"
;


}

and the missing value is added to the DropDownList.

More importantly the Value
NotFound event allows a logic layer to be hooked in to change the value or add the value to the list.


There is no need to worry about DataSets, ObjectDataSources, DataRows, DataRowViews or type casting.



How does it work?

To understand what is going on t
aking a look at the ListControl with
Reflector

helps a great deal.


Basically, ListControl's set
accessor for SelectedValue checks to see if the items collection has been populated yet and put
s the new selected value into a
cache until the controls DataBind method is invoked.


Once the items list is built the cached value is pulled out and made active
or throws an exception if it is not in the items collection.


The DataBindDropDownList


does t
he same thing, it caches the
selected value and if the base class (DropDownList) raises the ArgumentOutOfRangeException it fires the ValueNotFoundEvent.


If the event is unused a ArgumentOutOfRangeException with the ActualValue populated is thrown.


If the

event is used the value
in the events ValueNotFoundArgs is evaluated.


If it finds the value, which the event may have changed, in the
DataBindDropDownList items it is set to be the selected item.


If the value is not found it checks to see if
AddValueIfI
tDoesNotExist is true.


If it is we create the ListItem with the value and the specified DisplayName.


If

13

AddValueIfItDoesNotExist is false a ArgumentOutOfRangeException is thrown with the value from the ValueNotFoundArgs as the
ActualValue because that wa
s the last value we tried to set.

Between the 3 different ways outlined here, the original method from
attractor's article
, the quick event hack and the event
based sub
-
class of the D
ropDownList control you should be able to address the problem of the missing value in a data bound
DropDownList in a way that fits your code/environment.

Back when I used Visual Studio 2005 I would use the quick event hack because of the "issues" getting V
S2005 to see controls in an
assembly and display them in the toolbox.


Because 2008 has addressed the "common issues" with the toolbox and assemblies I
would rather build the DataBindDropDownList in an assembly, add the reference to the project and use it.

Happy coding.



14

http://weblogs.asp.net/davidfowler/archive/2008/12/13/how
-
bind
-
works.aspx


How <%# Bind %> Works

In my last post I spoke about 2
-
way databinding an
d how it can be used to extract values from control
properties. How does this all work? Lets take a look at a page with 2
-
way databinding:

<
asp
:
LinqDataSource

ID
=
"productsSource"




runat
=
"server"




ContextTypeName
=
"FowlerSamples.NorthwindDataContext"




EnableDelete
=
"True"




EnableInsert
=
"True"




EnableUpdate
=
"True"

TableName
=
"Products"
>

</
asp
:
LinqDataSource
>





<
asp
:
GridView

ID
=
"products"




DataKeyNames
=
"ProductID,CategoryID"




AutoGenerateColumns
=
"False"




runat
=
"server"

DataSo
urceID
=
"productsSource"
>



<
Columns
>



<
asp
:
CommandField

ShowEditButton
=
"True"

/>











<
asp
:
BoundField

DataField
=
"ProductName"

/>



<
asp
:
TemplateField
>



<
EditItemTemplate
>



<
asp
:
LinqDataSource





ID
=
"categoriesSource"




runat
=
"server"




ContextTypeName
=
"FowlerSamples.NorthwindDataContext"




TableName
=
"Categories"

AutoGenerateWhereClause
=
"true"
>



</
asp
:
LinqDataS
ource
>



<
asp
:
DropDownList




runat
=
"server"




ID
=
"categories"



DataSourceID
=
"categoriesSource"



DataTextField
=
"CategoryName"



DataValueField
=
"Categ
oryID"



SelectedValue
=
'
<%
# Bind("CategoryID")
%>
'
>

















</
asp
:
DropDownList
>















</
EditItemTemplate
>













</
asp
:
TemplateField
>



</
Columns
>

</
asp
:
GridView
>


In the above example, the GridView has a template field with an
EditItemTemplate
that has a
DropDownList
that is 2
-
way databound. We're going to introduce a small error in the page in order to see
what the generated code looks like:

<
EditIte
mTemplate
>


<
asp
:
LinqDataSource






ID
=
"categoriesSource"




runat
=
"server"




ContextTypeName
=
"FowlerSamples.NorthwindDataContext"






TableName
=
"Categories"

AutoGenerateWhereClause
=
"true"
>



</
asp
:
LinqDataSource
>



<
as
p
:
DropDownList




runat
=
"server"




ID
=
"categories"


15



DataSourceID
=
"categoriesSource"



DataTextField
=
"CategoryName"



DataValueField
=
"CategoryID"



SelectedValue
=
'
<%
# Bind("CategoryID")
%>
'
>

















</
asp
:
DropDownList
>



<%
# Eval(3)
%>

</
EditItemTemplate
>


When we try to run this page we'll get a compile error and the famous
ASP.NET

YSOD(Yellow Screen of
Death):




Click on
Show Complete Compilation Source,

if your curious about how ASP.NET converts your the
markup to code.


When examining the source, we see a rather interesting method:

[System.Diagnostics.
DebuggerNonUserCodeAttribute
()]

public

System.Colle
ctions.Specialized.
IOrderedDictionary

@__ExtractValues__control8(System.Web.UI.
Control

@__container) {



System.Collections.Specialized.
OrderedDictionary

@__table;



System.Web.UI.WebControls.
DropDownList

categories;





categories =
((System.Web.UI.
WebControls.
DropDownList
)(@__container.FindControl(
"categories"
)));





@__table =
new

System.Collections.Specialized.
OrderedDictionary
();





if

((categories !=
null
)) {



@__table[
"CategoryID"
] = categories.SelectedValue;



}





return

@__
table;

}


As you can see in the above method, an OrderedDictionary is created and the SelectedValue property of the
DropDownList is pushed into the "CategoryID" field. But how does this get all the way to the data control?
Each control has a BuildControl m
ethod associated with it, if we examine the BuildControl method for the

16

TemplateField it becomes a bit more clear how things get hooked up.




[System.Diagnostics.
DebuggerNonUserCodeAttribute
()]

private

global
::System.Web.UI.WebControls.
TemplateField

@__B
uildControl__control7() {



global
::System.Web.UI.WebControls.
TemplateField

@__ctrl;





@__ctrl =
new

global
::System.Web.UI.WebControls.
TemplateField
();





@__ctrl.EditItemTemplate =
new

System.Web.UI.
CompiledBindableTemplateBuilder
(
new

System.Web.
UI.
BuildTemplateMethod
(
this
.@__BuildControl__control8),
new

System.Web.UI.
ExtractTemplateValuesMethod
(
this
.@__ExtractValues__control8));





return

@__ctrl;

}

The EditItemTemplate property is of type
ITemplate
.
CompiledBindableTemplate
implements both
ITemplate
and
IBindableTempalte
.

public

interface

IBindableTemplate

:
ITemplate

{









IOrderedDictionary

ExtractValues(
Control

container);

}

It's slowly coming t
ogether. So lets put together what we're learnt so far:

1.

Code Gen

creates
ExtractValues

method that returns the dictionary of values for each
ITemplate

that has a
Bind

expression.

2.

The
BuildControl

method

for the ITemplate's container (
TemplateField

in this

case)

assigns a new
CompiledBindableTemplate

to an
ITemplate
(EditItemTemplate in this case)

3.

CompiledBindableTemplate

implements
IBindableTemplate
, which has a method,
ExtractValues
which returns the dictionary given a container.

It almost all makes sens
e now. Each data control uses this mechanism to extract values from template fields
with 2
-
way databinding expressions.

What can you do with your new found knowledge?

<
asp
:
FormView




runat
=
"server"




ID
=
"formView"




DefaultMode
=
"Edit"
>



<
EditIt
emTemplate
>



<
asp
:
TextBox

ID
=
"textBox"

runat
=
"server"

Text
=
'
<%
# Bind("Name")
%>
'
></
asp
:
TextBox
>



<
asp
:
TextBox

ID
=
"textBox1"

runat
=
"server"

Text
=
'
<%
# Bind("Age")
%>
'
></
asp
:
TextBox
>



<
asp
:
Button

runat
=
"server"

ID
=
"updateButton"

CommandNa
me
=
"Update"

Text
=
"Update"

/>



</
EditItemTemplate
>

</
asp
:
FormView
>


And the code behind:




class

Person

{



public

string

Name {
get
;
set
; }



public

int

Age {
get
;
set
; }

}




17

protected

void

Page_Load() {



formView.ItemUpdating += formView_ItemUp
dating;


if

(!IsPostBack) {


formView.DataSource =
new

Person
[] {
new

Person

{ Name =
"David"
, Age = 22 } };



formView.DataBind();


}

}



protected

void

formView_ItemUpdating(
object

sender,
FormViewUpdateEventArgs

e) {



IBindableTemp
late

template = formView.EditItemTemplate
as

IBindableTemplate
;



if

(template !=
null
) {



IOrderedDictionary

values = template.ExtractValues(formView);



Response.Write(values[
"Name"
]);



Response.Write(values[
"Age"
]);



}

}


How co
ol is that?
:)


Published Saturday, December 13, 2008 8:57 AM by
davidfowl


Filed under:
ASP.NET
,
DataBinding
,
DataControls

Comments

#

re: How <%# Bind %> Works

Saturday, December 13, 2008 9:36 PM by
Will
保哥


What a bright way to figure out a new knowledge!

Thanks for sharing.

#

Interesting Finds: 2008.12.12~2008.12.18

Thursday, December 18, 2008 7:17 PM by
gOODiDEA.NET


Web 10 Ways to Cut Down Web Development Time JavaScript Inheritance via Prototypes and Closures
How to

#

Databinding 3.0

Friday, November 13, 2009 5:37 AM by
Unha
ndled Exception


There was a post on our internal discussion group recently where a customer pointed out one of the
weaknesses


18

http://weblogs.asp.net/davidfowler/a
rchive/2009/11/13/databinding
-
3
-
0.aspx




Databinding 3.0

There was a post on our internal discussion group recently where a customer pointed out one of the
weaknesses of 2 way data binding not working within user controls. Consider the following page:

<
asp:ObjectDataSource

runat=
"server"

ID=
"personSource"




SelectMethod=
"GetPersons"




UpdateMethod=
"Update"




DataObjectTypeName=
"ExtendedDatabinding.Person"





TypeName=
"ExtendedDatabinding.PersonRepository"
>



</
asp:ObjectD
ataSource
>

<
asp:FormView

runat=
"server"

ID=
"personFormView"

DataSourceID=
"personSource"

DefaultMode=
"Edit"

DataKeyNames=
"Id"
>



<
EditItemTemplate
>



<
custom:personedit

runat=
"server"

ID=
"personForm"

/> <
br

/> <
br

/>





<
asp:But
ton

runat=
"server"

Text=
"Update"

CommandName=
"Update"

/>



</
EditItemTemplate
>

</
asp:FormView
>

I have an ObjectDataSource that points to some business object and is bound to a form view. Also note that
we have one usercontrol is the form view, <custom:pe
rsonedit> which contains UI for an edit form. This is
pretty useful since I may want the same UI for edit and insert I could just use the same usercontrol.

The problem is this doesn’t work with 2 way binding, so the FormView won’t extract the values from w
ithin
the usercontrol even if there are <%# Bind() #> expressions declared. Here’s what the user control looks
like:

<
strong
>First Name:</
strong
><
asp:TextBox

runat=
"server"

ID=
"TextBox1"

Text=
'
<%
#
Bind("FirstName")
%>
'
></
asp:TextBox
> <
br

/> <
br

/>

<
strong
>
Last Name:</
strong
><
asp:TextBox

runat=
"server"

ID=
"TextBox2"

Text=
'
<%
# Bind("LastName")
%>
'
></
asp:TextBox
> <
br

/> <
br

/>

<
strong
>Address:</
strong
><
asp:TextBox

runat=
"server"

ID=
"TextBox3"

TextMode=
"MultiLine"

Rows=
"5"

Text=
'
<%
# Bind("Address")
%>
'
></
asp:Te
xtBox
> <
br

/> <
br

/>

<
strong
>State:</
strong
><
asp:DropDownList

runat=
"server"

ID=
"DropDownList1"

SelectedValue=
'
<%
#
Bind("State")
%>
'
>



<
asp:ListItem

Text=
""
></
asp:ListItem
>



<
asp:ListItem

Text=
"FL"
></
asp:ListItem
>



<
asp:ListItem

Text=
"WA"
></
asp:L
istItem
>



<
asp:ListItem

Text=
"CA"
></
asp:ListItem
>

</
asp:DropDownList
>

The sad thing is all of those Bind expression will be ignored when we hit update.

I don’t want to get into exactly why this is the case (you should read about how
bind works
), instead I’d like
to introduce a new way to do 2 way databinding.

In Dynamic Data 3.5 sp1 we introduced an interface
IBindableControl

which has an ExtractValues method
that takes a dictionary to populate with name value pairs. FormView and ListView know about this interface
and will look recursively for controls that implement IBindinab
leControl and call ExtractValues when

19

performing an update, insert or delete (also to store the edit values in viewstate). We could make our
usercontrol implement this interface and manually extract data from each control and put it into the
dictionary, bu
t that is tedious.

Enter databinding 3.0. Using the hidden gem
ProcessGeneratedCode

we can build a base class which I call
BindableUserControl
that supports a different Bind syntax to make this scenario work.

The idea exploits the fact that most controls derive from WebControl so we take advantage of their ability to
use expando attributes and use it to declare a bogus Binding attribute with a so
me bind expression as the
value. But enough talk lets dive into some code!



<%
@
Control

Language=
"C#"

Inherits=
"Web.Binding.BindableUserControl"

%>



<
strong
>First Name:</
strong
><
asp:TextBox

runat=
"server"

ID=
"firstName"

Binding=
"{Text=FirstName}"
></
asp:T
extBox
> <
br

/> <
br

/>

<
strong
>Last Name:</
strong
><
asp:TextBox

runat=
"server"

ID=
"lastName"

Binding=
"{Text=LastName}"
></
asp:TextBox
> <
br

/> <
br

/>

<
strong
>Address:</
strong
><
asp:TextBox

runat=
"server"

ID=
"address"

TextMode=
"MultiLine"

Rows=
"5"

Binding=
"{Text
=Address}"
></
asp:TextBox
> <
br

/> <
br

/>

<
strong
>State:</
strong
><
asp:DropDownList

runat=
"server"

ID=
"ddl"

Binding=
"{SelectedValue=State}"
>



<
asp:ListItem

Text=
"FL"
></
asp:ListItem
>



<
asp:ListItem

Text=
"WA"
></
asp:ListItem
>



<
asp:ListItem

Text=
"CA"
><
/
asp:ListItem
>

</
asp:DropDownList
>

We’re going to use the
Binding

attribute to determine what to bind and also the kind of binding to do. From
just looking you can pretty much follow the syntax:

{ControlPropertyName=PropertyName}

There is also an enum you

can use to specify what kind of binding you want to do:


{Text=Description, Mode=TwoWay}

{Text=Description, Mode=In}

{Text=Description, Mode=Out}

It basically tells the ControlBuilder what to generate i.e. Eval or ExtractValues statements or both.

The
special base class BindableUserControl has a FileLevelControlBuilder that does all of the magic. The
good news is that binding will work as expected now.

You can download the sample project here:


ExtendedDatabinding.zip

Published Friday, November 13, 2009 2:37 AM by
davidfowl


Filed under:
ASP.NET
,
DataBinding
,
Data Controls

Comments

#

Twitter Trackbacks for Databinding 3.0
-

Unhandled Exception [asp.ne
t] on Topsy.com


20

Friday, November 13, 2009 5:44 AM by
Twitter Trackbacks for Databinding 3.0
-

Unhandled Exception
[asp.net] on Topsy.com


Pingback from

Twitter Trackbacks for
















Databinding 3.0
-

Unhandled Exception








[asp.net]







on Topsy.com

#

Databinding 3.0
-

Unhandled Exception

Friday, November 13, 2009 6:56 AM

by
Databinding 3.0
-

Unhandled Exception


Pingback from

Databinding 3.0
-

Unhandled Exception

#

re: Databinding 3.0

Friday, November 13, 2009 7:27 AM by Joe Chung

Sweet! Nice to see WPF/Silverlight/XAML
-
style data binding come to ASP.NET!

#

Databinding 3.0 | I love .NET!

Friday, November 13, 2009 7:47 AM by
Databinding 3.0 | I love .NET!


Pingback from

Databin
ding 3.0 | I love .NET!

#

Dew Drop &#8211; November 13, 2009 | Alvin Ashcraft&#039;s Morning Dew

Friday, November 13, 2009 8:47 AM by
Dew Drop


November 13, 2009 | Alvin Ashcraft's Morning Dew


Pingback from

Dew Drop &#8211; November 13, 2009 | Alvin Ashcraft&#039;s Morning Dew

#

re: Databinding 3.0

Friday, November 13, 2009 10:05 AM by
rajbk


This is excellent news. I had bl
ogged about the same sometime ago.

weblogs.asp.net/.../formview
-
binding
-
gotcha.aspx

Thanks for fixing this!

#

re: Databinding 3.0

Friday, November 13, 2009 2:35 PM by
Alessandro


ahh, that's a very useful tip. Thanks for taking the time to blog thi
s.

#

re: Databinding 3.0

Sunday, November 15, 2009 8:25 AM by
mich
ielvoo


Looks very useful, but what is DataBinding 3.0? I've never heard that before. Is it in ASP.NET 4?


21

#

re: Databinding 3.0

Sunday, November 15, 2
009 2:44 PM by
davidfowl


@michielvoo Nothing to do with ASP.NET 4. This is a standalone thing that works even on 3.5.

#

?????? ?????????????????? ASP.NET Controls ?? DI
-
?????????????????? &laquo; butaji

Monday, November 16, 2009 1:59 AM by
?????? ?????????????????? ASP.NET Controls ?? DI
-
?????????????????? « butaji


Pingback from

?????? ??????????
???????? ASP.NET Controls ?? DI
-
?????????????????? &laquo; butaji

#

12 Ways to Simplify ASP.NET and Visual Studio

Friday, December 04, 2009 11:56 AM by

Community Blogs


While at PDC this year I had an opportunity to interview a number of smart and engaging people. One

of

#

re: Databinding 3.0

Thursday, December 10, 2009 8:56 AM by
Frank


Can you do a chain of

properties?

For Example, if I added a supervisor property to the person class could I
reference it like so:

Binding="{Text=Supervisor.FirstName}"

#

re
: Databinding 3.0

Monday, December 14, 2009 5:35 AM by
davidfowl


@Frank 2 way binding won't work right now because most datasources (they are responsible for building th
e
object from the binding expressions) won't handle complex objects right now.


`