<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8212091881452213631</id><updated>2011-04-22T00:31:45.129+01:00</updated><category term='OOP'/><category term='C#'/><category term='Extenders'/><category term='Design'/><category term='Asp.net'/><category term='Build'/><category term='Optimera'/><category term='CSS'/><category term='Javascript'/><category term='Ajax'/><category term='TFS'/><category term='C# 3.0'/><title type='text'>Hocke - Tankar, tutorials, tips och tricks</title><subtitle type='html'>Tankar, tips och tricks om det jag jobbar med för tillfället på &lt;a href="http://thomascook.se/"&gt;Thomas Cook&lt;/a&gt;/&lt;a href="http://www.ving.se/"&gt;Ving&lt;/a&gt;. Det här är den svenska varianten av min &lt;a href="http://hocke.blogspot.com"&gt;engelska blogg&lt;/a&gt;.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://hockeswe.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://hockeswe.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Håkan Canberger</name><uri>http://www.blogger.com/profile/07785350579880064843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>24</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8212091881452213631.post-627634738925711084</id><published>2009-02-16T18:54:00.001+01:00</published><updated>2009-02-16T19:17:10.179+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><category scheme='http://www.blogger.com/atom/ns#' term='Design'/><title type='text'>Aldrig Fluent Interface på bekostnad av god design</title><content type='html'>&lt;a title="Johan Lindfors blogg" href="http://blogs.msdn.com/johanl/archive/2009/02/13/en-liten-dsl-f-r-att-best-lla-kaffe.aspx"&gt;Johan Lindfors har ett blogginlägg&lt;/a&gt; om hur man kan instansiera ett objekt, en KaffeLatte, med fluent interface, eller member chaining. Eftersom han ville bolla idéen så kommer här min replik på det. Så här ser Johans exempel ut:   &lt;pre class="csharpcode"&gt;KatteLatte latte = KatteLatte.beställ&lt;br /&gt;    .dubbel&lt;br /&gt;    .fettfri&lt;br /&gt;    .vanilj;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Klassen måste då se ut så här:&lt;/p&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; KatteLatte&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; KatteLatte beställ&lt;br /&gt;    {&lt;br /&gt;        get&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; KatteLatte();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt; &lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; KatteLatte dubbel&lt;br /&gt;    {&lt;br /&gt;        get&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.Dubbel = &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;br /&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt; &lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; KatteLatte vanilj&lt;br /&gt;    {&lt;br /&gt;        get&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.Vanilj = &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;br /&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt; &lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; KatteLatte fettfri&lt;br /&gt;    {&lt;br /&gt;        get&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.Vanilj = &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;br /&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt; &lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; Vanilj { get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set; }&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; Dubbel { get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set; }&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; Fettfri { get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set; }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Inte så snyggt, om du frågar mig, och andra invänder mot det i kommentarerna till Johans inlägg. Fluent Interface är trevligt, men det får inte ske på bekostnad av principer för god objekt orienterad programmering. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;I det här fallet är latten ett typexempel på Decorator Pattern (just kaffe finns med som &lt;a title="Wikipedia: Decorator Pattern" href="http://en.wikipedia.org/wiki/Decorator_pattern"&gt;exempel på Wikipedia&lt;/a&gt;). Jag går inte in på varför det är en bättre lösning, utan konstaterar bara &lt;em&gt;att&lt;/em&gt; det är det. :)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Vidare bör man inte blanda ihop det man skapar med hur man skapar det. Här kommer ett exempel på betydligt bättre design OCH fluent interface. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Om vi börjar med Decorator-mönstret. I korthet kan man säga att man kedjar ihop liknande objekt med varandra. Dessa kan hakas ihop i valfri ordning och man kan därmed bygga både komplexa objekt och nya strukturer man inte förutsåg när man började. I det här fallet skapar vi upp de olika ingredienserna och med hjälp av mönstret kan vi haka ihop dessa till olika drycker.&lt;/p&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Dryck&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; Dryck _dryck;&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; Dryck() { }&lt;br /&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; Dryck(Dryck dryck) { _dryck = dryck; }&lt;br /&gt;…&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Espresso : Dryck&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; Espresso() { }&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; Espresso(Dryck dryck) : &lt;span class="kwrd"&gt;base&lt;/span&gt;(dryck) { }&lt;br /&gt;…&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Mjölk : Dryck&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; Mjölk() { }&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; Mjölk(Dryck dryck) : &lt;span class="kwrd"&gt;base&lt;/span&gt;(dryck) { }&lt;br /&gt;…&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; FettfriMjölk : Dryck&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; FettfriMjölk() { }&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; FettfriMjölk(Dryck dryck) : &lt;span class="kwrd"&gt;base&lt;/span&gt;(dryck) { }&lt;br /&gt;…&lt;br /&gt;}&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Vanilj : Dryck&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; Vanilj() { }&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; Vanilj(Dryck dryck) : &lt;span class="kwrd"&gt;base&lt;/span&gt;(dryck) { }&lt;br /&gt;…&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;… fler drycker&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Vi kan nu skapa lite olika drycker så här:&lt;/p&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;var latte=&lt;span class="kwrd"&gt;new&lt;/span&gt; Espresso(&lt;span class="kwrd"&gt;new&lt;/span&gt; Milk());&lt;br /&gt;var dubbelEspresso=&lt;span class="kwrd"&gt;new&lt;/span&gt; Espresso(&lt;span class="kwrd"&gt;new&lt;/span&gt; Espresso());&lt;br /&gt;var americano=&lt;span class="kwrd"&gt;new&lt;/span&gt; Espresso(&lt;span class="kwrd"&gt;new&lt;/span&gt; Vatten());&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;(Mängden mjölk i en latte kan diskuteras, men om du frågar mig är det alltid för mycket mjölk i en kaffe med mjölk i :)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Sen skapas en &lt;a title="Wikipedia: Abstract Factory" href="http://en.wikipedia.org/wiki/Abstract_factory_pattern"&gt;Abstract Factory&lt;/a&gt; (jag tog bort dubbel för att göra det hela lite enklare). Fabriken har till uppgift att skapa en dryck.&lt;/p&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IDryckFactory&lt;br /&gt;{&lt;br /&gt;    IDryckFactory Vanilj();&lt;br /&gt;    IDryckFactory Fettfri();&lt;br /&gt;    Dryck BeställningKlar();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; LatteFactory : IDryckFactory&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; _vanilj;&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; _fettfri;&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; IDryckFactory Beställ()&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; LatteFactory();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; IDryckFactory Vanilj() { _vanilj = &lt;span class="kwrd"&gt;true&lt;/span&gt;; &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;; }&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; IDryckFactory Fettfri() { _fettfri = &lt;span class="kwrd"&gt;true&lt;/span&gt;; &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;; }&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; Dryck BeställningKlar()&lt;br /&gt;    {&lt;br /&gt;        Dryck latte = _fettfri ? &lt;br /&gt;                      &lt;span class="kwrd"&gt;new&lt;/span&gt; Espresso(&lt;span class="kwrd"&gt;new&lt;/span&gt; FettfriMjölk()) : &lt;br /&gt;                      &lt;span class="kwrd"&gt;new&lt;/span&gt; Espresso(&lt;span class="kwrd"&gt;new&lt;/span&gt; Mjölk());&lt;br /&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt;(_vanilj)&lt;br /&gt;        {&lt;br /&gt;            latte = &lt;span class="kwrd"&gt;new&lt;/span&gt; Vanilj(latte);&lt;br /&gt;        }&lt;br /&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; latte;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;För att skapa en latte nu så kan man skriva:&lt;/p&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;var latte = LatteFactory.Beställ()&lt;br /&gt;    .Fettfri()&lt;br /&gt;    .Vanilj()&lt;br /&gt;    .BeställningKlar();&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Inte så mycket mer för utvecklaren som ska skapa en latte att skriva, men mycket, mycket bättre underliggande design.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Mönstret &amp;lt;Skapa ett objekt, anropa lite metoder, avsluta med en “avsluta”-metod&amp;quot;, få ut ett resultat&amp;gt; går att använda till fler saker. Metoden fungerar bra till valideringar t.ex &lt;/p&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;string&lt;/span&gt; myString;&lt;br /&gt;...&lt;br /&gt;&lt;span class="kwrd"&gt;bool&lt;/span&gt; isValid=myString.StartValidation().&lt;br /&gt;   IsNotNull().&lt;br /&gt;   LengthIsAtLeast(5).&lt;br /&gt;   LengthIsAtMost(10).&lt;br /&gt;   DoesNotContain(&lt;span class="str"&gt;&amp;quot;-&amp;quot;&lt;/span&gt;).&lt;br /&gt;   Validate();&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Går inte in i detalj på hur man gör, kanske kommer det en post om det i framtiden, men här används extension metoder och generiska klasser på ett listigt sätt. Det går att utöka så att man, utöver en bool, kan få ut felmeddelanden om varje del som inte validerar. &lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- Bloggtoppen.se --&gt; &lt;a href="http://www.bloggtoppen.se/"&gt;&lt;img border="0" src="http://www.bloggtoppen.se/tracker.php?do=in&amp;id=12520" alt="Bloggtoppen.se" /&gt;&lt;/a&gt; &lt;!-- /Bloggtoppen.se --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212091881452213631-627634738925711084?l=hockeswe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hockeswe.blogspot.com/feeds/627634738925711084/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8212091881452213631&amp;postID=627634738925711084' title='1 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/627634738925711084'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/627634738925711084'/><link rel='alternate' type='text/html' href='http://hockeswe.blogspot.com/2009/02/aldrig-fluent-interface-pa-bekostnad-av.html' title='Aldrig Fluent Interface på bekostnad av god design'/><author><name>Håkan Canberger</name><uri>http://www.blogger.com/profile/07785350579880064843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8212091881452213631.post-1859405691886726939</id><published>2008-07-27T13:09:00.001+02:00</published><updated>2008-07-27T14:01:36.131+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='Ajax'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Inkludera script efter asp.net ajax-ramverkets filer</title><content type='html'>&lt;div class="otherLanguage"&gt; &lt;a href="http://hocke.blogspot.com/2008/07/how-to-include-scripts-after-aspnet.html"&gt;English version of this entry&lt;/a&gt; &lt;/div&gt; &lt;p&gt;N&amp;#228;r man registrerar script-filer med &lt;a href="http://msdn.microsoft.com/sv-se/library/system.web.ui.scriptmanager.registerclientscriptinclude(en-us).aspx"&gt;ScriptManager.RegisterClientScriptInclude(&amp;quot;myFile.js&amp;quot;)&lt;/a&gt; inkluderas alltid filerna f&amp;#246;re ajax-ramverkets. Det &amp;#228;r inte vad man vill om filerna &amp;#228;r beroende av ramverket.Oftast m&amp;#228;rker man det p&amp;#229; att man f&amp;#229;r script-fel liknande &amp;quot;Type is not defined&amp;quot; d&amp;#229; man oftast &amp;#246;verst i en sina filer deklarerar ett namespace med: &amp;quot;Type.registerNamespace('My.Namespace&amp;quot;);&amp;quot;&lt;/p&gt;  &lt;p&gt;Om man d&amp;#228;remot registrerar en fil som en referens via en ScriptManagerProxy, kommer filen att inkluderas efter ramverkets:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:ScriptManagerProxy&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;ScriptManagerProxy1&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Scripts&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:ScriptReference&lt;/span&gt; &lt;span class="attr"&gt;Path&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;~/anotherFile.js&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Scripts&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;asp:ScriptManagerProxy&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;F&amp;#246;rklaringen till betendet &amp;#228;r enkel, &amp;#228;ven om man &amp;#246;nskar att det inte hade fungerat s&amp;#229; h&amp;#228;r. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;N&amp;#228;r man registrerar filen via RegisterClientScriptInclude kommer funktionalitet i en klass som heter ClientScriptManager att anv&amp;#228;ndas. ClientScriptManager har internt en lista med script-filer och filer som registrerars hamnar sist i den listan. S&amp;#229; filen kommer, direkt n&amp;#228;r man anropar ScriptManager.RegisterClientScriptInclude(&amp;quot;myFile.js&amp;quot;), att hamna i listan. Efter anropet kommer listan att se ut s&amp;#229; h&amp;#228;r:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;ClientScriptManagerClientScripts = { ..., &amp;quot;~/myFile.js&amp;quot; }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Filerna i ScriptManagerProxy hanteras d&amp;#228;remot lite annorlunda. ScriptManager registrerar sig p&amp;#229; eventet PagePreRenderComplete och n&amp;#228;r det intr&amp;#228;ffar samlar ScriptManager ihop filerna fr&amp;#229;n alla ScriptManagerProxies i en lista. F&amp;#246;rst i den listan hamnar ajax-ramverkets filer. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Lista hos ScriptManager = { ajax-ramverkets filer, &amp;quot;~/anotherFile.js&amp;quot; }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Dessa registreras hos ClientScriptManager och hamnar d&amp;#229; i dess lista. Eftersom vi har registrerat myFile.js f&amp;#246;r det att PagePreRenderComplete intr&amp;#228;ffar (PagePreRenderComplete intr&amp;#228;ffar sent i asp.net pipeline) s&amp;#229; kommer myFile.js att ligga f&amp;#246;re ramverkets:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;ClientScriptManagerClientScripts = { ..., &amp;quot;~/myFile.js&amp;quot;, ..., ajax-ramverkets filer, &amp;quot;~/anotherFile.js&amp;quot;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Dessa skrivs sedan ut till sidan under Render-fasen och det f&amp;#246;rklarar varf&amp;#246;r anotherFile.js har tillg&amp;#229;ng till ramverkets kod och myFile.js inte har det.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;L&amp;#246;sning 1. Anv&amp;#228;nd proxy&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Den enklaste l&amp;#246;sningen &amp;#228;r att l&amp;#228;gga in en ScriptManagerProxy p&amp;#229; sidan/user control och antingen, som ovan, registrera en ScriptReference, eller g&amp;#246;ra det via kod genom:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;ScriptManagerProxy1.Scripts.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; ScriptReference(&lt;span class="str"&gt;&amp;quot;~/myFile.js&amp;quot;&lt;/span&gt;));&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;L&amp;#246;sning 2. Registrera efter PagePreRenderComplete&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Om man p&amp;#229; n&amp;#229;got s&amp;#228;tt lyckas registrera myFile.js efter PagePreRenderComplete kommer filen att hamna efter ScriptManagerns filer. Det g&amp;#228;ller dock att hamna f&amp;#246;re rendreringen av script-blocken. Allts&amp;#229;: efter PagePreRenderComplete men f&amp;#246;re Render. Det som h&amp;#228;nder mellan dessa faser &amp;#228;r sparning av ViewState&amp;#160; S&amp;#229; om vi i SaveViewState registrerar myFile.js kommer den att hamna efter ajax-ramverkets filer. Det &amp;#228;r lite hackigt, och inte garanterat att fungera n&amp;#228;r nya versioner av ramverket kommer, men: det fungerar.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; SaveViewState()&lt;br /&gt;{&lt;br /&gt;    ScriptManager.RegisterClientScriptInclude(&lt;span class="kwrd"&gt;this&lt;/span&gt;,GetType(),&lt;span class="str"&gt;&amp;quot;myFile&amp;quot;&lt;/span&gt;,&lt;span class="str"&gt;&amp;quot;~/myFile.js&amp;quot;&lt;/span&gt;);&lt;br /&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;base&lt;/span&gt;.SaveViewState();&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;L&amp;#246;sning 3. En egen ScriptManager&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Det h&amp;#228;r &amp;#228;r i mina &amp;#246;gon den snyggaste l&amp;#246;sningen. Man skapar klassen MyScriptManager som &amp;#228;rver av ScriptManager och byter ut ScriptManager p&amp;#229; sidan mot MyScriptManager. P&amp;#229; MyScriptManager l&amp;#228;gger man till en metod RegisterClientScriptInclude(string url) och genom lite finurligheter internt i MyScriptManager kan man f&amp;#229; filer som registreras via den nya metoden att hamna efter ajax-ramverkets.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;N&amp;#228;r ScriptManager samlar ihop filer fr&amp;#229;n samtliga ScriptManagerProxies s&amp;#229; g&amp;#246;r den dessutom ytterligare en sak: Den h&amp;#228;mtar script-filer fr&amp;#229;n kontroller som registrerats via ScriptManager.GetCurrent(Page).RegisterScriptControl. Dessa kommer att inkluderas efter proxy-filerna och d&amp;#228;rmed &amp;#228;ven efter ramverks-filerna. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Om vi h&amp;#229;ller reda p&amp;#229; de filer som registrerats via den nya metoden i en egen lista och l&amp;#229;ter v&amp;#229;r MyScriptManager vara en IScriptControl och registrera sig sj&amp;#228;lv som en ScriptControl kan vi f&amp;#229; in v&amp;#229;r lista med filer efter ramverksfilerna. Det &amp;#228;r inte s&amp;#229; mycket kod som beh&amp;#246;vs:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; MyScriptManager : ScriptManager, IScriptControl&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; _registeredScripts = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt;();&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; RegisterClientScriptInclude(&lt;span class="kwrd"&gt;string&lt;/span&gt; url)&lt;br /&gt;    {&lt;br /&gt;        _registeredScripts.Add(url);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnPreRender(EventArgs e)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="rem"&gt;//Register this instance as a ScriptControl.&lt;/span&gt;&lt;br /&gt;        RegisterScriptControl(&lt;span class="kwrd"&gt;this&lt;/span&gt;);&lt;br /&gt;        &lt;span class="kwrd"&gt;base&lt;/span&gt;.OnPreRender(e);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; MyScriptManager GetCurrent(Page page)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; (MyScriptManager) ScriptManager.GetCurrent(page);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="preproc"&gt;#region&lt;/span&gt; IScriptControl Members&lt;br /&gt;    IEnumerable&amp;lt;ScriptDescriptor&amp;gt; IScriptControl.GetScriptDescriptors()&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    IEnumerable&amp;lt;ScriptReference&amp;gt; IScriptControl.GetScriptReferences()&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="rem"&gt;//For each element in _registeredScripts create a&lt;br /&gt;        //ScriptReference and return the IEnumerable&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; _registeredScripts.ConvertAll(s =&amp;gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ScriptReference(s));&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Observera att koden ovan &amp;#228;r f&amp;#246;renklad s&amp;#229; l&amp;#229;ngt det g&amp;#229;r f&amp;#246;r att visa konceptet. I produktionskod vill man t.ex. inte skapa listan om den inte beh&amp;#246;vs. Dessutom b&amp;#246;r man skapa tv&amp;#229; protected virtual varianter av GetScriptDescriptors och GetScriptReferences som IScriptControl.GetScriptDescriptors resp. IScriptControl.GetScriptReferences f&amp;#229;r anropa.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Med f&amp;#246;ljande kodrad registreras en script-fil som kommer att hamna efter ajax-ramverkets:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;MyScriptManager.GetCurrent(Page).RegisterClientScriptInclude(&lt;span class="str"&gt;&amp;quot;~/myFile.js&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Om du anv&amp;#228;nder AjaxControlToolkit &amp;#228;ndrar du bara arvet till ToolkitScriptManager.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Observera att filordningen blir: &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;ScriptManager.RegisterClientScriptInclude-registrerade filer &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Ajax-ramverkets filer &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Alla ScriptManagerProxy-filer &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;MyScriptManager.RegisterClientScriptInclude-registrerade filer &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Om du vill f&amp;#229; in filer mellan punkt 2 och 3 f&amp;#229;r du problem. Det g&amp;#229;r s&amp;#228;kert att g&amp;#246;ra, men det &amp;#228;r antagligen inte trivialt eftersom ScriptManager &amp;#228;r r&amp;#228;tt st&amp;#228;ngd f&amp;#246;r modifiering. Det hade varit trevligt om Microsoft f&amp;#246;ljt &lt;a href="http://en.wikipedia.org/wiki/Open/closed_principle"&gt;Open/Closed-principen&lt;/a&gt; lite mer.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- Bloggtoppen.se --&gt; &lt;a href="http://www.bloggtoppen.se/"&gt;&lt;img border="0" src="http://www.bloggtoppen.se/tracker.php?do=in&amp;id=12520" alt="Bloggtoppen.se" /&gt;&lt;/a&gt; &lt;!-- /Bloggtoppen.se --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212091881452213631-1859405691886726939?l=hockeswe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hockeswe.blogspot.com/feeds/1859405691886726939/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8212091881452213631&amp;postID=1859405691886726939' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/1859405691886726939'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/1859405691886726939'/><link rel='alternate' type='text/html' href='http://hockeswe.blogspot.com/2008/07/inkludera-script-efter-aspnet-ajax.html' title='Inkludera script efter asp.net ajax-ramverkets filer'/><author><name>Håkan Canberger</name><uri>http://www.blogger.com/profile/07785350579880064843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8212091881452213631.post-1160063684917417363</id><published>2008-05-17T17:53:00.001+02:00</published><updated>2008-05-17T17:53:01.174+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Build'/><category scheme='http://www.blogger.com/atom/ns#' term='TFS'/><title type='text'>Bygga Database Project i TFS</title><content type='html'>&lt;p&gt;Att f&amp;#229; ig&amp;#229;ng byggen p&amp;#229; Team Foundation Server 2008 med Team Build d&amp;#228;r Database Project ing&amp;#229;r i en solutionfil &amp;#228;r inte helt enkelt. Sj&amp;#228;lv har jag inte k&amp;#246;rt Database Project n&amp;#229;got, &amp;#228;n. I projektet jag jobbar i beh&amp;#246;vde vi f&amp;#229; ig&amp;#229;ng dagliga byggen s&amp;#229; det f&amp;#246;ll p&amp;#229; min lott att f&amp;#229; det att funka.&lt;/p&gt;  &lt;p&gt;Ut&amp;#246;ver att kompilera s&amp;#229; bygger vi och deployar databas och webappen till en server. Det h&amp;#228;r inl&amp;#228;gget beskriver vad vi gjorde f&amp;#246;r att f&amp;#229; ig&amp;#229;ng det. Observera att vi inte kickat ig&amp;#229;ng unit-tester &amp;#228;n, s&amp;#229; jag vet inte hur det h&amp;#228;r fungerar ihop med det.&lt;/p&gt;  &lt;h2&gt;Skapa ett vanligt bygge&lt;/h2&gt;  &lt;p&gt;Steg ett &amp;#228;r att skapa ett bygge i TFS 2008 p&amp;#229; vanligt s&amp;#228;tt och peka ut solution-filen man vill bygga.&lt;/p&gt;  &lt;h2&gt;Ange databas d&amp;#228;r bygget ska ske&lt;/h2&gt;  &lt;p&gt;N&amp;#228;r man bygger ett dabasprojekt i Visual Studio 2008 s&amp;#229; byggs databasen enl. de inst&amp;#228;llningar man gjort i VS f&amp;#246;r det projektet. Vi l&amp;#229;ter varje utvecklare k&amp;#246;ra mot en egen instans av Sql. Dessa inst&amp;#228;llningar lagras inte i dbproj-filen, utan i en fil som slutar p&amp;#229; dbproj.user. Denna fil &amp;#228;r unik f&amp;#246;r varje anv&amp;#228;ndare och checkas d&amp;#228;rf&amp;#246;r inte in i Source Control.&lt;/p&gt;  &lt;p&gt;P&amp;#229; n&amp;#229;got s&amp;#228;tt m&amp;#229;ste vi ers&amp;#228;tta det som st&amp;#229;r i dbproj.user-filen och tala om f&amp;#246;r byggservern var den ska bygga n&amp;#229;gonstans. Det &amp;#228;r TargetDatabase, TargetConnectionString, eller DefaultDataPath som m&amp;#229;ste anges och det finns lite olika s&amp;#228;tt att g&amp;#246;ra det p&amp;#229;. &lt;a href="http://blogs.msdn.com/buckh/archive/2007/09/11/vsts-2005-and-2008-building-database-projects-with-team-build.aspx"&gt;Buck Hodges har beskrivit hur man f&amp;#229;r ig&amp;#229;ng byggen&lt;/a&gt; och han n&amp;#228;mner 3 s&amp;#228;tt att g&amp;#246;ra det p&amp;#229; (tv&amp;#229; i texten och en i kommentarerna).&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Ange v&amp;#228;rdena direkt i .dbproj-filen      &lt;br /&gt;Checka ut dbproj-filen, &amp;#246;ppna den som xml-fil och l&amp;#228;gg in v&amp;#228;rdena f&amp;#246;r f&amp;#228;lten. Enklast &amp;#228;r att modifiera v&amp;#228;rdena fr&amp;#229;n dbproj.user-filen.       &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot; '$(Configuration)' == 'Default' &amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;TargetDatabase&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;MyProject_Daily&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;TargetDatabase&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;TargetConnectionString&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Data Source=.\SQLEXPRESS;Integrated Security=True;Pooling=False&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;TargetConnectionString&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DefaultDataPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;d:\data\&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;DefaultDataPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;  &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Skicka in v&amp;#228;rdena som command line-argument till MSBuild, antingen i Queue Build-f&amp;#246;nstret eller genom att l&amp;#228;gga dem TFSBuild.rsp-filen. T.ex. &lt;br /&gt;    &lt;pre class="csharpcode"&gt;/p:DefaultDataPath=&lt;em&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;path&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/em&gt;; TargetDatabase=&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;em&gt;&lt;span class="html"&gt;databaseName&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/em&gt;;TargetConnectionString=&amp;quot;&lt;em&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;connection string&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/em&gt;&amp;quot;&lt;/pre&gt;&lt;br /&gt;  &lt;/li&gt;&lt;br /&gt;&lt;br /&gt;  &lt;li&gt;Skapa en egen targets-fil och inkludera den precis innan dbproj.user importeras. &lt;br /&gt;    &lt;br /&gt;Skapa en fil .dbproj.BuildDefaults: &lt;br /&gt;&lt;br /&gt;    &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="html"&gt;xml&lt;/span&gt; &lt;span class="attr"&gt;version&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;1.0&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;encoding&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;utf-8&amp;quot;&lt;/span&gt;?&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Project&lt;/span&gt; &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;http://schemas.microsoft.com/developer/msbuild/2003&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot; '$(Configuration)' == 'Default' &amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;        &lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;TargetDatabase&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;MyProject_Daily&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;TargetDatabase&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;TargetConnectionString&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Data Source=.\SQLEXPRESS;Integrated Security=True;Pooling=False&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;TargetConnectionString&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DefaultDataPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;d:\DATA\&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;DefaultDataPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;L&amp;#228;gg sedan till de tv&amp;#229; &amp;#246;versta raderna nedan i dbproj filen precis innan importen av Microsoft.VisualStudio.TeamSystem.Data.Tasks.targets. &lt;br /&gt;&lt;br /&gt;    &lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;&amp;lt;!-- Import default settings --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Import&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Exists('$(MSBuildProjectFullPath).BuildDefaults')&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(MSBuildProjectFullPath).BuildDefaults&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;&amp;lt;!--Import the settings--&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Import&lt;/span&gt; &lt;span class="attr"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v9.0\TeamData\Microsoft.VisualStudio.TeamSystem.Data.Tasks.targets&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;Eftersom Microsoft.VisualStudio.TeamSystem.Data.Tasks.targets importerar dbproj.user-filen (om den finns) s&amp;#229; kommer det som finns i BuildDefaults att ers&amp;#228;ttas av det som st&amp;#229;r i dbproj.user filen n&amp;#228;r man bygger lokalt. P&amp;#229; byggservern finns inte dbproj.user-filen och d&amp;#228;rf&amp;#246;r kommer v&amp;#228;rdena fr&amp;#229;n BuildDefaults-filen att g&amp;#228;lla. &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Alternativ 1 och 3 inneb&amp;#228;r att man (i princip) talar om i k&amp;#228;llkoden var man ska bygga. Inte s&amp;#229; snyggt. Inte s&amp;#229; flexibelt. Bygg-inst&amp;#228;llningarna vill man h&amp;#229;lla borta fr&amp;#229;n koden i enlighet med &lt;a href="http://en.wikipedia.org/wiki/Separation_of_concerns"&gt;Separation of Concerns&lt;/a&gt;-t&amp;#228;nket.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Alt. 2 &amp;#228;r r&amp;#228;tt ok, men jag f&amp;#246;redrar att h&amp;#229;lla alla bygg-inst&amp;#228;llningar i TFSBuild.proj-filen&amp;#160; Det enklaste &amp;#228;r faktiskt att skicka med parametrarna n&amp;#228;r man specificerar vilken solution-fil som ska byggas (i TFSBuild.proj):&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;SolutionToBuild&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(BuildProjectFolderPath)/../../MyProject.sln&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Targets&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Targets&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Properties&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;TargetDatabase=MyProject_Daily;DefaultDataPath=e:\data;TargetConnectionString=Data Source=.\SQLEXPRESS&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Properties&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;SolutionToBuild&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;  &lt;p&gt;HACK: Observera Target Connection-str&amp;#228;ngen. Jag utnyttjar default-v&amp;#228;rden f&amp;#246;r Integrated Security. Om man l&amp;#228;gger in semikolon, oavsett om man g&amp;#246;r det som ; eller %3B kommer dessa v&amp;#228;rden att tolkas som egna properties med skumma fel som f&amp;#246;ljd.&lt;/p&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Vi har st&amp;#228;llt in solution-filen p&amp;#229; att bygga databas projektet &amp;#228;ven f&amp;#246;r Debug och Release. Om man inte g&amp;#246;r det m&amp;#229;ste man se till att bygga Default-flavor ocks&amp;#229; (&lt;a href="http://blogs.msdn.com/buckh/archive/2007/09/11/vsts-2005-and-2008-building-database-projects-with-team-build.aspx"&gt;Buck Hodges f&amp;#246;rklarar under Issue #3&lt;/a&gt;).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Nu ska allt bygga. Om du f&amp;#229;r problem, kolla &lt;a href="http://blogs.msdn.com/buckh/archive/2007/09/11/vsts-2005-and-2008-building-database-projects-with-team-build.aspx"&gt;Buck Hodges text&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Deploya&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;F&amp;#246;r att deploya databasen till en server m&amp;#229;ste man bygga databasen f&amp;#246;r den servern ocks&amp;#229;. Vi har valt att k&amp;#246;ra ytterligare ett byggomg&amp;#229;ng f&amp;#246;r databasprojeket och sen efter att allt droppats s&amp;#229; deployar vi.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Bygg f&amp;#246;r deploy&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;F&amp;#246;r att bygga databasprojektet anv&amp;#228;nder man en MSBuild Task:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MSBuild&lt;/span&gt; &lt;span class="attr"&gt;Projects&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(SolutionRoot)/Database/MyDatabase/MyDatabase.dbproj&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Targets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Rebuild&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Properties&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;TargetDatabase=MyDb; TargetConnectionString=Data Source=MyServer%3BIntegrated Security=True%3BPooling=False%3B;DefaultDataPath=d:\data\&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;F&amp;#246;r att f&amp;#229; den att k&amp;#246;ra m&amp;#229;ste man l&amp;#228;gga den i en Target och se till att den exekveras ihop med den &amp;#246;vriga kompileringen:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;AfterCompile&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;DependsOnTargets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(AfterCompile);BuildDatabaseForDeploy&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;BuildDatabaseForDeploy&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MSBuild&lt;/span&gt; &lt;span class="attr"&gt;Projects&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(SolutionRoot)/Database/MyDatabase/MyDatabase.dbproj&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Targets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Rebuild&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Properties&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;TargetDatabase=MyDb; TargetConnectionString=Data Source=MyServer%3BIntegrated Security=True%3BPooling=False%3B;DefaultDataPath=d:\data\&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Deploy&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;F&amp;#246;r att deploya till en sql server k&amp;#246;r man MSBuild igen, men med Deploy som Targets. Detta g&amp;#246;rs efter det att bygget droppats.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;AfterDropBuild&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;DependsOnTargets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(AfterDropBuild);DeployDatabase&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;DeployDatabase&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;DependsOnTargets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;BuildDatabaseForDeploy&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MSBuild&lt;/span&gt; &lt;span class="attr"&gt;Projects&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(SolutionRoot)/Database/MyDatabase/MyDatabase.dbproj&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Targets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Deploy&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Properties&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;TargetDatabase=MyDb; TargetConnectionString=Data Source=MyServer%3BIntegrated Security=True%3BPooling=False%3B;DefaultDataPath=d:\data\&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Snygga till det hela&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Koden ovan &amp;#228;r det minimala man m&amp;#229;ste g&amp;#246;ra, f&amp;#246;r att f&amp;#229; det hela lite snyggare b&amp;#246;r man samla alla inst&amp;#228;llningar p&amp;#229; ett st&amp;#228;lle. N&amp;#228;r man bygger f&amp;#246;r deploy s&amp;#229; skapas ingen sql-fil i drops-katalogen. Man f&amp;#229;r heller inget meddelande om att stegen k&amp;#246;rs. Nedanst&amp;#229;ende fixar till det. L&amp;#228;gg in det f&amp;#246;re &amp;lt;/Project&amp;gt; i TFSBuild.proj. &lt;br /&gt;  &lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DbDeployTargetConnectionString&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot; '$(DbDeployTargetConnectionString)'==''&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Data Source=MyServer%3BIntegrated Security=True%3BPooling=False%3B&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;DbDeployTargetConnectionString&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DbDeployTargetDatabase&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot; '$(DbDeployTargetDatabase)'==''&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;MyDb&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;DbDeployTargetDatabase&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DbDeployDefaultDataPath&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot; '$(DbDeployDefaultDataPath)'==''&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;d:\data\&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;DbDeployDefaultDataPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DbDeployBuildScriptName&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot; '$(DbDeployBuildScriptName)'==''&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(DbDeployTargetDatabase)_Deploy.sql&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;DbDeployBuildScriptName&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DatabaseProjectFilePath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(SolutionRoot)/Database/MyDatabase/MyDatabase.dbproj&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;DatabaseProjectFilePath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DbForDeployProperties&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot; '$(DbForDeployProperties)'==''&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    TargetDatabase=$(DbDeployTargetDatabase);&lt;br /&gt;    TargetConnectionString=$(DbDeployTargetConnectionString);&lt;br /&gt;    DefaultDataPath=$(DbDeployDefaultDataPath);&lt;br /&gt;    BuildScriptName=$(DbDeployBuildScriptName);&lt;br /&gt;    OutputPath=$(BinariesRoot)&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;DbForDeployProperties&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;AfterCompile&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;DependsOnTargets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(AfterCompile);BuildDatabaseForDeploy&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;BuildDatabaseForDeploy&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;BuildStep&lt;/span&gt; &lt;span class="attr"&gt;TeamFoundationServerUrl&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(TeamFoundationServerUrl)&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class="attr"&gt;BuildUri&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(BuildUri)&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class="attr"&gt;Message&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Building database for deployment.&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Output&lt;/span&gt; &lt;span class="attr"&gt;TaskParameter&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Id&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;PropertyName&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;StepId&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;BuildStep&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MSBuild&lt;/span&gt; &lt;span class="attr"&gt;Projects&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(DatabaseProjectFilePath)&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Targets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Rebuild&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Properties&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(DbForDeployProperties)&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;BuildStep&lt;/span&gt; &lt;span class="attr"&gt;TeamFoundationServerUrl&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(TeamFoundationServerUrl)&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class="attr"&gt;BuildUri&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(BuildUri)&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class="attr"&gt;Id&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(StepId)&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class="attr"&gt;Status&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Succeeded&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;OnError&lt;/span&gt; &lt;span class="attr"&gt;ExecuteTargets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;DbMarkBuildStepAsFailed&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;AfterDropBuild&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;DependsOnTargets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(AfterDropBuild);DeployDatabase&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;DeployDatabase&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;DependsOnTargets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;BuildDatabaseForDeploy&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;BuildStep&lt;/span&gt; &lt;span class="attr"&gt;TeamFoundationServerUrl&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(TeamFoundationServerUrl)&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class="attr"&gt;BuildUri&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(BuildUri)&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class="attr"&gt;Message&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Deploying database.&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Output&lt;/span&gt; &lt;span class="attr"&gt;TaskParameter&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Id&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;PropertyName&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;StepId&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;BuildStep&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MSBuild&lt;/span&gt; &lt;span class="attr"&gt;Projects&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(DatabaseProjectFilePath)&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Targets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Deploy&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Properties&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(DbForDeployProperties)&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;BuildStep&lt;/span&gt; &lt;span class="attr"&gt;TeamFoundationServerUrl&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(TeamFoundationServerUrl)&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class="attr"&gt;BuildUri&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(BuildUri)&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class="attr"&gt;Id&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(StepId)&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class="attr"&gt;Status&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Succeeded&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;OnError&lt;/span&gt; &lt;span class="attr"&gt;ExecuteTargets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;DbMarkBuildStepAsFailed&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;DbMarkBuildStepAsFailed&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;BuildStep&lt;/span&gt; &lt;span class="attr"&gt;TeamFoundationServerUrl&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(TeamFoundationServerUrl)&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class="attr"&gt;BuildUri&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(BuildUri)&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class="attr"&gt;Id&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(StepId)&amp;quot;&lt;/span&gt;&lt;br /&gt;      &lt;span class="attr"&gt;Status&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Failed&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;S&amp;#229; h&amp;#228;r ser det ut n&amp;#228;r det byggs:&lt;br /&gt;  &lt;br /&gt;&lt;a href="http://lh6.ggpht.com/Hakan.Canberger/SC7_WgBBWiI/AAAAAAAAABU/qEAaVeTrCUY/Steps%5B3%5D.png"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="158" alt="Steps" src="http://lh4.ggpht.com/Hakan.Canberger/SC7_XABBWjI/AAAAAAAAABg/6eVlSyo6GB4/Steps_thumb%5B1%5D.png" width="464" border="0" /&gt;&lt;/a&gt; .&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Att deploya applikationen &amp;#228;r en annan historia. Vi deployar webapparna med en &lt;a href="http://msdn.microsoft.com/en-us/library/3e54c37h.aspx"&gt;Copy Task&lt;/a&gt; och sen har vi en egenutvecklad Task som &amp;#228;ndrar v&amp;#228;rden i web.config-filerna s&amp;#229; att det passar milj&amp;#246;n applikationen ligger i.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- Bloggtoppen.se --&gt; &lt;a href="http://www.bloggtoppen.se/"&gt;&lt;img border="0" src="http://www.bloggtoppen.se/tracker.php?do=in&amp;id=12520" alt="Bloggtoppen.se" /&gt;&lt;/a&gt; &lt;!-- /Bloggtoppen.se --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212091881452213631-1160063684917417363?l=hockeswe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hockeswe.blogspot.com/feeds/1160063684917417363/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8212091881452213631&amp;postID=1160063684917417363' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/1160063684917417363'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/1160063684917417363'/><link rel='alternate' type='text/html' href='http://hockeswe.blogspot.com/2008/05/bygga-database-project-i-tfs.html' title='Bygga Database Project i TFS'/><author><name>Håkan Canberger</name><uri>http://www.blogger.com/profile/07785350579880064843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/Hakan.Canberger/SC7_XABBWjI/AAAAAAAAABg/6eVlSyo6GB4/s72-c/Steps_thumb%5B1%5D.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8212091881452213631.post-2677444083827906861</id><published>2008-02-19T21:49:00.001+01:00</published><updated>2008-02-19T21:49:00.086+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C# 3.0'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>C# 3.0: Automatiskt implementerade egenskaper</title><content type='html'>&lt;p&gt;Jag tänkte jag skulle beskriva lite om nyheterna i C# 3.0. Det finns väl en hel del av dessa beskrivningar ute på nätet nu, men jag har inte sett någon riktigt bra på svenska som gått lite mer på djupet. &lt;/p&gt; &lt;p&gt;Först ut är automatiskt implementerade egenskaper (eng. &lt;em&gt;auto-implemented properties&lt;/em&gt;).&lt;/p&gt; &lt;h2&gt;C# 2.0&lt;/h2&gt; &lt;p&gt;I C# 2.0 skrivs properties så här:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; _name;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Name&lt;br /&gt;{&lt;br /&gt;    get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _name; }&lt;br /&gt;    set { _name = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt;	font-size: small;&lt;br /&gt;	color: black;&lt;br /&gt;	font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt;	background-color: #ffffff;&lt;br /&gt;	/*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt;	background-color: #f4f4f4;&lt;br /&gt;	width: 100%;&lt;br /&gt;	margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;br /&gt;&lt;/style&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;C# 3.0&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;Självklart kan du fortsätta skriva properties på samma sätt som i 2.0, men eftersom många properties är just enkla hämta-lagra-ett-värde så finns det i C# 3.0 ett mer kompakt sätt att skriva ovanstående på.&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Name { get; set; }&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Båda varianterna är i princip ekvivalenta. Kompilatorn kommer automatiskt att generera en privat variabel, som sen används på samma sätt som _name. Den lägger dessutom till attributet &lt;a title="The CompilerGenerated Attribute at MSDN" href="http://msdn2.microsoft.com/en-us/library/system.runtime.compilerservices.compilergeneratedattribute.aspx"&gt;CompilerGenerated&lt;/a&gt; för att markera att get- och set-metoderna är genererade av kompilatorn.&lt;/p&gt;&lt;br /&gt;&lt;p style="margin-left: 2em"&gt;&lt;strong&gt;Sidospår:&lt;/strong&gt; En property består i själva verket av en get-metod och en set-metod. Så Name har en metod: string get_Name() och en void set_Name(string value). Det är båda dessa som markeras med attributet &lt;a title="The CompilerGenerated Attribute at MSDN" href="http://msdn2.microsoft.com/en-us/library/system.runtime.compilerservices.compilergeneratedattribute.aspx"&gt;CompilerGenerated&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;På samma sätt som i 2.0 kan man ange private/protected på set för att göra en, utifrån sett, read-only property:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Name { get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set; }&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Name2 { get; &lt;span class="kwrd"&gt;protected&lt;/span&gt; set; }&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Observera att man måste ha både get och set. Så följande är inte tillåtet:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;pre class="csharpcode" style="text-decoration: line-through"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Name { get; }&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Name2 { set; }&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Varför ska man kunna hämta ett värde när man inte kan sätta det, och vice-versa?&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Tips: &lt;/strong&gt;I Visual Studio skapar man properties enklast genom att skriva &lt;em&gt;prop&lt;/em&gt; och trycka tab två gånger.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;Läs mer&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;Kortfattad summering:&lt;br&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/bb384054.aspx"&gt;http://msdn2.microsoft.com/en-us/library/bb384054.aspx&lt;/a&gt;&lt;br&gt;Scott Guthrie förklarar:&lt;br&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2007/03/08/new-c-orcas-language-features-automatic-properties-object-initializers-and-collection-initializers.aspx"&gt;http://weblogs.asp.net/scottgu/archive/2007/03/08/new-c-orcas-language-features-automatic-properties-object-initializers-and-collection-initializers.aspx&lt;/a&gt;&lt;br&gt;Detaljerna kring vad som händer under skalet:&lt;br&gt;&lt;a href="http://community.bartdesmet.net/blogs/bart/archive/2007/03/03/c-3-0-automatic-properties-explained.aspx"&gt;http://community.bartdesmet.net/blogs/bart/archive/2007/03/03/c-3-0-automatic-properties-explained.aspx&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- Bloggtoppen.se --&gt; &lt;a href="http://www.bloggtoppen.se/"&gt;&lt;img border="0" src="http://www.bloggtoppen.se/tracker.php?do=in&amp;id=12520" alt="Bloggtoppen.se" /&gt;&lt;/a&gt; &lt;!-- /Bloggtoppen.se --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212091881452213631-2677444083827906861?l=hockeswe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hockeswe.blogspot.com/feeds/2677444083827906861/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8212091881452213631&amp;postID=2677444083827906861' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/2677444083827906861'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/2677444083827906861'/><link rel='alternate' type='text/html' href='http://hockeswe.blogspot.com/2008/02/c-30-automatiskt-implementerade.html' title='C# 3.0: Automatiskt implementerade egenskaper'/><author><name>Håkan Canberger</name><uri>http://www.blogger.com/profile/07785350579880064843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8212091881452213631.post-8660942796842012864</id><published>2008-01-03T14:34:00.001+01:00</published><updated>2008-01-03T15:21:05.707+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Currying i Javascript</title><content type='html'>&lt;p&gt;En trevlig sak som finns i funktionella språk är &lt;a href="http://en.wikipedia.org/wiki/Currying"&gt;currying&lt;/a&gt; och partial application, vilket lite förenklat kan förklaras som att om man anropar en funktion med färre argument än vad funktionen kräver får man tillbaka en ny funktion som kräver de resterande argumenten (egentligen står currying för själva transformerandet av en funktion till en annan).&lt;/p&gt; &lt;p&gt;Anta att vi har en funktion add som givet två tal, a &amp;amp; b, adderar dem med varandra.&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;function&lt;/span&gt; add a b -&amp;gt; a+b&lt;/pre&gt;&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt;	font-size: small;&lt;br /&gt;	color: black;&lt;br /&gt;	font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt;	background-color: #ffffff;&lt;br /&gt;	/*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt;	background-color: #f4f4f4;&lt;br /&gt;	width: 100%;&lt;br /&gt;	margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;br /&gt;&lt;/style&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Då kan du skapa en ny funktion increase som alltid adderar 1 till ett tal så här&lt;/p&gt;&lt;pre class="csharpcode"&gt;increase = add (1)&lt;br&gt;increase (7)   ==&amp;gt;  ger resultatet 8&lt;/pre&gt;&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt;	font-size: small;&lt;br /&gt;	color: black;&lt;br /&gt;	font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt;	background-color: #ffffff;&lt;br /&gt;	/*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt;	background-color: #f4f4f4;&lt;br /&gt;	width: 100%;&lt;br /&gt;	margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;br /&gt;&lt;/style&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Trivialt exempel, men det visar att man på det här sättet kan låta funktioner vara byggblock som kan återanvändas och ingå i andra funktioner på enkelt sätt.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Svend Tofte har en intressant artikel om hur detta kan göras i Javascript (han har även ett exempel som visar när currying kan vara användbart): &lt;a title="http://www.svendtofte.com/code/curried_javascript/" href="http://www.svendtofte.com/code/curried_javascript/"&gt;http://www.svendtofte.com/code/curried_javascript/&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Och, ja man kan fippla till det även i C#: &lt;a href="http://diditwith.net/2007/08/15/TheArtOfCurrying.aspx"&gt;http://diditwith.net/2007/08/15/TheArtOfCurrying.aspx&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- Bloggtoppen.se --&gt; &lt;a href="http://www.bloggtoppen.se/"&gt;&lt;img border="0" src="http://www.bloggtoppen.se/tracker.php?do=in&amp;id=12520" alt="Bloggtoppen.se" /&gt;&lt;/a&gt; &lt;!-- /Bloggtoppen.se --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212091881452213631-8660942796842012864?l=hockeswe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hockeswe.blogspot.com/feeds/8660942796842012864/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8212091881452213631&amp;postID=8660942796842012864' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/8660942796842012864'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/8660942796842012864'/><link rel='alternate' type='text/html' href='http://hockeswe.blogspot.com/2008/01/currying-i-javascript.html' title='Currying i Javascript'/><author><name>Håkan Canberger</name><uri>http://www.blogger.com/profile/07785350579880064843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8212091881452213631.post-944304409476318134</id><published>2007-10-09T19:28:00.001+02:00</published><updated>2007-10-09T19:29:33.341+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Asp.net'/><title type='text'>Event som inte höjs för dynamiskt skapa kontroller</title><content type='html'>&lt;p&gt;En kollega hade problem med att ett Click-event för en dynamiskt skapad kontroll inte höjdes vid vissa postbacks. Oftast brukar problem med att event inte höjs för en dynamiskt skapad kontroll hänga ihop med att dess ID ändras mellan postbacks. Så även denna gång.&lt;/p&gt; &lt;h2&gt;Sidan och problemet&lt;/h2&gt; &lt;p&gt;Förenklat sett, består sidan av en lista med saker och en dropdownlist som används som val för att filtrera listan. Initialt visar listan upp alla saker. I slutet på varje rad i listan finns en knapp (en ImageButton). Saker ska hända när man klickar på knappen genom en eventhanterare på knappens Click-event,&lt;/p&gt; &lt;p&gt;När man visar sidan för första gången visar listan alla saker och ett klick på en av knapparna leder till att eventet höjs.&lt;/p&gt; &lt;p&gt;När man väljer något i dropdownlisten så autopostbackar sidan och listan populeras om. Klickar man nu på någon knapp görs en postback men eventet höjs aldrig. Sidan returneras. Ett klick på en knapp nu fungerar; eventet höjs.&lt;/p&gt; &lt;p&gt;Så direkt efter att man gjort ett val slutar eventet att höjas, för att vi nästa försök fungera igen. &lt;/p&gt; &lt;h2&gt;Hur listan byggs upp&lt;/h2&gt; &lt;p&gt;Listan byggs upp i en metod MyCreateControls() som anropas i Page_Load. I metoden hämtas en lista med saker att visa. För varje sak i listan laddas en UserControl, lite värden sätts på UserControl-instansen och den läggs till en PlaceHolders ControlCollection via propertyn Controls. &lt;/p&gt; &lt;h3&gt;Pseudokod för MyCreateControls&lt;/h3&gt;&lt;pre class="csharpcode"&gt;MyCreateControls()&lt;br /&gt;  PlaceHolder1.Controls.Clear()&lt;br /&gt;  DataList=GetData()&lt;br /&gt;  ForEach(item &lt;span class="kwrd"&gt;in&lt;/span&gt; DataList)&lt;br /&gt;  {&lt;br /&gt;    ctrl=MyCreateControl()&lt;br /&gt;    ctrl.data=item.data&lt;br /&gt;    PlaceHolder1.Controls.Add(ctrl)&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt;	font-size: small;&lt;br /&gt;	color: black;&lt;br /&gt;	font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt;	background-color: #ffffff;&lt;br /&gt;	/*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt;	background-color: #f4f4f4;&lt;br /&gt;	width: 100%;&lt;br /&gt;	margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;br /&gt;&lt;/style&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;När man väljer ett item i dropdownlistan anropas MyCreateControls. PlaceHoldern rensas på alla kontroller med Controls.Clear() (PostBackEvents höjs efter OnLoad som redan hunnit fylla på listan enligt de gamla kriterierna) och därefter fylls PlaceHoldern på som beroende på valet i dropdownlistan kommer att använda en annan lista av saker. &lt;/p&gt;&lt;br /&gt;&lt;h2&gt;&lt;a title="UniqueID" href="http://msdn2.microsoft.com/en-us/library/system.web.ui.control.uniqueid.aspx"&gt;UniqueID&lt;/a&gt;&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;Varje kontroll, och då menar jag Control, har en property &lt;a title="UniqueID" href="http://msdn2.microsoft.com/en-us/library/system.web.ui.control.uniqueid.aspx"&gt;UniqueID&lt;/a&gt; med ett id som är unikt för just den kontrollen. Detta id består av två delar: den första delen är UniqueID för den &lt;a href="http://msdn2.microsoft.com/en-us/library/system.web.ui.control.namingcontainer.aspx"&gt;NamingContainer&lt;/a&gt; som kontrollen ligger i; den andra delen är kontrollens ID. Så för en kontroll med ID="MyChildControl" som ligger i en NamingContainer-kontroll med UniqueID="MyParent" är UniqueId="MyParent:MyChildControl". Separatorn kan också vara "$".&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Om kontrollen saknar id används en löpnummerserie i stil med "ctl00", "ctl01" och vi får då UniqueId="MyParent:ctl00". Skapandet av ID om kontrollen saknar ett görs i Control.GenerateAutomaticID() som, för varje gång den behöver skapa ett unikt id, räknar upp ett värde på kontrollens NamingControl. Så lägger vi till tre kontroller som saknar ID till en NamingControl kommer här värdet att räknas upp från 0 till 1 till 2 till 3 (den sista kontrollen får ID="ctl02"). Detta värde nollställs eller räknas aldrig ner så tar vi sen bort dessa tre kontroller och lägger dit en ny, som också saknar ID kommer den att få ID="ctl03" och värdet har räknats upp till 4.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;När vi ändå håller på: ClientId är UniqueId med "_" som separator istället för ":".&amp;nbsp; Så vi får då: "MyParent_MyChildControl"&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;&lt;a title="UniqueID" href="http://msdn2.microsoft.com/en-us/library/system.web.ui.control.uniqueid.aspx"&gt;UniqueID&lt;/a&gt; och PostBacks&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;När en kontroll, t.ex. en ImageButton (som skrivs ut som en &amp;lt;input type="image"&amp;gt;-HTML-kontroll) postar tillbaka värden görs det under dess UniqueID. Så om man klickar på en ImageButton som har UniqueID="MyParent:ImageButton1" kommer den att skicka tillbaka den x- och y-koordinat man klickade på under "MyParent:ImageButton1.x" och "MyParent:ImageButton1.y". Det här gör att Asp.Net vet till vilken kontroll varje postat värde hör till.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;Problemet denna gång&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;Tillbaka till det faktiska problement. UserControlen som lades i PlaceHoldern fick inget ID satt. Det gjorde att varje UserControl fick UniqueID i stil med: "xx:PlaceHolder1:ctl00", "xx:PlaceHolder1:ctl01" osv. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;Antag att vi via Page_Load lagt till tio kontroller (den sista kontrollen får ID="ctl09"). Om man valt ett nytt värde i dropdownen kommer MyCreateControls() att anropas igen och dessa tio kontroller tas då bort ur Controls. Istället kommer till exempel tre nya kontroller att läggas till. Den första nya kontrollen blir dock inte "ctl00" utan "ctl10", eftersom det är så Control.GenerateAutomaticID fungerar: den fortsätter på löpnummerserien. Så vi har då de tre kontrollerna "ctl10", "ctl11" och "ctl12".&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Vad händer då när man klickar på den första ImageButton-kontrollen som ligger i den första UserControlen? Den har UniqueID="xx:PlaceHolder1:ctl10:ImageButton1", så x- och y-koordinaten skickas i "xx:PlaceHolder1:ctl10:ImageButton1.x" och "xx:PlaceHolder1:ctl10:ImageButton1.y".&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Men Page_Load som bygger upp de tre kontrollerna på nytt kommer denna gång att skapa "ctl00", "ctl01" och "ctl02" (eftersom räknaren alltid börjar på noll och det är de första kontrollerna vi lägger till). Gissa vad som händer då med våra x- och y-värden. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;Absolut ingenting. Det finns ingen ImageButton1 som ligger i en kontroll med UniqueID="xx:PlaceHolder1:ctl10". Och eftersom inga x- och y-värden ändras på någon kontroll kommer inte någon ImageButton att höja sitt Click-event. Sidan skickas tillbaka.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Men, klickar man på knappen denna gång så skickas "xx:PlaceHolder1:ctl00:ImageButton1.x" och "xx:PlaceHolder1:ctl01:ImageButton1.y" och den här gången finns det en ImageButton1 som ligger i en NamingContainer med UniqueID="xx:PlaceHolder1:ctl00" vilket gör att värdena hamnar rätt. I och med att dessa värden sätts så kommer ImageButton1 att höja sitt Click-event.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;Lösningen&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;Den enkla lösningen är att själv ange ett ID med en löpnummerserie, t.ex. C0, C1 osv.)&amp;nbsp; som nollställs i i början av MyCreateControls(). Det här säkerställer att första kontrollen alltid får id=C0, och därmed kommer PostBack-värdena att alltid hamna rätt.&lt;/p&gt;&lt;pre class="csharpcode"&gt;MyCreateControls()&lt;br /&gt;  PlaceHolder1.Controls.Clear()&lt;br /&gt;  DataList=GetData()&lt;br /&gt;  Counter=0&lt;br /&gt;  ForEach(item &lt;span class="kwrd"&gt;in&lt;/span&gt; DataList)&lt;br /&gt;  {&lt;br /&gt;    ctrl=MyCreateControl()&lt;br /&gt;    ctrl.data=item.data&lt;br /&gt;    ctrl.ID=&lt;span class="str"&gt;"C"&lt;/span&gt;+Counter&lt;br /&gt;    PlaceHolder1.Controls.Add(ctrl)&lt;br /&gt;    Counter=Counter+1&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt;	font-size: small;&lt;br /&gt;	color: black;&lt;br /&gt;	font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt;	background-color: #ffffff;&lt;br /&gt;	/*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt;	background-color: #f4f4f4;&lt;br /&gt;	width: 100%;&lt;br /&gt;	margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;br /&gt;&lt;/style&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Avslutningsvis&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;Om du har problem med att event höjs ibland och ibland inte, ta dig en titt på kontrollernas ID:n. Ändrar de sig mellan postbacks så har du troligen orsaken där.&lt;/p&gt; &lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- Bloggtoppen.se --&gt; &lt;a href="http://www.bloggtoppen.se/"&gt;&lt;img border="0" src="http://www.bloggtoppen.se/tracker.php?do=in&amp;id=12520" alt="Bloggtoppen.se" /&gt;&lt;/a&gt; &lt;!-- /Bloggtoppen.se --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212091881452213631-944304409476318134?l=hockeswe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hockeswe.blogspot.com/feeds/944304409476318134/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8212091881452213631&amp;postID=944304409476318134' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/944304409476318134'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/944304409476318134'/><link rel='alternate' type='text/html' href='http://hockeswe.blogspot.com/2007/10/event-som-inte-hjs-fr-dynamiskt-skapa.html' title='Event som inte höjs för dynamiskt skapa kontroller'/><author><name>Håkan Canberger</name><uri>http://www.blogger.com/profile/07785350579880064843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8212091881452213631.post-270542671029249988</id><published>2007-10-02T14:03:00.001+02:00</published><updated>2007-10-02T14:03:57.547+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Optimera'/><category scheme='http://www.blogger.com/atom/ns#' term='Asp.net'/><title type='text'>ID-optimering, fortsättning</title><content type='html'>&lt;p&gt;Jag skrev i en &lt;a title="Anv&amp;auml;nd korta ID:n p&amp;aring; tunga sidor" href="http://hockeswe.blogspot.com/2007/10/anvnd-korta-id-p-tunga-sidor.html"&gt;tidigare bloggpost&lt;/a&gt; om hur man enkelt kan optimera sina sidor genom att välja korta ID:n på sina Asp.Net-kontroller. Det här är en fortsättning.&lt;/p&gt; &lt;h2&gt;ID på kontroller som saknar ID&lt;/h2&gt; &lt;p&gt;Vissa kontroller saknar ID:n. De får då ett ID av typen ctl00, ctl01, ctl02 och så vidare. Det kan därför vara god idé att tilldela dessa kontroller ett ID som är kortare.&lt;/p&gt; &lt;h2&gt;ID på MasterPage&lt;/h2&gt; &lt;p&gt;På sajter där man använder MasterPages sidor så visar det sig att alla ID:n börjar med ctl00. Med största sannolikhet så kommer den delen från själva MasterPage-kontrollen, eftersom de flesta inte bryr sig om att sätta något ID på den.&lt;/p&gt; &lt;p&gt;&lt;br&gt;För att sätta ID på en masterpage får man gå in i dess konstruktor och där sätta ID. Om masterpage-kontrollen heter DefaultMasterPage.master, så ska följande kod läggas till i dess code behind:&lt;/p&gt;&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; DefaultMasterPage()&lt;br /&gt;    {&lt;br /&gt;        ID = &lt;span class="str"&gt;"M"&lt;/span&gt;;&lt;br /&gt;    } &lt;/pre&gt;&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt;	font-size: small;&lt;br /&gt;	color: black;&lt;br /&gt;	font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt;	background-color: #ffffff;&lt;br /&gt;	/*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt;	background-color: #f4f4f4;&lt;br /&gt;	width: 100%;&lt;br /&gt;	margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;br /&gt;&lt;/style&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Den förändringen slår i genom på &lt;em&gt;alla&lt;/em&gt; kontroller på &lt;em&gt;alla&lt;/em&gt; sidor (som utnyttjar DefaultMasterPage).&lt;/p&gt; &lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- Bloggtoppen.se --&gt; &lt;a href="http://www.bloggtoppen.se/"&gt;&lt;img border="0" src="http://www.bloggtoppen.se/tracker.php?do=in&amp;id=12520" alt="Bloggtoppen.se" /&gt;&lt;/a&gt; &lt;!-- /Bloggtoppen.se --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212091881452213631-270542671029249988?l=hockeswe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hockeswe.blogspot.com/feeds/270542671029249988/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8212091881452213631&amp;postID=270542671029249988' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/270542671029249988'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/270542671029249988'/><link rel='alternate' type='text/html' href='http://hockeswe.blogspot.com/2007/10/id-optimering-fortsttning.html' title='ID-optimering, fortsättning'/><author><name>Håkan Canberger</name><uri>http://www.blogger.com/profile/07785350579880064843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8212091881452213631.post-3514513474619937573</id><published>2007-10-01T18:04:00.001+02:00</published><updated>2007-10-03T14:27:51.248+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Optimera'/><category scheme='http://www.blogger.com/atom/ns#' term='Asp.net'/><title type='text'>Använd korta ID på tunga sidor</title><content type='html'>&lt;p&gt;I projektet jag jobbar i nu har vi en rätt tung sida: den är komplex till sin struktur, mycket nästlade kontroller och mycket databindning.  &lt;p&gt;Eftersom vi när vi byggde sidan koncentrerade oss på funktionalitet framför att få den snabb blev vi nu, såklart, tvungna att optimera sidan.  &lt;p&gt;Jag har precis påbörjat arbetet. En första sak jag gjorde var att byta ut alla ID:n. Från saker som RepeaterAllRooms och ContainerValidators till RR och CV.  &lt;h2&gt;ID:n "ärvs"&lt;/h2&gt; &lt;p&gt;Ju högre upp en kontroll är i hierarkin desto viktigare är det att få ID:et kort, eftersom föräldrars ID används för att skapa en kontrolls unika ID. Så alla rader i kontrollen RepeaterAllRooms får ID i stil med RepeaterAllRooms_RoomRow1, RepeaterAllRooms_RoomRow2, etc. Dessutom ligger ju de i sin tur i en container som ligger i en container som ligger i en container som…  &lt;p&gt;Längst ner i hierarkin har vi input-fält. Varje fält fick ID:n i stil med:&lt;br&gt;&lt;em&gt;ctl00_ctl00_ContentPlaceHolder1_tabContentPlaceHolder_RateAllotmentEditView1_&lt;br&gt;RateAllotmentControl_MultiTemplatePeriods_I0_RepeaterRooms_I0_RepeatedColumns_&lt;br&gt;ctl01_ColumnData_colPercentage_txt&lt;/em&gt;  &lt;p&gt;Eftersom det är ett input-fält får den dessutom lika långt Name:&lt;br&gt;&lt;em&gt;ctl00$ctl00$ContentPlaceHolder1$tabContentPlaceHolder$RateAllotmentEditView1$&lt;br&gt;RateAllotmentControl$MultiTemplatePeriods$I0$RepeaterRooms$I0$RepeatedColumns$&lt;br&gt;ctl01$ColumnData$colPercentage$txt&lt;/em&gt;  &lt;p&gt;Med 100 fält blir sedan snabbt rätt tung. Inte nog med det; ViewState blir tungt också eftersom ID:n används även där.  &lt;h2&gt;36% html-kod försvann&lt;/h2&gt; &lt;p&gt;Före förändringen var HTML-koden för sidan på runt 338 kB. Efter kortare-ID-bytet var sidan nere i 216 kB. Rätt stor förändring utan särskilt mycket jobb!&amp;nbsp; &lt;p&gt;Nästa steg blir bl.a. att se över ViewState.  &lt;h2&gt;Förkorta, förkorta, förkorta&lt;/h2&gt; &lt;p&gt;Så se till att använda korta ID:n. Kör du med MasterPages, byt ut ContentPlaceHolder1 mot t.ex. CPH eftersom ALLA kontroller under det kommer att innehålla strängen ContentPlaceHolder1. På vår sida gav bara det en minskning med 14 kB. Kontroller som i sin tur innehåller många andra kontroller, som t.ex. en databunden Repeater, är goda kandidater för förkortning.&lt;/p&gt; &lt;p&gt;Att förkorta ID måste man ju såklart väga mot att få läsbar kod.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;div class="blogger-post-footer"&gt;&lt;strong&gt;Edit 2007-10-02 17:42&lt;br&gt;&lt;/strong&gt;Givetvis ska man inte byt ut alla ID:n för alla kontroller, utan enbart såna som faktiskt påverkar slutresultatet nämnvärt, dvs. enbart de kontroller som gör att html-koden bli nämnvärt mindre. Övriga kontroller låter man vara.&lt;/div&gt; &lt;div class="blogger-post-footer"&gt;&amp;nbsp;&lt;/div&gt; &lt;div class="blogger-post-footer"&gt;Effekten på sidor som komprimeras är så klart mindre än okomprimerade sidor.&lt;/div&gt; &lt;div class="blogger-post-footer"&gt;&lt;br&gt;&lt;!-- Bloggtoppen.se --&gt;&lt;a href="http://www.bloggtoppen.se/"&gt;&lt;img alt="Bloggtoppen.se" src="http://www.bloggtoppen.se/tracker.php?do=in&amp;amp;id=12520" border="0"&gt;&lt;/a&gt; &lt;!-- /Bloggtoppen.se --&gt;&lt;/div&gt; &lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- Bloggtoppen.se --&gt; &lt;a href="http://www.bloggtoppen.se/"&gt;&lt;img border="0" src="http://www.bloggtoppen.se/tracker.php?do=in&amp;id=12520" alt="Bloggtoppen.se" /&gt;&lt;/a&gt; &lt;!-- /Bloggtoppen.se --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212091881452213631-3514513474619937573?l=hockeswe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hockeswe.blogspot.com/feeds/3514513474619937573/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8212091881452213631&amp;postID=3514513474619937573' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/3514513474619937573'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/3514513474619937573'/><link rel='alternate' type='text/html' href='http://hockeswe.blogspot.com/2007/10/anvnd-korta-id-p-tunga-sidor.html' title='Använd korta ID på tunga sidor'/><author><name>Håkan Canberger</name><uri>http://www.blogger.com/profile/07785350579880064843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8212091881452213631.post-1004993752375812426</id><published>2007-09-15T13:06:00.001+02:00</published><updated>2007-09-17T15:42:49.140+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ajax'/><category scheme='http://www.blogger.com/atom/ns#' term='Asp.net'/><title type='text'>$get och $find i Asp.Net Ajax</title><content type='html'>&lt;p&gt;I Asp.Net Ajax finns två metoder som kan verka snarlika: &lt;em&gt;$get&lt;/em&gt; och &lt;em&gt;$find&lt;/em&gt;. &lt;/p&gt; &lt;h2&gt;$get för DOM-element&lt;/h2&gt; &lt;p&gt;Använd &lt;em&gt;$get(id)&lt;/em&gt; för att få tag på ett DOM-element, t.ex. input, button, a, table, etc. som finns någonstans i dokumentet. Med &lt;em&gt;$get(id,parent)&lt;/em&gt; söker du enbart bland barnen (inkl. barnbarn, barnbarnsbarn, etc) till &lt;em&gt;parent&lt;/em&gt;.&lt;/p&gt; &lt;h2&gt;$find för Sys.Component, Sys.UI.Behavior och Sys.UI.Control&lt;/h2&gt; &lt;p&gt;Använd &lt;em&gt;$find(id)&lt;/em&gt; och &lt;em&gt;$find(id,parent)&lt;/em&gt; för att hitta en Asp.Net Ajax Sys.Component (t.ex. behaviors och Sys.UI-kontroller). Typiskt skapas dessa av ramverket med &lt;em&gt;$create&lt;/em&gt;. Använd inte &lt;em&gt;$find&lt;/em&gt; för att hitta DOM-element.&lt;/p&gt; &lt;p&gt;Mer information:&lt;br&gt;&lt;a title="http://mattberseth.com/blog/2007/08/the_everuseful_get_and_find_as.html" href="http://mattberseth.com/blog/2007/08/the_everuseful_get_and_find_as.html"&gt;http://mattberseth.com/blog/2007/08/the_everuseful_get_and_find_as.html&lt;/a&gt;&lt;br&gt;&lt;a title="http://blogs.msdn.com/irenak/archive/2007/02/19/sysk-290-asp-net-ajax-get-vs-find.aspx" href="http://blogs.msdn.com/irenak/archive/2007/02/19/sysk-290-asp-net-ajax-get-vs-find.aspx"&gt;http://blogs.msdn.com/irenak/archive/2007/02/19/sysk-290-asp-net-ajax-get-vs-find.aspx&lt;/a&gt;&lt;/p&gt; &lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- Bloggtoppen.se --&gt; &lt;a href="http://www.bloggtoppen.se/"&gt;&lt;img border="0" src="http://www.bloggtoppen.se/tracker.php?do=in&amp;id=12520" alt="Bloggtoppen.se" /&gt;&lt;/a&gt; &lt;!-- /Bloggtoppen.se --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212091881452213631-1004993752375812426?l=hockeswe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hockeswe.blogspot.com/feeds/1004993752375812426/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8212091881452213631&amp;postID=1004993752375812426' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/1004993752375812426'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/1004993752375812426'/><link rel='alternate' type='text/html' href='http://hockeswe.blogspot.com/2007/09/get-och-find-i-aspnet-ajax.html' title='$get och $find i Asp.Net Ajax'/><author><name>Håkan Canberger</name><uri>http://www.blogger.com/profile/07785350579880064843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8212091881452213631.post-4193699097753880033</id><published>2007-07-27T17:34:00.001+02:00</published><updated>2007-07-27T17:34:08.120+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Asp.net'/><title type='text'>AutoEventWireup=true</title><content type='html'>&lt;div class="otherLanguage"&gt;&lt;a href="http://hocke.blogspot.com/2007/07/autoeventwireuptrue.html"&gt;English version of this entry&lt;/a&gt;&lt;/div&gt; &lt;p&gt;Om du på en Web User Control eller sida skriver &lt;em&gt;AutoEventWireup=True&lt;/em&gt; kommer metoder som t.ex.&lt;em&gt; Page_Init() &lt;/em&gt;och &lt;em&gt;Page_Load() &lt;/em&gt;att automatiskt hakas på sidans &lt;em&gt;Init&lt;/em&gt;- resp. &lt;em&gt;Load&lt;/em&gt;-event.&lt;/p&gt; &lt;p&gt;Detta är bra ibland, dumt ibland. Smidigt för man slipper haka på eventen själv. Dumt därför att det är något som görs i runtime (tar därmed tid) och kan leda till att event anropas flera gånger.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Exempel: Event-hanterare som anropas två gånger.&lt;/strong&gt;&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: rgb(0,0,255)"&gt;protected&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;void&lt;/span&gt; Page_Init()&lt;br /&gt;{&lt;br /&gt;    Page.Load += Page_Load;&lt;br /&gt;}&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;protected&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;void&lt;/span&gt; Page_Load(&lt;span style="color: rgb(0,0,255)"&gt;object&lt;/span&gt; sender, &lt;span style="color: rgb(43,145,175)"&gt;EventArgs&lt;/span&gt; e)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;//This code will execute twice&lt;br /&gt;&lt;/span&gt;}&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;br /&gt;&lt;p&gt;I ovanstående exempel kommer &lt;em&gt;Page_Load&lt;/em&gt; att anropas två gånger. En gång eftersom du manuellt hakat på metoden på &lt;em&gt;Load&lt;/em&gt;-eventet. Ytterligare en gång därför att &lt;em&gt;AutoEventWireup=true&lt;/em&gt; och metoden heter som den gör vilket gör att den automatiskt kommer att hakas på &lt;em&gt;Load&lt;/em&gt;-eventet.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;em&gt;AutoEventWireup&lt;/em&gt; fungerar&amp;nbsp; för &lt;em&gt;TemplateControl&lt;/em&gt; vilket både &lt;em&gt;Page&lt;/em&gt; och &lt;em&gt;Web User Controls&lt;/em&gt; ärver av. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;Du kan, om du vill dock inte nödvändigt, börja med att läsa &lt;a href="http://odetocode.com/Blogs/scott/archive/2006/02/16/2914.aspx"&gt;K Scott Allens bloggpost&lt;/a&gt; om vad &lt;em&gt;AutoEventWireup&lt;/em&gt; gör. Det nedan är en fördjupning på ämnet. :)&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;SupportAutoEvents&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;Vad händer egentligen när &lt;em&gt;AutoEventWireup=true?&lt;/em&gt; En &lt;em&gt;TemplateControl&lt;/em&gt; har en property som heter &lt;em&gt;SupportAutoEvents&lt;/em&gt;. Denna är t&lt;em&gt;rue&lt;/em&gt; per default (och ändras bara till &lt;em&gt;false&lt;/em&gt; av parsern/control buildern&amp;nbsp;som bygger upp kontrollen om man sätter &lt;em&gt;AutoEventWireup=false&lt;/em&gt;).&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;HookUpAutomaticHandlers &lt;/h2&gt;&lt;br /&gt;&lt;p&gt;&lt;em&gt;TemplateControl.HookUpAutomaticHandlers&lt;/em&gt; (vilken anropas under kontrollens &lt;em&gt;OnInit&lt;/em&gt; bland annat) kommer om &lt;em&gt;AutoEventWireup=true&lt;/em&gt; att försöka hitta följande metoder:&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Om kontrollen är Page: &lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Page_PreInit &lt;br /&gt;&lt;li&gt;Page_PreLoad &lt;br /&gt;&lt;li&gt;Page_LoadComplete &lt;br /&gt;&lt;li&gt;Page_PreRenderComplete &lt;br /&gt;&lt;li&gt;Page_InitComplete &lt;br /&gt;&lt;li&gt;Page_SaveStateComplete &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;li&gt;För alla TemplateControls: &lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Page_Init &lt;br /&gt;&lt;li&gt;Page_Load &lt;br /&gt;&lt;li&gt;Page_DataBind &lt;br /&gt;&lt;li&gt;Page_PreRender &lt;br /&gt;&lt;li&gt;Page_Unload &lt;br /&gt;&lt;li&gt;Page_Error &lt;br /&gt;&lt;li&gt;Page_AbortTransaction eller om den inte finns;&amp;nbsp;OnTransactionAbort &lt;br /&gt;&lt;li&gt;Page_CommitTransaction eller om den inte finns; OnTransactionCommit&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;Detta görs i metoden &lt;em&gt;TemplateControl.GetDelegateInformationWithNoAssert()&lt;/em&gt;.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;32 försök&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;Som &lt;a href="http://odetocode.com/Blogs/scott/archive/2006/02/16/2914.aspx"&gt;K Scott Allen&lt;/a&gt; skriver kommer den för varje metodnamn att försöka två gånger. Först försöker den hitta en &lt;em&gt;EventHandler&lt;/em&gt; med det namnet, dvs. en metod med signaturen:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: rgb(0,0,255)"&gt;void&lt;/span&gt; EventHandler(&lt;span style="color: rgb(0,0,255)"&gt;object&lt;/span&gt; sender, &lt;span style="color: rgb(43,145,175)"&gt;EventArgs&lt;/span&gt; e)&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Exempel: Metod som är en EventHandler&lt;/strong&gt;&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: rgb(0,0,255)"&gt;void&lt;/span&gt; Page_PreInit(&lt;span style="color: rgb(0,0,255)"&gt;object&lt;/span&gt; sender, &lt;span style="color: rgb(43,145,175)"&gt;EventArgs&lt;/span&gt; e)&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;br /&gt;&lt;p&gt;Om det misslyckas kommer den försöka att hitta en &lt;em&gt;VoidMethod&lt;/em&gt;, dvs. en metod med signaturen:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: rgb(0,0,255)"&gt;void&lt;/span&gt; VoidMethod()&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Exempel: Metod som är en VoidMethod&lt;/strong&gt;&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: rgb(0,0,255)"&gt;void&lt;/span&gt; Page_PreInit()&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Så om du inte har angivet någon metod alls som matchar något av kriterierna ovan i t.ex. en sida så kommer den ändå att leta efter 32 metoder (och inte 28 som K Scott Allen skrev).&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Resultatet av matchningen kommer att lagras i en cache, och kommer därför inte att anropas varje gång. Men det kommer att anropas åtminstone en gång. :)&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Haka metoden på eventet&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;För alla metoder som matchar kriterierna kommer &lt;em&gt;TemplateControl.HookUpAutomaticHandlers()&lt;/em&gt;&amp;nbsp;att haka metoden på motsvarande event. Detta kommer dock inte att göras om metoden redan har hakats på eventet eftersom &lt;em&gt;HookUpAutomaticHandlers&lt;/em&gt;&amp;nbsp;letar igenom alla event-hanterare för eventet och&amp;nbsp;om den hittar metoden där så struntar den i att lägga till metoden igen.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Men i exemplet ovan så blev ju &lt;em&gt;Page_Load()&lt;/em&gt; påhakat två gånger på samma event? &lt;br&gt;Jepp, men det var för att när vi i &lt;em&gt;Page_Init&lt;/em&gt; hakade på eventet så hade &lt;em&gt;HookUpAutomaticHandlers&lt;/em&gt; redan gjort det. &lt;em&gt;HookUpAutomaticHandlers&lt;/em&gt; anropas ju i &lt;em&gt;OnInit&lt;/em&gt; som körs före vår &lt;em&gt;Page_Init&lt;/em&gt;.&amp;nbsp;Om vi istället hakar på vårt event före sidans&amp;nbsp;&lt;em&gt;OnInit&lt;/em&gt; och därmed före &lt;em&gt;HookUpAutomaticHandlers&lt;/em&gt; anropats så kommer &lt;em&gt;Page_Load&lt;/em&gt; bara att anropas en gång.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Exempel: Page_Load anropas bara en gång.&lt;/strong&gt;&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;partial&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;class&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;_Default&lt;/span&gt; : System.Web.UI.&lt;span style="color: rgb(43,145,175)"&gt;Page&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; _Default()&lt;br /&gt;    {&lt;br /&gt;        Page.Load += Page_Load;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;protected&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;void&lt;/span&gt; Page_Load(&lt;span style="color: rgb(0,0,255)"&gt;object&lt;/span&gt; sender, &lt;span style="color: rgb(43,145,175)"&gt;EventArgs&lt;/span&gt; e)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: rgb(0,128,0)"&gt;//This code will execute once&lt;br /&gt;&lt;/span&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;h2&gt;Slutsats: AutoEventWireup=false&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;Överväg att slå om &lt;em&gt;AutoEventWireup&lt;/em&gt; till &lt;em&gt;false&lt;/em&gt; (den är &lt;em&gt;true&lt;/em&gt;&amp;nbsp;per default) och haka själv på de event du vill använda. Du får mer kontroll över när saker anropas och du slipper den overhead som &lt;em&gt;TemplateControl.HookUpAutomaticHandlers&lt;/em&gt;&amp;nbsp;medför. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;Microsoft själva rekommenderar att man slår av det när hög prestanda är viktigt.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;Mer om AutoEventWireup på MSDN&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;&lt;a title="http://msdn2.microsoft.com/en-us/library/system.web.configuration.pagessection.autoeventwireup.aspx" href="http://msdn2.microsoft.com/en-us/library/system.web.configuration.pagessection.autoeventwireup.aspx"&gt;http://msdn2.microsoft.com/en-us/library/system.web.configuration.pagessection.autoeventwireup.aspx&lt;/a&gt;&lt;br&gt;&lt;a title="http://support.microsoft.com/default.aspx/kb/324151" href="http://support.microsoft.com/default.aspx/kb/324151"&gt;http://support.microsoft.com/default.aspx/kb/324151&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- Bloggtoppen.se --&gt; &lt;a href="http://www.bloggtoppen.se/"&gt;&lt;img border="0" src="http://www.bloggtoppen.se/tracker.php?do=in&amp;id=12520" alt="Bloggtoppen.se" /&gt;&lt;/a&gt; &lt;!-- /Bloggtoppen.se --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212091881452213631-4193699097753880033?l=hockeswe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hockeswe.blogspot.com/feeds/4193699097753880033/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8212091881452213631&amp;postID=4193699097753880033' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/4193699097753880033'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/4193699097753880033'/><link rel='alternate' type='text/html' href='http://hockeswe.blogspot.com/2007/07/autoeventwireuptrue.html' title='AutoEventWireup=true'/><author><name>Håkan Canberger</name><uri>http://www.blogger.com/profile/07785350579880064843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8212091881452213631.post-276776670474396126</id><published>2007-07-10T21:14:00.001+02:00</published><updated>2007-07-10T21:14:49.681+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><title type='text'>Vad Asp.Net-utvecklare bör kunna om JavaScript</title><content type='html'>&lt;p&gt;K. Scott Allen har skrivit en utmärkt artikel om &lt;a href="http://odetocode.com/Articles/473.aspx"&gt;"What ASP.NET Developers Should Know About JavaScript"&lt;/a&gt; &lt;/p&gt; &lt;p&gt;Obligatorisk läsning om man ska koda lite mer avancerad JavaScript på klientsidan.&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Varje objekt i JavaScript&amp;nbsp;är ett dictionary&lt;/li&gt; &lt;li&gt;Vare funktion i JavaScript är även ett objekt&lt;/li&gt; &lt;li&gt;Varje objekt har en prototyp.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Förvirrad? Läs &lt;a href="http://odetocode.com/Articles/473.aspx"&gt;artikeln&lt;/a&gt;!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- Bloggtoppen.se --&gt; &lt;a href="http://www.bloggtoppen.se/"&gt;&lt;img border="0" src="http://www.bloggtoppen.se/tracker.php?do=in&amp;id=12520" alt="Bloggtoppen.se" /&gt;&lt;/a&gt; &lt;!-- /Bloggtoppen.se --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212091881452213631-276776670474396126?l=hockeswe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hockeswe.blogspot.com/feeds/276776670474396126/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8212091881452213631&amp;postID=276776670474396126' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/276776670474396126'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/276776670474396126'/><link rel='alternate' type='text/html' href='http://hockeswe.blogspot.com/2007/07/vad-aspnet-utvecklare-br-kunna-om.html' title='Vad Asp.Net-utvecklare bör kunna om JavaScript'/><author><name>Håkan Canberger</name><uri>http://www.blogger.com/profile/07785350579880064843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8212091881452213631.post-8492132832406527574</id><published>2007-07-10T21:01:00.001+02:00</published><updated>2007-07-10T21:07:10.322+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ajax'/><category scheme='http://www.blogger.com/atom/ns#' term='Extenders'/><category scheme='http://www.blogger.com/atom/ns#' term='Asp.net'/><title type='text'>Utöka en befintlig AjaxControlToolkit Extender</title><content type='html'>&lt;p&gt;I en &lt;a title="Skapa en AjaxControlToolkitExtender" href="http://hockeswe.blogspot.com/2007/05/skapa-en-ajaxcontroltoolkit-extender.html"&gt;tidigare bloggpost&lt;/a&gt; visade jag hur man skapar en AjaxControlToolkitExtender från början. Den här gången tänkte jag visa hur man utökar en befintlig extender med lite ytterligare funktionalitet. Det kan vara bra att läsa den&amp;nbsp;&lt;a title="Skapa en AjaxControlToolkitExtender" href="http://hockeswe.blogspot.com/2007/05/skapa-en-ajaxcontroltoolkit-extender.html"&gt;tidigare bloggposten&lt;/a&gt; först.&lt;/p&gt; &lt;h1&gt;HoverAddsCssClassExtender&lt;/h1&gt; &lt;p&gt;Extendern &lt;em&gt;HoverAddsCssClassExtender&lt;/em&gt; hakas&amp;nbsp;liksom alla extendrar på en befinlig kontroll på sidan, t.ex. en Panel. När muspekaren förs över kontrollen kommer dess class-property (som innehåller&amp;nbsp;css-klassnamn)&amp;nbsp;att utökas med ytterligare ett css-klassnamn. När musen lämnar kontrollen återställs värdet. En klassisk onmouseover-, eller hover-effekt alltså. Traditionellt så brukar man byta css-klassnamnet mot något helt annat, men det är smartare att lägga på ytterligare en regel.&lt;/p&gt; &lt;p&gt;Ett litet exempel kan nog förtydliga vad som händer och hur den används:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;asp&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;:&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;Panel&lt;/span&gt; &lt;span style="color: rgb(255,0,0)"&gt;runat&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;="server"&lt;/span&gt; &lt;span style="color: rgb(255,0,0)"&gt;ID&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;="Panel1"&lt;/span&gt; &lt;span style="color: rgb(255,0,0)"&gt;CssClass&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;="squared"&amp;gt;&lt;br /&gt;&lt;/span&gt;    Hover me!    &lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;asp&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;:&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;Panel&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;br /&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;ajaxExtender&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;:&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;HoverAddsCssClassExtender&lt;/span&gt; &lt;span style="color: rgb(255,0,0)"&gt;runat&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;="server"&lt;/span&gt; &lt;br&gt; &lt;span style="color: rgb(255,0,0)"&gt;ID&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;="HoverAddsCssClassExtender1"&lt;/span&gt; &lt;span style="color: rgb(255,0,0)"&gt;TargetControlID&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;="Panel1"&lt;/span&gt; &lt;span style="color: rgb(255,0,0)"&gt;HoverCssClassName&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;="hover"&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;/&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;På klienten kommer &lt;em&gt;Panel1&lt;/em&gt; att vara en &lt;em&gt;div&lt;/em&gt; vars class-property är satt till &lt;em&gt;"squared"&lt;/em&gt;. När musen förs över &lt;em&gt;Panel1&lt;/em&gt;&amp;nbsp;kommer&amp;nbsp;dess class-property att sättas till &lt;em&gt;"squared hover"&lt;/em&gt;, dvs. värdet från &lt;em&gt;HoverCssClassName&lt;/em&gt;&amp;nbsp;läggs till sist, för att återställas till &lt;em&gt;"squared"&lt;/em&gt; när musen försvinner.&lt;/p&gt;&lt;br /&gt;&lt;h1&gt;HoverExtender&lt;/h1&gt;&lt;br /&gt;&lt;p&gt;Hur får man då till det här enklast? Jo det finns en extender som heter &lt;em&gt;HoverExtender&lt;/em&gt; som följer med AjaxControlToolkit och som är lite odokumenterad. Den ligger som grund till &lt;em&gt;DropDownExtender&lt;/em&gt; och &lt;em&gt;HoverMenuExtender&lt;/em&gt; men den fungerar alldeles utmärkt att använda fristående. Det den gör att den kör ett av användaren specificerat script på mouseover och ett annat script på mouseout. Man kan även specificera att det ska dröja ett tag innan någon av scripten körs. Detta kan t.ex. utnyttjas till att tillåta att muspekaren passerar över kontrollen utan att scriptet körs (eller lämnar kontrollen som hastigast utan att scriptet körs direkt). Bara genom att låta muspekaren dröja kvar ett tag körs scriptet.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Vi kommer att låta vår extender ärva funktionalitet av HoverExtender. Men bara på klientsidan.&lt;/p&gt;&lt;br /&gt;&lt;h1&gt;Skapa HoverAddsCssClassExtender&lt;/h1&gt;&lt;br /&gt;&lt;p&gt;Nog pratat. Låt oss börja koda. Jag kommer inte att gå in i detalj hur du sätter upp projektet utan utgå ifrån att du har ett projekt där du kan skapa extendern. Mer information om hur du sätter upp ett sånt projekt finns i &lt;a title="Skapa en AjaxControlToolkitExtender" href="http://hockeswe.blogspot.com/2007/05/skapa-en-ajaxcontroltoolkit-extender.html"&gt;den&amp;nbsp;tidigare bloggposten&lt;/a&gt;. Namnge projektet &lt;strong&gt;HoverAddsCssClass&lt;/strong&gt;.&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;Ny AjaxControlToolkitExtender&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;Du måste inte skapa Ajax Control Project utan kan skapa en extender i ett vanligt klassbibliotek.&amp;nbsp;För att skapa en ny extender i ett befintligt projekt: Högerklicka på projektet och välj &lt;strong&gt;Add &amp;gt; New&amp;nbsp;Item... &lt;/strong&gt;och välj &lt;strong&gt;ASP.NET AJAX Extender Control &lt;/strong&gt;längst ner under &lt;strong&gt;My Templates&lt;/strong&gt;. Ange &lt;strong&gt;HoverAddsCssClass&lt;/strong&gt; som namn. Se till att du har en referens till AjaxControlToolkit.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Nedan kommer jag förutsätta att du skapat ett nytt projekt som heter HoverAddsCssClass med tre filer. HoverAddsCssClassBehavior.js, HoverAddsCssClassDesigner.cs och HoverAddsCssClassExtender.cs. Det första man &lt;em&gt;ALLTID&lt;/em&gt; ska göra är att se till att js-filen har &lt;em&gt;Build Action=Embedded Resource&lt;/em&gt; (finns under properties för den filen).&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;Radera designern&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;Vi kommer inte att behöva någon egen designer så ta bort HoverAddsCssClassDesigner.cs ur projektet.&amp;nbsp;Default-designern duger utmärkt.&amp;nbsp;(Designern används i design-läget inne i&amp;nbsp;Visual Studio). Gå samtidigt in och radera hänvisningen till den i HoverAddsCssClassExtender.cs.&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: rgb(0,0,255)"&gt;namespace&lt;/span&gt; HoverAddsCssClass&lt;br /&gt;{&lt;br /&gt;    &lt;strike&gt;[&lt;span style="color: rgb(43,145,175)"&gt;Designer&lt;/span&gt;(&lt;span style="color: rgb(0,0,255)"&gt;typeof&lt;/span&gt;(&lt;span style="color: rgb(43,145,175)"&gt;HoverAddsCssClassDesigner&lt;/span&gt;))]&lt;/strike&gt;&lt;br /&gt;    [&lt;span style="color: rgb(43,145,175)"&gt;ClientScriptResource&lt;/span&gt;(&lt;span style="color: rgb(163,21,21)"&gt;"HoverAddsCssClass.HoverAddsCssClassBehavior"&lt;/span&gt;, &lt;br&gt;     &lt;span style="color: rgb(163,21,21)"&gt;"HoverAddsCssClass.HoverAddsCssClassBehavior.js"&lt;/span&gt;)]&lt;br /&gt;    [&lt;span style="color: rgb(43,145,175)"&gt;TargetControlType&lt;/span&gt;(&lt;span style="color: rgb(0,0,255)"&gt;typeof&lt;/span&gt;(&lt;span style="color: rgb(43,145,175)"&gt;Control&lt;/span&gt;))]&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;class&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;HoverAddsCssClassExtender&lt;/span&gt; : &lt;span style="color: rgb(43,145,175)"&gt;ExtenderControlBase&lt;br /&gt;&lt;/span&gt;    {&lt;br /&gt;        &lt;span style="color: rgb(0,128,0)"&gt;// TODO: Add your property accessors here.&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h1&gt;Ärv av HoverExtender – men bara på klientsidan&lt;/h1&gt;&lt;br /&gt;&lt;p&gt;Normalt ärver en extender (som används på server-sidan) från &lt;em&gt;ExtenderControlBase&lt;/em&gt; som syns i koden ovan, men den kan bytas ut mot vilken extender som helst i AjaxControlToolkit (och alla andra klasser som implementerar &lt;em&gt;IExtenderControl&lt;/em&gt;). Då vi vill återanvända funktionalitet som &lt;em&gt;HoverExtender&lt;/em&gt; har skulle vi&amp;nbsp;kunna byta ut arvet mot &lt;em&gt;HoverExtender&lt;/em&gt; och få en massa saker gratis. Men eftersom vi inte vill exponera alla de properties som &lt;em&gt;HoverExtender&lt;/em&gt; har så struntar vi i arvet. Istället lägger vi till de&amp;nbsp;properties vi vill ha.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;På klientsidan däremot vill vi utnyttja &lt;em&gt;HoverBehavior&lt;/em&gt; (som är klientdelen av &lt;em&gt;HoverExtender&lt;/em&gt;).&amp;nbsp;Även här används arv. Längst ner i filen HoverAddsCssClassBehavior.js hittar du:&lt;/p&gt;&lt;pre class="code"&gt;HoverAddsCssClass.HoverAddsCssClassBehavior.registerClass(&lt;br&gt; &lt;span style="color: rgb(163,21,21)"&gt;'HoverAddsCssClass.HoverAddsCssClassBehavior'&lt;/span&gt;, AjaxControlToolkit.BehaviorBase);&lt;br&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Klassen &lt;em&gt;HoverAddsCssClass.HoverAddsCssClassBehavior &lt;/em&gt;registreras och den&amp;nbsp;ärver av&amp;nbsp;&lt;em&gt;AjaxControlToolkit.BehaviorBase&lt;/em&gt;, men det finns inget som säger att den måste ärva från den klassen. Vi ändrar det till att vara &lt;em&gt;HoverBehavior&lt;/em&gt; istället&lt;/p&gt;&lt;pre class="code"&gt;HoverAddsCssClass.HoverAddsCssClassBehavior.registerClass(&lt;br&gt; &lt;span style="color: rgb(163,21,21)"&gt;'HoverAddsCssClass.HoverAddsCssClassBehavior'&lt;/span&gt;, AjaxControlToolkit.&lt;span class="highlight"&gt;HoverBehavior&lt;/span&gt;);&lt;br&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Vi måste även se till att koden för &lt;em&gt;HoverBehavior&lt;/em&gt; laddas ner till klienten. Det gör vi med hjälp av attributet &lt;em&gt;RequiredScript &lt;/em&gt;på serversidans extender&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;&lt;pre class="code"&gt;[&lt;span style="color: rgb(43,145,175)"&gt;ClientScriptResource&lt;/span&gt;(&lt;span style="color: rgb(163,21,21)"&gt;"HoverAddsCssClass.HoverAddsCssClassBehavior"&lt;/span&gt;, &lt;br&gt; &lt;span style="color: rgb(163,21,21)"&gt;"HoverAddsCssClass.HoverAddsCssClassBehavior.js"&lt;/span&gt;)]&lt;br /&gt;[&lt;span style="color: rgb(43,145,175)"&gt;TargetControlType&lt;/span&gt;(&lt;span style="color: rgb(0,0,255)"&gt;typeof&lt;/span&gt;(&lt;span style="color: rgb(43,145,175)"&gt;Control&lt;/span&gt;))]&lt;br /&gt;&lt;span class="highlight"&gt;[&lt;span style="color: rgb(43,145,175)"&gt;RequiredScript&lt;/span&gt;(&lt;span style="color: rgb(0,0,255)"&gt;typeof&lt;/span&gt;(&lt;span style="color: rgb(43,145,175)"&gt;HoverExtender&lt;/span&gt;))]&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;class&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;HoverAddsCssClassExtender&lt;/span&gt; : Hover&lt;br /&gt;{&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;&lt;br&gt;Vi säger med &lt;em&gt;RequiredScript&lt;/em&gt;-raden ovan att vi vill få ner alla script-filer som &lt;em&gt;HoverExtender &lt;/em&gt;använder.&lt;/p&gt;&lt;br /&gt;&lt;h1&gt;HoverCssClassName – Property&lt;/h1&gt;&lt;br /&gt;&lt;p&gt;Vi behöver en property &lt;em&gt;HoverCssClassName&lt;/em&gt; så att man kan ange css-klassnamnet som ska läggas till då musen förs över elementet. Vi börjar i extendern med att lägga till propertyn. Ta samtidigt bort &lt;em&gt;MyProperty&lt;/em&gt; som redan ligger i filen.&lt;/p&gt;&lt;pre class="code"&gt;[&lt;span style="color: rgb(43,145,175)"&gt;ExtenderControlProperty&lt;/span&gt;()]&lt;br /&gt;[&lt;span style="color: rgb(43,145,175)"&gt;DefaultValue&lt;/span&gt;(&lt;span style="color: rgb(163,21,21)"&gt;""&lt;/span&gt;)]&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt; HoverCssClassName&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;get&lt;br /&gt;&lt;/span&gt;    {&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; GetPropertyValue(&lt;span style="color: rgb(163,21,21)"&gt;"HoverCssClassName"&lt;/span&gt;, &lt;span style="color: rgb(43,145,175)"&gt;String&lt;/span&gt;.Empty);&lt;br /&gt;    }&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;set&lt;br /&gt;&lt;/span&gt;    {&lt;br /&gt;        SetPropertyValue(&lt;span style="color: rgb(163,21,21)"&gt;"HoverCssClassName"&lt;/span&gt;, &lt;span style="color: rgb(0,0,255)"&gt;value&lt;/span&gt;);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;&lt;br&gt;Över till klientsidans behavior-kod. &lt;/p&gt;&lt;pre class="code"&gt;HoverAddsCssClass.HoverAddsCssClassBehavior = &lt;span style="color: rgb(0,0,255)"&gt;function&lt;/span&gt;(element) {&lt;br /&gt;    HoverAddsCssClass.HoverAddsCssClassBehavior.initializeBase(&lt;span style="color: rgb(0,0,255)"&gt;this&lt;/span&gt;, [element]);&lt;br /&gt;&lt;br /&gt;    &lt;span class="highlight"&gt;&lt;span style="color: rgb(0,0,255)"&gt;this&lt;/span&gt;._hoverCssClassName = &lt;span style="color: rgb(163,21,21)"&gt;""&lt;/span&gt;;&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;...&lt;br&gt;dispose : &lt;span style="color: rgb(0,0,255)"&gt;function&lt;/span&gt;() {&lt;br /&gt;    &lt;span style="color: rgb(0,128,0)"&gt;// TODO: add your cleanup code here&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;    HoverAddsCssClass.HoverAddsCssClassBehavior.&lt;br&gt;       callBaseMethod(&lt;span style="color: rgb(0,0,255)"&gt;this&lt;/span&gt;, &lt;span style="color: rgb(163,21,21)"&gt;'dispose'&lt;/span&gt;);&lt;br /&gt;},&lt;br /&gt;&lt;br /&gt;&lt;span class="highlight"&gt;get_HoverCssClassName : &lt;span style="color: rgb(0,0,255)"&gt;function&lt;/span&gt;() {&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;this&lt;/span&gt;._hoverCssClassName;&lt;br /&gt;},&lt;br /&gt;set_HoverCssClassName : &lt;span style="color: rgb(0,0,255)"&gt;function&lt;/span&gt;(value) {&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;this&lt;/span&gt;._hoverCssClassName = value;&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;this&lt;/span&gt;.raisePropertyChanged(&lt;span style="color: rgb(163,21,21)"&gt;'HoverCssClassName'&lt;/span&gt;);&lt;br /&gt;},&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Hämta och spara värdet i en lokalt deklarerad&amp;nbsp;variabel.&lt;/p&gt;&lt;br /&gt;&lt;h1&gt;Hantera mouseover&lt;/h1&gt;&lt;br /&gt;&lt;p&gt;&lt;em&gt;HoverBehavior&lt;/em&gt;, klientsidans behavior som vi ärver&amp;nbsp;av,&lt;em&gt;&amp;nbsp;&lt;/em&gt;har två properties &lt;em&gt;hoverScript&lt;/em&gt; och &lt;em&gt;unhoverScript&lt;/em&gt;, på vilka man anger&amp;nbsp;javascriptkod i form av en strängar. Denna kod kommer att tolkas och köras vid mouseover resp. mouseout (och även focus resp. blur). Det här utnyttjar vi till att köra två av våra egna metoder för att lägga till och ta bort css-klassnamnet.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Eftersom vi ärver av &lt;em&gt;HoverBehavior&lt;/em&gt; har vi tillgång till de metoder som används för att sätta dess properties. På samma sätt som vår &lt;em&gt;HoverCssClassName &lt;/em&gt;har en metod &lt;em&gt;set_HoverCssClassName&lt;/em&gt; för att ange värdet har &lt;em&gt;hoverScript&lt;/em&gt; och &lt;em&gt;unhoverScript&lt;/em&gt; de två metoderna &lt;em&gt;set_hoverScript&lt;/em&gt; och &lt;em&gt;set_unhoverScript&lt;/em&gt;. Så vi anropar dem från vår initialize-kod:&lt;/p&gt;&lt;pre class="code"&gt;initialize : &lt;span style="color: rgb(0,0,255)"&gt;function&lt;/span&gt;() {&lt;br /&gt;    HoverAddsCssClass.HoverAddsCssClassBehavior.&lt;br&gt;     callBaseMethod(&lt;span style="color: rgb(0,0,255)"&gt;this&lt;/span&gt;, &lt;span style="color: rgb(163,21,21)"&gt;'initialize'&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;&lt;span class="highlight"&gt;    &lt;span style="color: rgb(0,0,255)"&gt;this&lt;/span&gt;.set_hoverScript(&lt;span style="color: rgb(163,21,21)"&gt;"this._addCss()"&lt;/span&gt;);&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;this&lt;/span&gt;.set_unhoverScript(&lt;span style="color: rgb(163,21,21)"&gt;"this._removeCss()"&lt;/span&gt;);&lt;br&gt;&lt;/span&gt;},&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;och vi lägger till de två metoder som initialize hänvisar till:&lt;/p&gt;&lt;pre class="code"&gt;_addCss : &lt;span style="color: rgb(0,0,255)"&gt;function&lt;/span&gt;()&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;var&lt;/span&gt; targetElement=&lt;span style="color: rgb(0,0,255)"&gt;this&lt;/span&gt;.get_element();&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;if&lt;/span&gt;(targetElement &amp;amp;&amp;amp; !Sys.UI.DomElement.containsCssClass(targetElement,&lt;span style="color: rgb(0,0,255)"&gt;this&lt;/span&gt;._hoverCssClassName))&lt;br /&gt;    {&lt;br /&gt;        Sys.UI.DomElement.addCssClass(targetElement,&lt;span style="color: rgb(0,0,255)"&gt;this&lt;/span&gt;._hoverCssClassName);&lt;br /&gt;    }&lt;br /&gt;},&lt;br /&gt;&lt;br /&gt;_removeCss : &lt;span style="color: rgb(0,0,255)"&gt;function&lt;/span&gt;()&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;var&lt;/span&gt; targetElement=&lt;span style="color: rgb(0,0,255)"&gt;this&lt;/span&gt;.get_element();&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;if&lt;/span&gt;(targetElement &amp;amp;&amp;amp; Sys.UI.DomElement.containsCssClass(targetElement,&lt;span style="color: rgb(0,0,255)"&gt;this&lt;/span&gt;._hoverCssClassName))&lt;br /&gt;    {&lt;br /&gt;        Sys.UI.DomElement.removeCssClass(targetElement,&lt;span style="color: rgb(0,0,255)"&gt;this&lt;/span&gt;._hoverCssClassName);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;br /&gt;&lt;p&gt;I &lt;em&gt;_addCss()&lt;/em&gt; börjar vi med att plocka ut det element som extendern hakades på. Om ett sånt element fanns (ska alltid finnas, men bäst att kolla ändå för att slippa fel om den ändå inte skulle finnas) och dess&amp;nbsp;css-klassnamnsträng&amp;nbsp;inte redan innehöll vår &lt;em&gt;_hoverCssClassName&lt;/em&gt; lägg till det till css-klassnamnet. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;em&gt;_removeCss()&lt;/em&gt; fungerar på liknande sätt. Om vi har ett target element och dess css-klassnamnsträng innehåller &lt;em&gt;_hoverCssClassName&lt;/em&gt;, ta bort det.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Vi nyttjar här tre funktioner som Asp.Net Ajax för med sig:&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://ajax.asp.net/docs/ClientReference/Sys.UI/DomElementClass/SysUIDomElementContainsCssClassMethod.aspx"&gt;Sys.UI.DomElement.containsCssClass&lt;/a&gt; &lt;br /&gt;&lt;li&gt;&lt;a href="http://ajax.asp.net/docs/ClientReference/Sys.UI/DomElementClass/SysUIDomElementAddCssClassMethod.aspx"&gt;Sys.UI.DomElement.addCssClass&lt;/a&gt; &lt;br /&gt;&lt;li&gt;&lt;a href="http://ajax.asp.net/docs/ClientReference/Sys.UI/DomElementClass/SysUIDomElementRemoveCssClassMethod.aspx"&gt;Sys.UI.DomElement.removeCssClass&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;I och med det är allt klart.&lt;/p&gt;&lt;br /&gt;&lt;h1&gt;Testsida&lt;/h1&gt;&lt;br /&gt;&lt;p&gt;Läs den&amp;nbsp;&lt;a title="Skapa en AjaxControlToolkitExtender" href="http://hockeswe.blogspot.com/2007/05/skapa-en-ajaxcontroltoolkit-extender.html"&gt;tidigare bloggposten&lt;/a&gt; för information om hur man skapar en testsajt. I Default.aspx knackar du in följande:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;head&lt;/span&gt; &lt;span style="color: rgb(255,0,0)"&gt;id&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;="Head1"&lt;/span&gt; &lt;span style="color: rgb(255,0,0)"&gt;runat&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;="server"&amp;gt;&lt;br /&gt;&lt;/span&gt;    &lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;title&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;Untitled Page&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;title&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;    &lt;span class="highlight"&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;style&lt;/span&gt; &lt;span style="color: rgb(255,0,0)"&gt;type&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;="text/css"&amp;gt;&lt;br /&gt;&lt;/span&gt;        &lt;span style="color: rgb(163,21,21)"&gt;.squared&lt;br /&gt;&lt;/span&gt;        {&lt;br /&gt;            &lt;span style="color: rgb(255,0,0)"&gt;width&lt;/span&gt;:&lt;span style="color: rgb(0,0,255)"&gt;200px&lt;/span&gt;;&lt;br /&gt;            &lt;span style="color: rgb(255,0,0)"&gt;height&lt;/span&gt;:&lt;span style="color: rgb(0,0,255)"&gt;200px&lt;/span&gt;;&lt;br /&gt;            &lt;span style="color: rgb(255,0,0)"&gt;border&lt;/span&gt;: &lt;span style="color: rgb(0,0,255)"&gt;dashed&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;4px&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;black&lt;/span&gt;;&lt;br /&gt;            &lt;span style="color: rgb(255,0,0)"&gt;background-color&lt;/span&gt;: &lt;span style="color: rgb(0,0,255)"&gt;#eee&lt;/span&gt;;&lt;br /&gt;            &lt;span style="color: rgb(255,0,0)"&gt;text-align&lt;/span&gt;:&lt;span style="color: rgb(0,0,255)"&gt;center&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: rgb(163,21,21)"&gt;.hover&lt;br /&gt;&lt;/span&gt;        {&lt;br /&gt;            &lt;span style="color: rgb(255,0,0)"&gt;background-color&lt;/span&gt;: &lt;span style="color: rgb(0,0,255)"&gt;#228&lt;/span&gt;;    &lt;br /&gt;            &lt;span style="color: rgb(255,0,0)"&gt;color&lt;/span&gt;:&lt;span style="color: rgb(0,0,255)"&gt;white&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;style&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;lt;/&lt;span style="color: rgb(163,21,21)"&gt;head&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;br /&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;body&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;    &lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;form&lt;/span&gt; &lt;span style="color: rgb(255,0,0)"&gt;id&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;="form1"&lt;/span&gt; &lt;span style="color: rgb(255,0,0)"&gt;runat&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;="server"&amp;gt;&lt;br /&gt;&lt;/span&gt;        &lt;span class="highlight"&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;asp&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;:&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;ScriptManager&lt;/span&gt; &lt;span style="color: rgb(255,0,0)"&gt;ID&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;="ScriptManager1"&lt;/span&gt; &lt;span style="color: rgb(255,0,0)"&gt;runat&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;="server"&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;/&amp;gt;&lt;br /&gt;&lt;/span&gt;        &lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;asp&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;:&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;Panel&lt;/span&gt; &lt;span style="color: rgb(255,0,0)"&gt;runat&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;="server"&lt;/span&gt; &lt;span style="color: rgb(255,0,0)"&gt;ID&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;="Panel1"&lt;/span&gt; &lt;span style="color: rgb(255,0,0)"&gt;CssClass&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;="squared"&amp;gt;&lt;br /&gt;&lt;/span&gt;            Hover me!&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;asp&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;:&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;Panel&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;        &lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;myExtenders&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;:&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;HoverAddsCssClassExtender&lt;/span&gt; &lt;span style="color: rgb(255,0,0)"&gt;runat&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;="server"&lt;/span&gt; &lt;span style="color: rgb(255,0,0)"&gt;ID&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;="HoverAddsCssClassExtender1"&lt;/span&gt; &lt;span style="color: rgb(255,0,0)"&gt;TargetControlID&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;="Panel1"&lt;/span&gt; &lt;span style="color: rgb(255,0,0)"&gt;HoverCssClassName&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;="hover"&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;    &lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;form&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;br /&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;body&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;br /&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;html&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Sen är det bara att trycka F5 och testa.&lt;/p&gt;&lt;br /&gt;&lt;h1&gt;Utöka med HoverDelay &amp;amp; UnhoverDelay&lt;/h1&gt;&lt;br /&gt;&lt;p&gt;&lt;em&gt;HoverBehavior&lt;/em&gt; har ytterligare properties som vi enkelt kan utnyttja: &lt;em&gt;hoverDelay&lt;/em&gt; och &lt;em&gt;unhoverDelay&lt;/em&gt;. Genom att sätta dessa specificerar vi&amp;nbsp;hur lång tid i millisekunder man måste befinna oss över elementet innan &lt;em&gt;hoverScript&lt;/em&gt; körs, resp. hur länge vi måste befinna oss utanför för att &lt;em&gt;unhoverScript&lt;/em&gt; ska köras. Att lägga till stöd för dessa två värden är enkelt. På klientsidan ärver vi ju av &lt;em&gt;HoverBehavior&lt;/em&gt; så där är dessa properties redan exponerade. Det räcker således med att göra det i serversidans extender.&lt;/p&gt;&lt;pre class="code"&gt;[&lt;span style="color: rgb(43,145,175)"&gt;ExtenderControlProperty&lt;/span&gt;]&lt;br /&gt;[&lt;span style="color: rgb(43,145,175)"&gt;DefaultValue&lt;/span&gt;(0)]&lt;br /&gt;[&lt;span style="color: rgb(43,145,175)"&gt;ClientPropertyName&lt;/span&gt;(&lt;span style="color: rgb(163,21,21)"&gt;"hoverDelay"&lt;/span&gt;)]&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt; HoverDelay&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;get&lt;br /&gt;&lt;/span&gt;    {&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; GetPropertyValue(&lt;span style="color: rgb(163,21,21)"&gt;"HoverDelay"&lt;/span&gt;, 0);&lt;br /&gt;    }&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;set&lt;br /&gt;&lt;/span&gt;    {&lt;br /&gt;        SetPropertyValue(&lt;span style="color: rgb(163,21,21)"&gt;"HoverDelay"&lt;/span&gt;, &lt;span style="color: rgb(0,0,255)"&gt;value&lt;/span&gt;);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;[&lt;span style="color: rgb(43,145,175)"&gt;ExtenderControlProperty&lt;/span&gt;()]&lt;br /&gt;[&lt;span style="color: rgb(43,145,175)"&gt;ClientPropertyName&lt;/span&gt;(&lt;span style="color: rgb(163,21,21)"&gt;"unhoverDelay"&lt;/span&gt;)]&lt;br /&gt;[&lt;span style="color: rgb(43,145,175)"&gt;DefaultValue&lt;/span&gt;(0)]&lt;br /&gt;&lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt; UnhoverDelay&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;get&lt;br /&gt;&lt;/span&gt;    {&lt;br /&gt;        &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; GetPropertyValue(&lt;span style="color: rgb(163,21,21)"&gt;"UnhoverDelay"&lt;/span&gt;, 0);&lt;br /&gt;    }&lt;br /&gt;    &lt;span style="color: rgb(0,0,255)"&gt;set&lt;br /&gt;&lt;/span&gt;    {&lt;br /&gt;        SetPropertyValue(&lt;span style="color: rgb(163,21,21)"&gt;"UnhoverDelay"&lt;/span&gt;, &lt;span style="color: rgb(0,0,255)"&gt;value&lt;/span&gt;);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;h1&gt;Composition istället för arv&lt;/h1&gt;&lt;br /&gt;&lt;p&gt;I det här exemplet använde vi arv på klientsidan för att få den funktionalitet vi behövde. Ett annat sätt är använda composition, vilket innebär att att man istället för att &lt;em&gt;ärva&lt;/em&gt; in önskat beteende &lt;em&gt;skapar&lt;/em&gt;&amp;nbsp;en privat HoverBehavior &lt;em&gt;inne&lt;/em&gt; i vår behavior (och då ärver man&amp;nbsp;från AjaxControlToolkit.BehaviorBase som vanligt). Man får då själv se till att förändringar av mina properties slår igenom även på HoverBehavior.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;När och varför man ska välja arv eller composition ligger utanför denna genomgång och även hur man skapar med Composition. Är du nyfiken på hur man gör kolla in t.ex. HoverMenuBehavior i AjaxControlToolkit som använder composition för PopupBehavior och HoverBehavior.&lt;/p&gt;&lt;br /&gt;&lt;h1&gt;Ladda ner projektet&lt;/h1&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://hakan.canberger.googlepages.com/HoverAddsCssClassExtender.zip"&gt;Ladda ner projektet&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- Bloggtoppen.se --&gt; &lt;a href="http://www.bloggtoppen.se/"&gt;&lt;img border="0" src="http://www.bloggtoppen.se/tracker.php?do=in&amp;id=12520" alt="Bloggtoppen.se" /&gt;&lt;/a&gt; &lt;!-- /Bloggtoppen.se --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212091881452213631-8492132832406527574?l=hockeswe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hockeswe.blogspot.com/feeds/8492132832406527574/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8212091881452213631&amp;postID=8492132832406527574' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/8492132832406527574'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/8492132832406527574'/><link rel='alternate' type='text/html' href='http://hockeswe.blogspot.com/2007/07/utka-en-befintlig-ajaxcontroltoolkit.html' title='Utöka en befintlig AjaxControlToolkit Extender'/><author><name>Håkan Canberger</name><uri>http://www.blogger.com/profile/07785350579880064843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8212091881452213631.post-7035920260157583872</id><published>2007-05-21T15:32:00.000+02:00</published><updated>2007-05-21T15:38:33.164+02:00</updated><title type='text'>Infoga Do-nothing-kommentarer</title><content type='html'>&lt;div class="otherLanguage"&gt;&lt;a href="http://hocke.blogspot.com/2007/05/insert-do-nothing-comments.html"&gt;English version of this entry&lt;/a&gt;&lt;/div&gt;Infoga alltid en &lt;code&gt;//Do nothing&lt;/code&gt; kommentar på ställen där avsikten är att inget ska utföras.&lt;br /&gt;&lt;br /&gt;Anta t.ex. att du har en konstructor i en Control som ärver av WebControl och det enda du vill göra är att ändra vilken tag som ska användas.&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; MyControl()&lt;br /&gt;   :&lt;span class="kwrd"&gt;base&lt;/span&gt;(HtmlTextWriterTag.Div)&lt;br /&gt;{&lt;br /&gt;}&lt;/pre&gt;När någon annan senare läser koden (eller du själv en månad senare när du glömt allt) är risken stor att man undrar om koden är klar eller om det saknas något i konstruktorn eftersom den är tom. Genom att knacka in en kommentar tydliggör du för dig själv och andra att den verkligen ska vara tom.&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; MyControl()&lt;br /&gt;   :&lt;span class="kwrd"&gt;base&lt;/span&gt;(HtmlTextWriterTag.Div)&lt;br /&gt;{&lt;br /&gt;   &lt;span class="highlight rem"&gt;//Do nothing&lt;/span&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Jag har en code snippet för det här så jag behöver bara skriva &lt;code&gt;don&lt;/code&gt; och trycka tab två gånger så infogas &lt;code&gt;//Do nothing&lt;/code&gt;.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- Bloggtoppen.se --&gt; &lt;a href="http://www.bloggtoppen.se/"&gt;&lt;img border="0" src="http://www.bloggtoppen.se/tracker.php?do=in&amp;id=12520" alt="Bloggtoppen.se" /&gt;&lt;/a&gt; &lt;!-- /Bloggtoppen.se --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212091881452213631-7035920260157583872?l=hockeswe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hockeswe.blogspot.com/feeds/7035920260157583872/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8212091881452213631&amp;postID=7035920260157583872' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/7035920260157583872'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/7035920260157583872'/><link rel='alternate' type='text/html' href='http://hockeswe.blogspot.com/2007/05/infoga-do-nothing-kommentarer.html' title='Infoga Do-nothing-kommentarer'/><author><name>Håkan Canberger</name><uri>http://www.blogger.com/profile/07785350579880064843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8212091881452213631.post-5632637941539663720</id><published>2007-05-20T15:53:00.000+02:00</published><updated>2007-07-10T21:05:43.628+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='Ajax'/><category scheme='http://www.blogger.com/atom/ns#' term='Extenders'/><category scheme='http://www.blogger.com/atom/ns#' term='Asp.net'/><title type='text'>Skapa en AjaxControlToolkit Extender</title><content type='html'>&lt;p&gt;I den här genomgången ska vi skapa en AjaxControlToolkit Extender som man hakar på en TextBox. När användaren skriver in ett datum i något av de tillåtna formaten kommer datumet att formateras om till ett angivet format. Om användaren skriver in "070519" kommer det att formateras om till "2007-05-19". Detta sker på klienten utan något anrop till webbservern.&lt;/p&gt;&lt;br&gt; &lt;p&gt;För att kunna göra detta måste du ha laddat ner och installerat &lt;strong&gt;ASP.NET 2.0 AJAX Extensions 1.0&lt;/strong&gt; och &lt;strong&gt;ASP.NET AJAX Control Toolkit&lt;/strong&gt; från &lt;a href="http://ajax.asp.net/downloads/"&gt;http://ajax.asp.net/downloads/&lt;/a&gt;.&lt;/p&gt;&lt;br&gt; &lt;p&gt;Länk till projektet finns längst ner&lt;/p&gt;&lt;br&gt; &lt;h1&gt;Klientkoden – översikt&lt;/h1&gt;&lt;br&gt; &lt;p&gt;Microsoft har utökat Date-proptotypen med metoden &lt;em&gt;&lt;a href="http://ajax.asp.net/docs/ClientReference/Global/JavascriptTypeExtensions/DateTypeExt/DateParseLocaleFunction.aspx"&gt;Date.parseLocale(value, validFormats)&lt;/a&gt;&lt;/em&gt; som givet en sträng returnerar ett datum om värdet matchade något av de angivna formaten. De har också utökat med en &lt;em&gt;&lt;a href="http://ajax.asp.net/docs/ClientReference/Global/JavascriptTypeExtensions/DateTypeExt/DateFormatFunction.aspx"&gt;format(displayFormat)&lt;/a&gt;&lt;/em&gt; metod för att formattera ett datum. &lt;/p&gt;&lt;br&gt; &lt;p&gt;Med dessa två metoder har vi allt vi behöver. Genom att hantera &lt;em&gt;change&lt;/em&gt;-eventet på en input-textbox får vi reda på när dess värde ändrats. När värdet ändrats skickas det till &lt;em&gt;parseLocale&lt;/em&gt; som antingen returnerar &lt;em&gt;null&lt;/em&gt;, eller ett datum. Om ett datum returneras så formatteras det med &lt;em&gt;format&lt;/em&gt; och den resulterande strängen åker tillbaka till input-textboxen.&lt;/p&gt;&lt;br&gt; &lt;h1&gt;Nytt Ajax Control Project&lt;/h1&gt;&lt;br&gt; &lt;p&gt;Börja med att skapa ett nytt &lt;b&gt;ASP.NET AJAX Control Project&lt;/b&gt;. (&lt;b&gt;File &amp;gt; New &amp;gt;&lt;/b&gt; &lt;strong&gt;Project&lt;/strong&gt;. Välj &lt;b&gt;Visual C#&lt;/b&gt; och under &lt;b&gt;My Templates&lt;/b&gt; välj &lt;b&gt;ASP.NET AJAX Control Project&lt;/b&gt;). Ge projektet ett valfritt namn, t.ex. &lt;b&gt;DateParser&lt;/b&gt;. Ett nytt projekt sätts upp med tre filer: &lt;code&gt;DateParserBehavior.js&lt;/code&gt;, &lt;code&gt;DateParserDesigner.cs&lt;/code&gt; och &lt;code&gt;DateParserExtender.cs&lt;/code&gt;. (Dessa filer kan du även få i ett befintligt projekt genom att högerklicka på projektet och välja &lt;strong&gt;Add New Item&lt;/strong&gt; och sen välja &lt;strong&gt;ASP.NET AJAX Control&lt;/strong&gt;.) &lt;/p&gt;&lt;br&gt; &lt;p&gt;En extender består av en server del, &lt;em&gt;DateParserExtender.cs&lt;/em&gt;, och en klientdel, &lt;em&gt;DateParserBehavior.js&lt;/em&gt;. Genom att sätta properties i server-kontrollen kan vi påverka hur klientdelens beteende ska vara. Den tredje filen är en designer-klass men den behöver man sällan in och peta i.&lt;/p&gt;&lt;br&gt; &lt;p&gt;Det första man måste göra när man lagt till en ny extender är att verifiera att javascript-filen kommer att bäddas in som en resurs. Kolla att propertyn &lt;strong&gt;Build Action&lt;/strong&gt; är satt till &lt;strong&gt;Embedded Resorce&lt;/strong&gt;.&lt;br&gt;&lt;img class="picture" height="158" alt="Javascript file, Build Action: Embedded Resource" src="http://www.canberger.se/blogfiles/hocke/embeddedresource.png" width="296" border="0"&gt;&lt;/p&gt;&lt;br&gt; &lt;p&gt;Om du glömmer att bädda in den som en resurs kommer du att få ett meddelande om att resursen inte finns när du försökèr köra applikationen.&lt;/p&gt;&lt;br&gt; &lt;p&gt;&lt;/p&gt;&lt;br&gt; &lt;h1&gt;Serverkontrollen&lt;/h1&gt;&lt;br&gt; &lt;p&gt;DateParser Extendern (i DateParserExtender.cs) ska ha två properties: &lt;em&gt;ValidFormats &lt;/em&gt;och &lt;em&gt;DisplayFormat &lt;/em&gt;för att man ska kunna ange tillåtna format samt hur det formatterade datumet ska se ut. DateParserExtender.cs utgör själva server-kontrollen och den ärver av &lt;em&gt;ExtenderControlBase&lt;/em&gt; från AjaxControlToolkit. Inledningsvis innehåller vår nya kontroll en property; &lt;em&gt;MyProperty&lt;/em&gt; som fungerar som en mall för hur properties ska skrivas.&lt;/p&gt;&lt;pre class="csharpcode"&gt;[ExtenderControlProperty]&lt;br&gt;[DefaultValue(&lt;span class="str"&gt;""&lt;/span&gt;)]&lt;br&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; MyProperty&lt;br&gt;{&lt;br&gt;  get&lt;br&gt;  {&lt;br&gt;      &lt;span class="kwrd"&gt;return&lt;/span&gt; GetPropertyValue(&lt;span class="str"&gt;"MyProperty"&lt;/span&gt;, &lt;span class="str"&gt;""&lt;/span&gt;);&lt;br&gt;  }&lt;br&gt;  set&lt;br&gt;  {&lt;br&gt;      SetPropertyValue(&lt;span class="str"&gt;"MyProperty"&lt;/span&gt;, &lt;span class="kwrd"&gt;value&lt;/span&gt;);&lt;br&gt;  }&lt;br&gt;}&lt;/pre&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Attributet &lt;em&gt;ExtenderControlProperty&lt;/em&gt; signalerar att det här är en property vars värde ska ner till klienten. Om attributet saknas kommer värdet aldrig att föras över till Behaviorn (man kan alltså ha "vanliga" properties vars värden inte direkt påverkar klient-beteendet). &lt;/p&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;&lt;em&gt;DefaultValue&lt;/em&gt;-attributet har att göra med hur koden för att skapa den här kontrollen ska se ut (och ligger utanför detta ämne) och ska sättas till propertyns defaultvärde.&lt;/p&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;För att hämta och sätta värden används metoderna &lt;em&gt;GetPropertyValue&lt;/em&gt; resp. &lt;em&gt;SetPropertyValue&lt;/em&gt;. I samband med att man hämtar värdet anger man det värde som ska gälla ifall propertyn inte har satts tidigare. Se till att det motsvarar &lt;em&gt;DefaultValue&lt;/em&gt;-attributet.&lt;/p&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Våra properties blir då alltså:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; _Default_ValidFormats = &lt;span class="str"&gt;"yyMMdd;yyyyMM;ddyyyy-MM-dd;yy-MM-dd;yyyyMM-dd;yyyy-MMdd;yyMM-dd;yy-MMdd;dd MMM yyyy;MM/dd/yy;MM/dd/YYYY"&lt;/span&gt;;&lt;br&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; _Default_DisplayFormat = &lt;span class="str"&gt;"yyyy-MM-dd"&lt;/span&gt;;&lt;br&gt;&lt;br&gt;[ExtenderControlProperty]&lt;br&gt;[DefaultValue(_Default_DisplayFormat)]&lt;br&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; DisplayFormat&lt;br&gt;{&lt;br&gt;  get&lt;br&gt;  {&lt;br&gt;      &lt;span class="kwrd"&gt;return&lt;/span&gt; GetPropertyValue(&lt;span class="str"&gt;"DisplayFormat"&lt;/span&gt;, _Default_DisplayFormat);&lt;br&gt;  }&lt;br&gt;  set&lt;br&gt;  {&lt;br&gt;      SetPropertyValue(&lt;span class="str"&gt;"DisplayFormat"&lt;/span&gt;, &lt;span class="kwrd"&gt;value&lt;/span&gt;);&lt;br&gt;  }&lt;br&gt;}&lt;br&gt;&lt;br&gt;[ExtenderControlProperty]&lt;br&gt;[DefaultValue(_Default_ValidFormats)]&lt;br&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ValidFormats&lt;br&gt;{&lt;br&gt;  get&lt;br&gt;  {&lt;br&gt;      &lt;span class="kwrd"&gt;return&lt;/span&gt; GetPropertyValue(&lt;span class="str"&gt;"ValidFormats"&lt;/span&gt;, _Default_ValidFormats);&lt;br&gt;  }&lt;br&gt;  set&lt;br&gt;  {&lt;br&gt;      SetPropertyValue(&lt;span class="str"&gt;"ValidFormats"&lt;/span&gt;, &lt;span class="kwrd"&gt;value&lt;/span&gt;);&lt;br&gt;  }&lt;br&gt;}&lt;/pre&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Vi använder konstanter för defaultvärdena för att se till att attributet och &lt;em&gt;GetPropertyValue&lt;/em&gt; använder samma värde (sen är det dessutom snyggare att göra så och vi gillar ju att skriva snygg kod). Då var serverdelen klar.&lt;/p&gt;&lt;br&gt;&lt;br /&gt;&lt;h1&gt;Klientens Behavior&lt;/h1&gt;En behavior kan ses som en klass. Den har en konstruktor, där dess privata variabler definieras; den har properties; publika och privata metoder samt en &lt;em&gt;initialize&lt;/em&gt; och en &lt;em&gt;dispose&lt;/em&gt;-metod. När en behavior skapas körs först konstruktorn, eventuell properties från servern sätts, varpå &lt;em&gt;initialize&lt;/em&gt; körs. I &lt;em&gt;initialize&lt;/em&gt; bygger man upp det som behaviorn behöver för att fungera, registrerar events, etc. När behaviorn ska tas bort körs dess &lt;em&gt;dispose&lt;/em&gt;-metod. Här avregistrerar man sig från event och rensar upp efter sig. Observera att &lt;em&gt;dispose&lt;/em&gt; kan komma att anropas flera gånger så det gäller att se till att koden klarar det.&lt;br&gt;&lt;br /&gt;&lt;h2&gt;Properties&lt;/h2&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Även filen &lt;em&gt;DateParserBehavior.js&lt;/em&gt; innehåller lite exempelkod för att visa hur den ska kodas. En property på klientsidan består av tre delar: en privat variabel som skapas i konstruktorn högt upp i filen, en get-metod och en set-metod som man använder för att sätta värdet på propertyn. Så för propertyn &lt;em&gt;MyProperty&lt;/em&gt; så skriver man inte &lt;em&gt;obj.MyProperty="value";&lt;/em&gt; istället gör man anropet &lt;em&gt;obj.set_MyProperty("value");&lt;/em&gt;. &lt;/p&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Så för våra properties behöver vi två variabler för att hålla deras värden. Vi anger också default-värden.&lt;/p&gt;&lt;pre&gt;DateParser.DateParserBehavior = function(element) {&lt;br&gt;&lt;br&gt;  DateParser.DateParserBehavior.initializeBase(this, [element]);&lt;br&gt;&lt;br&gt;  // Property variables&lt;br&gt;  this._displayFormat = "yyyy-MM-dd";&lt;br&gt;  this._validFormats = "yyMMdd;yyyyMMdd;yyyy-MM-dd;yy-MM-dd;yyyyMM-dd;yyyy-MMdd;yyMM-dd;yy-MMdd;dd MMM yyyy;MM/dd/yy;MM/dd/YYYY";&lt;br&gt;}&lt;/pre&gt;Efter dispose-metoden lägger vi in get- och set-metoderna&lt;pre&gt;&lt;span class="notImportant"&gt;dispose : function() {&lt;br&gt;// TODO: add your cleanup code here&lt;br&gt;&lt;br&gt;DateParser.DateParserBehavior.callBaseMethod(this, 'dispose');&lt;br&gt;},&lt;/span&gt;&lt;br&gt;&lt;br&gt;// Properties ------------------------------------------------&lt;br&gt;get_DisplayFormat : function() {&lt;br&gt; return this._displayFormat;&lt;br&gt;},&lt;br&gt;set_DisplayFormat : function(value) {&lt;br&gt; this._displayFormat = value;&lt;br&gt;}, &lt;br&gt;&lt;br&gt;&lt;br&gt;get_ValidFormats : function() {&lt;br&gt; return this._validFormats;&lt;br&gt;},&lt;br&gt;set_ValidFormats : function(value) {&lt;br&gt; this._validFormats = value;&lt;br&gt;}&lt;/pre&gt;De privata variablerna (signaleras med att de börjar med ett understreck) kan namnges som man vill men namnen på get- och set-metoderna måste motsvara server-kontrollens properties. Eftersom vi har en &lt;em&gt;ExtenderControlProperty&lt;/em&gt;-markerad property i server-kontrollen som heter &lt;em&gt;ValidFormats&lt;/em&gt; måste vi även ha en &lt;em&gt;get_ValidFormats&lt;/em&gt; och en &lt;em&gt;set_ValidFormats&lt;/em&gt; metod på klienten.&lt;br&gt;&lt;br /&gt;&lt;h2&gt;ParseDate, sträng till datum&lt;/h2&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Innan vi skriver kod för eventhanteringen behöver vi en hjälpmetod för att anropa &lt;em&gt;Date.parseLocale(value,formats)&lt;/em&gt;. Se &lt;a title="Anropa Date.parseLocale() med en array" href="http://hockeswe.blogspot.com/2007/05/anropa-javascript-dateparselocale-med.html"&gt;mitt tidigare inlägg&lt;/a&gt; om varför detta behövs.&lt;/p&gt;&lt;pre&gt;_parseDate : function(value,formats)&lt;br&gt;{&lt;br&gt;//Create an array that initially will contain value.&lt;br&gt;//Add the elements from formats after the value.&lt;br&gt;var args=[value];&lt;br&gt;Array.addRange(args,formats);&lt;br&gt;&lt;br&gt;//args contains now: [value, formats[0], formats[1], ... ]  &lt;br&gt;//Call the parseLocale method using our args array as parameters&lt;br&gt;return Date.parseLocale.apply(Date,args);&lt;br&gt;}&lt;/pre&gt;&lt;br&gt;&lt;br /&gt;&lt;h2&gt;Uppdatera inputboxen&lt;/h2&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Metoden som kommer att anropas när eventet change höjs:&lt;/p&gt;&lt;pre&gt;_updateTargetElement : function()&lt;br&gt;{&lt;br&gt;var targetElement = this.get_element();&lt;br&gt;var value=targetElement.value;&lt;br&gt;if(value)&lt;br&gt;{&lt;br&gt;  var parsedDate = this._parseDate(value,this._validFormatsArr);&lt;br&gt;  if(parsedDate)&lt;br&gt;  {&lt;br&gt;    targetElement.value=parsedDate.format(this._displayFormat);&lt;br&gt;  }&lt;br&gt;  //Else, on parse error, do nothing.&lt;br&gt;}&lt;br&gt;}&lt;/pre&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Metoden börjar med att ta reda på vårt &lt;em&gt;targetElement&lt;/em&gt;, dvs. vår inputbox, genom att anropa metoden &lt;em&gt;get_element()&lt;/em&gt; (en metod vi ärvt från vår basklass). Om värdet har satts, försök att tolka det som ett datum. Om vi lyckades tolka det som ett datum, formattera det enligt specificerat format och uppdatera inputboxens &lt;em&gt;value&lt;/em&gt;. Det enda som behöver en förklaring är den privata variabeln &lt;em&gt;this._validFormatsArr&lt;/em&gt;. &lt;/p&gt;&lt;br&gt;&lt;br /&gt;&lt;h2&gt;Tillåtna format som array&lt;/h2&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Vi anger formatet som en semikolonseparerad sträng av godkända format, t.ex. &lt;em&gt;"yyyyMMdd;yyMMdd"&lt;/em&gt;. Strängen kommer vi att göra om till en array &lt;em&gt;["yyyyMMdd","yyMMdd"]&lt;/em&gt; och det är alltså det &lt;em&gt;this._validFormatsArr&lt;/em&gt; innehåller. Vi deklarerar den i konstruktorn ihop med de andra.&lt;/p&gt;&lt;pre&gt;    // Property variables&lt;br&gt;  this._displayFormat = "yyyy-MM-dd";&lt;br&gt;  this._validFormats = "yyMMdd;yyyyMMdd;yyyy-MM-dd;yy-MM-dd;yyyyMM-dd;yyyy-MMdd;yyMM-dd;yy-MMdd;dd MMM yyyy;MM/dd/yy;MM/dd/YYYY";&lt;br&gt;&lt;br&gt;  &lt;span class="highlight"&gt;// Internal variables&lt;br&gt;  this._validFormatsArr=null;&lt;/span&gt;&lt;/pre&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Arrayen fylls i Initialize-metoden.&lt;/p&gt;&lt;pre&gt;initialize : function() {&lt;br&gt;DateParser.DateParserBehavior.callBaseMethod(this, 'initialize');&lt;br&gt;&lt;br&gt;this._validFormatsArr=this._validFormats.split(";");&lt;br&gt;},&lt;/pre&gt;&lt;br&gt;&lt;br /&gt;&lt;h2&gt;Event-hantering&lt;/h2&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Det sista som återstår är att registrera en eventhanterare för inputboxens change-event. Mönstret för event består typiskt av fyra delar (ibland vill man göra på andra sätt men det är överkurs):&lt;/p&gt;&lt;br&gt;&lt;br /&gt;&lt;ol&gt;&lt;br&gt;&lt;br /&gt;&lt;li&gt;Skapa en funktion för eventhantering&lt;br&gt;&lt;br /&gt;&lt;li&gt;Deklarera en privat variabel i konstruktorn som kommer att innehålla en delegat (kan betraktas som en funktionspekare) för din eventhanterare.&lt;br&gt;&lt;br /&gt;&lt;li&gt;I initialize skapar man delegaten och registrerar den på eventet.&lt;br&gt;&lt;br /&gt;&lt;li&gt;I dispose avregistrerar man delegaten från eventet och sätter den privata variablen till null.&lt;/li&gt;&lt;/ol&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;I vårt exempel blir det då så här.&lt;/p&gt;&lt;br&gt;&lt;br /&gt;&lt;ol&gt;&lt;br&gt;&lt;br /&gt;&lt;li&gt;Skapa en funktion för eventhantering&lt;pre&gt;//Event handlers -----------------------------------------------&lt;br&gt;_onValueChange : function(e)&lt;br&gt;{&lt;br&gt;this._updateTargetElement();&lt;br&gt;}&lt;/pre&gt;&lt;br&gt;&lt;br /&gt;&lt;li&gt;Deklarera en privat variabel i konstruktorn som kommer att innehålla en delegat (kan betraktas som en funktionspekare) för din eventhanterare.&lt;pre&gt;//Event handlers&lt;br&gt;this._valueChangeHandler=null;&lt;/pre&gt;&lt;br&gt;&lt;br /&gt;&lt;li&gt;I &lt;em&gt;initialize&lt;/em&gt; skapar man delegaten och registrerar den på eventet. &lt;pre&gt;initialize : function() {&lt;br&gt;DateParser.DateParserBehavior.callBaseMethod(this, 'initialize');&lt;br&gt;&lt;br&gt;&lt;span class="highlight"&gt;var targetElement = this.get_element();&lt;/span&gt;&lt;br&gt;&lt;br&gt;this._validFormatsArr=this._validFormats.split(";");&lt;br&gt;&lt;br&gt;&lt;span class="highlight"&gt;//Register Event handlers&lt;br&gt;this._valueChangeHandler = Function.createDelegate(this, this._onValueChange);&lt;br&gt;$addHandler(targetElement, 'change', this._valueChangeHandler);&lt;/span&gt;&lt;br&gt;},&lt;/pre&gt;&lt;br&gt;&lt;br /&gt;&lt;li&gt;I &lt;em&gt;dispose&lt;/em&gt; avregistrerar man delegaten från eventet och sätter den privata variablen till &lt;em&gt;null&lt;/em&gt;.&lt;pre&gt;dispose : function() {&lt;br&gt;//Reminder: Might be called several times.&lt;br&gt;&lt;br&gt;var targetElement = this.get_element();&lt;br&gt;&lt;br&gt;&lt;span class="highlight"&gt;if (this._valueChangeHandler)&lt;br&gt;{&lt;br&gt;  $removeHandler(targetElement, 'change', this._valueChangeHandler);&lt;br&gt;  this._valueChangeHandler = null;&lt;br&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;DateParser.DateParserBehavior.callBaseMethod(this, 'dispose');&lt;br&gt;},&lt;/pre&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Sisådär då borde allt vara klart för en testtur.&lt;/p&gt;&lt;br&gt;&lt;br /&gt;&lt;h1&gt;Testprojekt&lt;/h1&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;För att kunna testa behöver vi en testsajt. Lägg till en ny Ajax-webbsajt (&lt;strong&gt;File&lt;/strong&gt; &amp;gt; &lt;strong&gt;Add&lt;/strong&gt; &amp;gt; &lt;strong&gt;New Web Site ...&lt;/strong&gt; &amp;gt; &lt;strong&gt;ASP.NET AJAX-enabled Web site&lt;/strong&gt;). Lägg till en referens till vår DateParser (högerklicka på webbsajten i Solution Explorer och välj &lt;strong&gt;Add Reference&lt;/strong&gt; &amp;gt; &lt;strong&gt;Projects&lt;/strong&gt; &amp;gt; &lt;strong&gt;Date Parser&lt;/strong&gt; &amp;gt; &lt;strong&gt;OK&lt;/strong&gt;).&lt;/p&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Öppna &lt;em&gt;default.aspx&lt;/em&gt; och dra in en TextBox från toolboxen. Växla till source-läge och lägg till följande direktiv ovanför DOCTYPE-raden för att göra vår extender tillgänglig på sidan:&lt;/p&gt;&lt;pre&gt;&amp;lt;%@ Register tagprefix="myExtenders" Namespace="DateParser" Assembly="DateParser" %&amp;gt;&lt;/pre&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Nedanför &lt;em&gt;TextBox1 &lt;/em&gt;lägger du till:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;myExtenders:DateParserExtender&lt;/span&gt; &lt;span class="attr"&gt;ID&lt;/span&gt;&lt;span class="kwrd"&gt;="TextBox1Extender"&lt;br&gt;&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;="server"&lt;/span&gt; &lt;span class="attr"&gt;TargetControlID&lt;/span&gt;&lt;span class="kwrd"&gt;="TextBox1"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Sätt webbprojektet till att vara startprojekt och kör igång genom att trycka F5. Om allt fungerar som det ska, ska du kunna mata in &lt;strong&gt;070519&lt;/strong&gt; i rutan, trycka tab och det formatteras om till &lt;strong&gt;2007-05-19&lt;/strong&gt;. Om du missat att säga till att JavaScript-filen ska bäddas in som en resurs är det nu du kommer att få ett felmeddelande om att resursen saknas i assembly:t.&lt;/p&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Om du vill byta datumformat är det bara att göra det på DateParserExtendern: &lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;myExtenders:DateParserExtender&lt;/span&gt; &lt;span class="attr"&gt;ID&lt;/span&gt;&lt;span class="kwrd"&gt;="TextBox1Extender"&lt;br&gt;&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;="server"&lt;/span&gt; &lt;span class="attr"&gt;TargetControlID&lt;/span&gt;&lt;span class="kwrd"&gt;="TextBox1"&lt;/span&gt;&lt;br&gt;&lt;span class="highlight"&gt; &lt;span class="attr"&gt;DisplayFormat&lt;/span&gt;&lt;span class="kwrd"&gt;="MMM ddd dd yyyy"&lt;/span&gt; &lt;span class="attr"&gt;ValidFormats&lt;/span&gt;&lt;span class="kwrd"&gt;="yyMMdd"&lt;/span&gt;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;Dessa format kan du använda: &lt;a href="http://msdn2.microsoft.com/en-us/library/bb79761a-ca08-44ee-b142-b06b3e2fc22b.aspx"&gt;http://msdn2.microsoft.com/en-us/library/bb79761a-ca08-44ee-b142-b06b3e2fc22b.aspx&lt;/a&gt;&lt;/p&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;För att slippa lägga till ett register-direktiv på alla sidor kan du lägga till följande i Web.Config.&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;system.web&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;pages&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;controls&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;tagPrefix&lt;/span&gt;&lt;span class="kwrd"&gt;="asp"&lt;/span&gt; &lt;span class="attr"&gt;namespace&lt;/span&gt;&lt;span class="kwrd"&gt;="System.Web.UI"&lt;/span&gt; &lt;span class="attr"&gt;assembly&lt;/span&gt;&lt;span class="kwrd"&gt;="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br&gt;&lt;span class="highlight"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;tagPrefix&lt;/span&gt;&lt;span class="kwrd"&gt;="myExtenders"&lt;/span&gt; &lt;span class="attr"&gt;namespace&lt;/span&gt;&lt;span class="kwrd"&gt;="DateParser"&lt;/span&gt; &lt;span class="attr"&gt;assembly&lt;/span&gt;&lt;span class="kwrd"&gt;="DateParser"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;controls&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;pages&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;En bra sak att alltid lägga in i sina behaviors är en metod för att trigga beteendet. Om beteendet är att poppa upp en ruta när något händer, lägg till en metod som poppar upp den. I vårt fall behöver vi en metod för att parse:a inputboxen och formattera om den, så vi lägger till följande publika metod:&lt;br&gt;&lt;/p&gt;&lt;pre&gt;//Public Methods -----------------------------------------------&lt;br&gt;updateTargetElement : function()&lt;br&gt;{&lt;br&gt; this._updateTargetElement();&lt;br&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Metoder som denna gör det möjligt att via kod trigga ett beteende och det är ibland väldigt praktiskt. Tyvärr är det något de flesta AjaxControlToolkit Extenders saknar.&lt;/p&gt;&lt;br&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://hakan.canberger.googlepages.com/DateParser.zip"&gt;Ladda ner projektet&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- Bloggtoppen.se --&gt; &lt;a href="http://www.bloggtoppen.se/"&gt;&lt;img border="0" src="http://www.bloggtoppen.se/tracker.php?do=in&amp;id=12520" alt="Bloggtoppen.se" /&gt;&lt;/a&gt; &lt;!-- /Bloggtoppen.se --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212091881452213631-5632637941539663720?l=hockeswe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hockeswe.blogspot.com/feeds/5632637941539663720/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8212091881452213631&amp;postID=5632637941539663720' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/5632637941539663720'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/5632637941539663720'/><link rel='alternate' type='text/html' href='http://hockeswe.blogspot.com/2007/05/skapa-en-ajaxcontroltoolkit-extender.html' title='Skapa en AjaxControlToolkit Extender'/><author><name>Håkan Canberger</name><uri>http://www.blogger.com/profile/07785350579880064843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8212091881452213631.post-6193841340344628840</id><published>2007-05-19T20:29:00.000+02:00</published><updated>2007-05-19T20:43:00.259+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='Ajax'/><category scheme='http://www.blogger.com/atom/ns#' term='Asp.net'/><title type='text'>Anropa Date.parseLocale() med en array</title><content type='html'>I dokumentation till javascript-metoden &lt;code&gt;Date.parseLocale(value,formats)&lt;/code&gt; (som Microsoft lagt till med Ajax) står det att formats är en array av format. Det är inte sant. Den tar formaten som flera argument:&lt;pre&gt;Date.parseLocale(value, format1, format2, ...)&lt;/pre&gt;Hur gör man då om man har en array med format och inte vill loopa över arrayen och göra ett anrop till &lt;code&gt;parseLocale&lt;/code&gt; för varje format? Ett sätt att göra det på är att använda standard-javascript-metoden &lt;code&gt;apply(thisObj, argArray)&lt;/code&gt;. Den kan köras på ett funktionsobjekt och tar som första argument det objekt som ska bli &lt;code&gt;this&lt;/code&gt; inne i funktionen. Som andra argument tar den en array med alla argument till funktionen. &lt;br /&gt;Så vi behöver bygga en array bestående av &lt;code&gt;[value, format1, format2, ...]&lt;/code&gt; och sen köra &lt;code&gt;apply&lt;/code&gt;. Så här:&lt;pre&gt;function myParseLocale(value,formats)&lt;br /&gt;{&lt;br /&gt;  var args=[value];&lt;br /&gt;  Array.addRange(args,formats);&lt;br /&gt;  return Date.parseLocale.apply(Date,args);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;Date.parseLocale&lt;/code&gt; är en metod som givet en sträng försöker tolka det som ett datum enligt ett av de inskickade formaten. Om den lyckas returneras ett &lt;code&gt;Date&lt;/code&gt;-objekt.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- Bloggtoppen.se --&gt; &lt;a href="http://www.bloggtoppen.se/"&gt;&lt;img border="0" src="http://www.bloggtoppen.se/tracker.php?do=in&amp;id=12520" alt="Bloggtoppen.se" /&gt;&lt;/a&gt; &lt;!-- /Bloggtoppen.se --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212091881452213631-6193841340344628840?l=hockeswe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hockeswe.blogspot.com/feeds/6193841340344628840/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8212091881452213631&amp;postID=6193841340344628840' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/6193841340344628840'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/6193841340344628840'/><link rel='alternate' type='text/html' href='http://hockeswe.blogspot.com/2007/05/anropa-javascript-dateparselocale-med.html' title='Anropa Date.parseLocale() med en array'/><author><name>Håkan Canberger</name><uri>http://www.blogger.com/profile/07785350579880064843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8212091881452213631.post-8599866989886143129</id><published>2007-05-18T10:23:00.000+02:00</published><updated>2007-05-20T00:56:06.969+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ajax'/><category scheme='http://www.blogger.com/atom/ns#' term='Extenders'/><category scheme='http://www.blogger.com/atom/ns#' term='Asp.net'/><title type='text'>Skicka värden till behaviors</title><content type='html'>&lt;div class="otherLanguage"&gt;&lt;a href="http://hocke.blogspot.com/2007/05/adding-extender-properties.html"&gt;English version of this entry&lt;/a&gt;&lt;/div&gt;En property i en Ajax Extender ser oftast ut så här:&lt;br /&gt;&lt;pre&gt;[ExtenderControlProperty]&lt;br /&gt;[DefaultValue("")]&lt;br /&gt;public string MyProperty&lt;br /&gt;{&lt;br /&gt;  get { ... }&lt;br /&gt;  set { ... }&lt;br /&gt;}&lt;/pre&gt;Med en matchande property i klientsidans behavior:&lt;pre&gt;get_MyProperty : function() { ... },&lt;br /&gt;set_MyProperty : function(value) { ... }&lt;/pre&gt;&lt;br /&gt;Värden som anges på serversidans &lt;code&gt;MyProperty&lt;/code&gt; kommer genom lite magi (nåja) att hamna på klientsidan och vara åtkomlig där.&lt;br /&gt;&lt;br /&gt;Ibland vill man skicka över värden, eller sätta egenskaper på klientens behavior utan att ha en matchande property på Extender-kontrollen. För att åstadkomma detta så override:a &lt;code&gt;RenderScriptAttributes()&lt;/code&gt; och lägg till klientegenskaper med &lt;code&gt;AddProperty()&lt;/code&gt;.&lt;pre&gt;protected override void RenderScriptAttributes(ScriptBehaviorDescriptor descriptor)&lt;br /&gt;{&lt;br /&gt;  base.RenderScriptAttributes(descriptor);&lt;br /&gt;  string horizontalAlignment=GetHorizontalAlignment();&lt;br /&gt;  descriptor.AddProperty("HorizontalAlignment", horizontalAlignment);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Voilà, propertyn &lt;b&gt;HorizontalAlignment&lt;/b&gt;i klientens behavior kommer att få ett värde utan att vi skapade en property på serversidan.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- Bloggtoppen.se --&gt; &lt;a href="http://www.bloggtoppen.se/"&gt;&lt;img border="0" src="http://www.bloggtoppen.se/tracker.php?do=in&amp;id=12520" alt="Bloggtoppen.se" /&gt;&lt;/a&gt; &lt;!-- /Bloggtoppen.se --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212091881452213631-8599866989886143129?l=hockeswe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hockeswe.blogspot.com/feeds/8599866989886143129/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8212091881452213631&amp;postID=8599866989886143129' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/8599866989886143129'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/8599866989886143129'/><link rel='alternate' type='text/html' href='http://hockeswe.blogspot.com/2007/05/english-version-of-this-entry-en.html' title='Skicka värden till behaviors'/><author><name>Håkan Canberger</name><uri>http://www.blogger.com/profile/07785350579880064843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8212091881452213631.post-3070162912523418045</id><published>2007-05-18T09:39:00.000+02:00</published><updated>2007-05-20T00:44:56.676+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ajax'/><category scheme='http://www.blogger.com/atom/ns#' term='Extenders'/><category scheme='http://www.blogger.com/atom/ns#' term='Asp.net'/><title type='text'>Namn på properties i Ajax extenders</title><content type='html'>&lt;div class="otherLanguage"&gt;&lt;a href="http://hocke.blogspot.com/2007/05/setting-property-names.html"&gt;English version of this entry&lt;/a&gt;&lt;/div&gt;Properties för Ajax-extenders som ärver av &lt;code&gt;ExtenderControlBase&lt;/code&gt; ser typiskt ut så här:&lt;pre class="csharpcode"&gt;[ExtenderControlProperty]&lt;br /&gt;[DefaultValue(&lt;span class="str"&gt;""&lt;/span&gt;)]&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; MyProperty&lt;br /&gt;{&lt;br /&gt;  get&lt;br /&gt;  {&lt;br /&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; GetPropertyValue(&lt;span class="str"&gt;"MyProperty"&lt;/span&gt;, &lt;span class="str"&gt;""&lt;/span&gt;);&lt;br /&gt;  }&lt;br /&gt;  set&lt;br /&gt;  {&lt;br /&gt;    SetPropertyValue(&lt;span class="str"&gt;"MyProperty"&lt;/span&gt;, &lt;span class="kwrd"&gt;value&lt;/span&gt;);&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I behavior-klassen på klientsidan måste en property med samma namn finnas:&lt;br /&gt;&lt;pre&gt;get_MyProperty : function() {&lt;br /&gt;  return this._myProperty;&lt;br /&gt;},&lt;br /&gt;set_MyProperty : function(value) {&lt;br /&gt;  this._myProperty = value;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Men om man nu vill att propertyn ska ha ett namn på serversidan och ett annat på klientsidan? Kul att du frågade. Riktigt enkelt. Markera propertyn på serversidan med  attributet &lt;code&gt;ClientPropertyName&lt;/code&gt;. Så om vi vill att &lt;code&gt;MyProperty&lt;/code&gt; ska heta &lt;b&gt;myProp&lt;/b&gt; på klientsidan, skriver man:&lt;br /&gt;&lt;pre class="csharpcode"&gt;[ExtenderControlProperty]&lt;br /&gt;[DefaultValue(&lt;span class="str"&gt;""&lt;/span&gt;)]&lt;br /&gt;&lt;span class="highlight"&gt;[ClientPropertyName(&lt;span class="str"&gt;"myProp"&lt;/span&gt;)]&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; MyProperty&lt;br /&gt;{&lt;br /&gt;  get&lt;br /&gt;  {&lt;br /&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; GetPropertyValue(&lt;span class="str"&gt;"MyProperty"&lt;/span&gt;, &lt;span class="str"&gt;""&lt;/span&gt;);&lt;br /&gt;  }&lt;br /&gt;  set&lt;br /&gt;  {&lt;br /&gt;    SetPropertyValue(&lt;span class="str"&gt;"MyProperty"&lt;/span&gt;, &lt;span class="kwrd"&gt;value&lt;/span&gt;);&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;På klientsidan kan vi då skriva:&lt;br /&gt;&lt;pre&gt;get_&lt;span class="highlight"&gt;myProp&lt;/span&gt; : function() {&lt;br /&gt;  return this._myProperty;&lt;br /&gt;},&lt;br /&gt;set_&lt;span class="highlight"&gt;myProp&lt;/span&gt; : function(value) {&lt;br /&gt;  this._myProperty = value;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Mer om attributen:&lt;br /&gt;&lt;a href="http://ajax.asp.net/ajaxtoolkit/Walkthrough/ExtenderClasses.aspx"&gt;http://ajax.asp.net/ajaxtoolkit/Walkthrough/ExtenderClasses.aspx&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- Bloggtoppen.se --&gt; &lt;a href="http://www.bloggtoppen.se/"&gt;&lt;img border="0" src="http://www.bloggtoppen.se/tracker.php?do=in&amp;id=12520" alt="Bloggtoppen.se" /&gt;&lt;/a&gt; &lt;!-- /Bloggtoppen.se --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212091881452213631-3070162912523418045?l=hockeswe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hockeswe.blogspot.com/feeds/3070162912523418045/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8212091881452213631&amp;postID=3070162912523418045' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/3070162912523418045'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/3070162912523418045'/><link rel='alternate' type='text/html' href='http://hockeswe.blogspot.com/2007/05/namn-p-properties-i-ajax-extenders.html' title='Namn på properties i Ajax extenders'/><author><name>Håkan Canberger</name><uri>http://www.blogger.com/profile/07785350579880064843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8212091881452213631.post-4065693941310308680</id><published>2007-05-10T12:28:00.000+02:00</published><updated>2007-05-20T00:29:18.548+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='Ajax'/><category scheme='http://www.blogger.com/atom/ns#' term='Asp.net'/><title type='text'>OOP i JavaScript</title><content type='html'>&lt;div class="otherLanguage"&gt;&lt;a href="http://hocke.blogspot.com/2007/05/oop-in-javascript.html"&gt;English version of this entry&lt;/a&gt;&lt;/div&gt;MSDN Magazine, maj 2007 har en intressant artikel om hur man programmerar objektorienterat i JavaScript. Ett absolut måste att läsa om man använder Microsofts Asp.Net Ajax och vill ha lite koll på vad som händer eftersom hela kodbiblioteket på klienten är skrivet med dessa tekniker.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/msdnmag/issues/07/05/JavaScript/default.aspx"&gt;http://msdn.microsoft.com/msdnmag/issues/07/05/JavaScript/default.aspx&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- Bloggtoppen.se --&gt; &lt;a href="http://www.bloggtoppen.se/"&gt;&lt;img border="0" src="http://www.bloggtoppen.se/tracker.php?do=in&amp;id=12520" alt="Bloggtoppen.se" /&gt;&lt;/a&gt; &lt;!-- /Bloggtoppen.se --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212091881452213631-4065693941310308680?l=hockeswe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hockeswe.blogspot.com/feeds/4065693941310308680/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8212091881452213631&amp;postID=4065693941310308680' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/4065693941310308680'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/4065693941310308680'/><link rel='alternate' type='text/html' href='http://hockeswe.blogspot.com/2007/05/english-version-of-this-entry-msdn.html' title='OOP i JavaScript'/><author><name>Håkan Canberger</name><uri>http://www.blogger.com/profile/07785350579880064843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8212091881452213631.post-7808069823080093323</id><published>2007-03-22T16:16:00.000+01:00</published><updated>2007-05-20T00:31:07.716+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ajax'/><category scheme='http://www.blogger.com/atom/ns#' term='Asp.net'/><title type='text'>Validators fungerar inte med UpdatePanel</title><content type='html'>&lt;div class="otherLanguage"&gt;&lt;a href="http://hocke.blogspot.com/2007/03/validators-not-working-with-updatepanel.html"&gt;English version of this entry&lt;/a&gt;&lt;/div&gt;Validatorer fungerar ibland rätt dåligt när man stoppar dem i en &lt;code&gt;UpdatePanel&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;I Ajx asp.net 1.0 releasen (den som finns nu i skrivande stund) så var tanken att man skulle fått till det här genom att byta ut de vanliga validatorerna mot ajax-enablade varianter. Så blev det inte. I väntan på nästa releas så finns det en fix tillgänglig.&lt;br /&gt;&lt;br /&gt;Kolla här: &lt;a href="http://blogs.msdn.com/mattgi/archive/2007/01/23/asp-net-ajax-validators.aspx"&gt;http://blogs.msdn.com/mattgi/archive/2007/01/23/asp-net-ajax-validators.aspx&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- Bloggtoppen.se --&gt; &lt;a href="http://www.bloggtoppen.se/"&gt;&lt;img border="0" src="http://www.bloggtoppen.se/tracker.php?do=in&amp;id=12520" alt="Bloggtoppen.se" /&gt;&lt;/a&gt; &lt;!-- /Bloggtoppen.se --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212091881452213631-7808069823080093323?l=hockeswe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hockeswe.blogspot.com/feeds/7808069823080093323/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8212091881452213631&amp;postID=7808069823080093323' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/7808069823080093323'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/7808069823080093323'/><link rel='alternate' type='text/html' href='http://hockeswe.blogspot.com/2007/05/validators-fungerar-inte-med.html' title='Validators fungerar inte med UpdatePanel'/><author><name>Håkan Canberger</name><uri>http://www.blogger.com/profile/07785350579880064843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8212091881452213631.post-430767821412855873</id><published>2007-02-16T10:49:00.000+01:00</published><updated>2007-05-20T00:18:35.641+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='Ajax'/><category scheme='http://www.blogger.com/atom/ns#' term='CSS'/><category scheme='http://www.blogger.com/atom/ns#' term='Asp.net'/><title type='text'>Snabbkommandon och översikter</title><content type='html'>Keyboard shortcuts för VS 20005:&lt;br /&gt;&lt;a href="http://blogs.msdn.com/robcaron/archive/2007/01/29/1552795.aspx"&gt;http://blogs.msdn.com/robcaron/archive/2007/01/29/1552795.aspx&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Regular Expressions cheat sheet:&lt;br /&gt;&lt;a href="http://www.ilovejackdaniels.com/cheat-sheets/regular-expressions-cheat-sheet/"&gt;http://www.ilovejackdaniels.com/cheat-sheets/regular-expressions-cheat-sheet/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;CSS cheat sheet&lt;br /&gt;&lt;a href="http://www.ilovejackdaniels.com/cheat-sheets/css-cheat-sheet/"&gt;http://www.ilovejackdaniels.com/cheat-sheets/css-cheat-sheet/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;JavaScript cheat sheet&lt;br /&gt;&lt;a href="http://www.ilovejackdaniels.com/cheat-sheets/javascript-cheat-sheet/"&gt;http://www.ilovejackdaniels.com/cheat-sheets/javascript-cheat-sheet/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Asp.net Lifecycle:&lt;br /&gt;&lt;a href="http://john-sheehan.com/blog/index.php/net-cheat-sheets/"&gt;http://john-sheehan.com/blog/index.php/net-cheat-sheets/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;AJAX asp.net&lt;br /&gt;&lt;a href="http://aspnetresources.com/blog/ms_ajax_cheat_sheets_batch2.aspx"&gt;http://aspnetresources.com/blog/ms_ajax_cheat_sheets_batch2.aspx&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- Bloggtoppen.se --&gt; &lt;a href="http://www.bloggtoppen.se/"&gt;&lt;img border="0" src="http://www.bloggtoppen.se/tracker.php?do=in&amp;id=12520" alt="Bloggtoppen.se" /&gt;&lt;/a&gt; &lt;!-- /Bloggtoppen.se --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212091881452213631-430767821412855873?l=hockeswe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hockeswe.blogspot.com/feeds/430767821412855873/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8212091881452213631&amp;postID=430767821412855873' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/430767821412855873'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/430767821412855873'/><link rel='alternate' type='text/html' href='http://hockeswe.blogspot.com/2007/02/snabbkommandon-och-versikter.html' title='Snabbkommandon och översikter'/><author><name>Håkan Canberger</name><uri>http://www.blogger.com/profile/07785350579880064843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8212091881452213631.post-5218275517079788993</id><published>2007-02-08T14:45:00.000+01:00</published><updated>2007-05-20T00:13:49.619+02:00</updated><title type='text'>Fippla inte med ClientID för tidigt</title><content type='html'>&lt;div class="otherLanguage"&gt;&lt;a href="http://hocke.blogspot.com/2007/02/dont-access-property-clientid-to-early.html"&gt;English version of this entry&lt;/a&gt;&lt;/div&gt;&lt;code&gt;ClientId&lt;/code&gt; propertyn på en kontroll har ett korrekt värde först efter det att kontrollen har lagts till en Controls-samling, dvs. först när den har fått en förälder. Inte nog med det, föräldern måste också ha en förälder och så vidare hela vägen upp till Page.&lt;br /&gt;&lt;br /&gt;Om du anropar &lt;code&gt;ClientId&lt;/code&gt; för tidigt, så får du tillbaka nåt oanvändbart. Inte nog med det, den gode kontrollen cachear dessutom värdet som den skickade till dig och alla efterföljande anrop  kommer att få samma meningslösa värde. Detta drabbar inte bara dig utan även asp.net-motorn kommer att få fel värde. T.ex. så kommer postback-event att funger som de ska.&lt;br /&gt;&lt;br /&gt;Big No-no:&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; MyControl : CompositeControl&lt;br /&gt;{&lt;br /&gt;  &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CreateChildControls()&lt;br /&gt;  {&lt;br /&gt;    Button myButton = &lt;span class="kwrd"&gt;new&lt;/span&gt; Button();&lt;br /&gt;    myButton.Text = &lt;span class="str"&gt;"Unclicked"&lt;/span&gt;;&lt;br /&gt;    myButton.Click += &lt;span class="kwrd"&gt;new&lt;/span&gt; EventHandler(myButton_Click);&lt;br /&gt;    Controls.Add(myButton);&lt;br /&gt;    &lt;br /&gt;    &lt;span class="rem"&gt;//MyControl has no parent yet. The following code will prevent&lt;/span&gt;&lt;br /&gt;    &lt;span class="rem"&gt;//the myButton_Click from beeing called when the button is clicked.&lt;/span&gt;&lt;br /&gt;    &lt;span class="rem"&gt;//Remove the line and it will be called.&lt;/span&gt;&lt;br /&gt;    &lt;span class="highlight"&gt;&lt;span class="kwrd"&gt;string&lt;/span&gt; id = myButton.ClientID;&lt;/span&gt; &lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  &lt;span class="kwrd"&gt;void&lt;/span&gt; myButton_Click(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;br /&gt;  {&lt;br /&gt;    Button button = (Button)sender;&lt;br /&gt;    button.Text = &lt;span class="str"&gt;"clicked"&lt;/span&gt;;&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ytterligare exempel: &lt;a href="http://aspadvice.com/blogs/joteke/archive/2007/01/28/Accessing-ClientID-or-UniqueID-too-early-can-cause-issues.aspx"&gt;http://aspadvice.com/blogs/joteke/archive/2007/01/28/Accessing-ClientID-or-UniqueID-too-early-can-cause-issues.aspx&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- Bloggtoppen.se --&gt; &lt;a href="http://www.bloggtoppen.se/"&gt;&lt;img border="0" src="http://www.bloggtoppen.se/tracker.php?do=in&amp;id=12520" alt="Bloggtoppen.se" /&gt;&lt;/a&gt; &lt;!-- /Bloggtoppen.se --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212091881452213631-5218275517079788993?l=hockeswe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hockeswe.blogspot.com/feeds/5218275517079788993/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8212091881452213631&amp;postID=5218275517079788993' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/5218275517079788993'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/5218275517079788993'/><link rel='alternate' type='text/html' href='http://hockeswe.blogspot.com/2007/02/fippla-inte-med-clientid-fr-tidigt.html' title='Fippla inte med ClientID för tidigt'/><author><name>Håkan Canberger</name><uri>http://www.blogger.com/profile/07785350579880064843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8212091881452213631.post-4814833302378173558</id><published>2007-01-31T18:08:00.000+01:00</published><updated>2007-05-19T23:58:47.671+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ajax'/><category scheme='http://www.blogger.com/atom/ns#' term='Asp.net'/><title type='text'>Hitta en kontroll i javascript (Ajax ASP.Net)</title><content type='html'>&lt;div class="otherLanguage"&gt;&lt;a href="http://hocke.blogspot.com/2007/01/find-control-in-javascript-ajax-aspnet.html"&gt;English version of this entry&lt;/a&gt;&lt;/div&gt;För att hitta en kontroll som har ID="MyControl" använd funktionen &lt;code&gt;$get&lt;/code&gt;.&lt;br /&gt;Exempel:&lt;pre&gt;alert(&lt;span class="highlight"&gt;$get("MyControl")&lt;/span&gt;.id);&lt;/pre&gt;&lt;br /&gt;Observera att det är motsvarande ClientID du ska använda. &lt;code&gt;$get&lt;/code&gt; finns bara tillgänglig på en ASP.Net Ajax-sida.&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- Bloggtoppen.se --&gt; &lt;a href="http://www.bloggtoppen.se/"&gt;&lt;img border="0" src="http://www.bloggtoppen.se/tracker.php?do=in&amp;id=12520" alt="Bloggtoppen.se" /&gt;&lt;/a&gt; &lt;!-- /Bloggtoppen.se --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212091881452213631-4814833302378173558?l=hockeswe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hockeswe.blogspot.com/feeds/4814833302378173558/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8212091881452213631&amp;postID=4814833302378173558' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/4814833302378173558'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/4814833302378173558'/><link rel='alternate' type='text/html' href='http://hockeswe.blogspot.com/2007/01/hitta-en-kontroll-i-javascript-ajax.html' title='Hitta en kontroll i javascript (Ajax ASP.Net)'/><author><name>Håkan Canberger</name><uri>http://www.blogger.com/profile/07785350579880064843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8212091881452213631.post-6573030567488939706</id><published>2007-01-31T16:44:00.000+01:00</published><updated>2007-05-19T23:52:42.923+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ajax'/><category scheme='http://www.blogger.com/atom/ns#' term='Asp.net'/><title type='text'>Visa och dölj en ModalPopupExtender-popup</title><content type='html'>&lt;div class="otherLanguage"&gt;&lt;a href="http://hocke.blogspot.com/2007/01/show-and-hide-modalpopupextender-from.html"&gt;English version of this entry&lt;/a&gt;&lt;/div&gt;För att via kod visa en popup som en &lt;CODE&gt;ModalPopupExtender&lt;/CODE&gt; hanterar som måste du sätta &lt;CODE&gt;BehaviorID&lt;/CODE&gt; propertyn: &lt;PRE&gt;&amp;lt;ajaxToolkit:ModalPopupExtender...&lt;br /&gt;&lt;span class=highlight&gt;BehaviorID="MyModalPopupExtender"&lt;/span&gt;&lt;br /&gt;... /&amp;gt; &lt;/PRE&gt;Med hjälp av &lt;CODE&gt;$find&lt;/CODE&gt; kan du få tag på instansen. Exempel på kod för att visa och dölja popupen. &lt;PRE&gt;&amp;lt;script language="javascript"&amp;gt;&lt;br /&gt;   function hidePopup()&lt;br /&gt;   {&lt;br /&gt;       $find('MyModalPopupExtender').show();&lt;br /&gt;   }&lt;br /&gt;   function hidePopup()&lt;br /&gt;   {&lt;br /&gt;       $find('MyModalPopupExtender').hide();&lt;br /&gt;   }&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/PRE&gt;&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- Bloggtoppen.se --&gt; &lt;a href="http://www.bloggtoppen.se/"&gt;&lt;img border="0" src="http://www.bloggtoppen.se/tracker.php?do=in&amp;id=12520" alt="Bloggtoppen.se" /&gt;&lt;/a&gt; &lt;!-- /Bloggtoppen.se --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212091881452213631-6573030567488939706?l=hockeswe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hockeswe.blogspot.com/feeds/6573030567488939706/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8212091881452213631&amp;postID=6573030567488939706' title='2 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/6573030567488939706'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/6573030567488939706'/><link rel='alternate' type='text/html' href='http://hockeswe.blogspot.com/2007/05/untitled.html' title='Visa och dölj en ModalPopupExtender-popup'/><author><name>Håkan Canberger</name><uri>http://www.blogger.com/profile/07785350579880064843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8212091881452213631.post-1061359584956228046</id><published>2007-01-30T21:39:00.000+01:00</published><updated>2007-07-27T11:27:05.904+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Asp.net'/><title type='text'>Asp.Net ViewState</title><content type='html'>&lt;div class="otherLanguage"&gt;&lt;a href="http://hocke.blogspot.com/2007/01/aspnet-viewstate.html"&gt;English version of this entry&lt;/a&gt;&lt;/div&gt;&lt;p&gt;Här är en bra artikel som förklarar ViewState i Asp.Net.&lt;br /&gt;&lt;a href="http://weblogs.asp.net/infinitiesloop/archive/2006/08/03/Truly-Understanding-Viewstate.aspx"&gt;http://weblogs.asp.net/infinitiesloop/archive/2006/08/03/Truly-Understanding-Viewstate.aspx&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;Det mest intressanta:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;De flesta kontroller sparar sina properties i ett fält som heter &lt;span style="font-weight: bold;"&gt;ViewState&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;Initialt håller kontrollen inte koll på förändringar i &lt;span style="font-weight: bold;"&gt;ViewState&lt;/span&gt;.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Efter det att en kontroll har börjat att hålla koll på sitt &lt;span style="font-weight: bold;"&gt;ViewState&lt;/span&gt;, eller spåra förändringar av &lt;span style="font-weight: bold;"&gt;ViewState &lt;/span&gt;(dålig översättning av tracking ViewState) så kommer ändrade properties att markeras som dirty. Det är endast dessa properties som kommer  att serialiseras ner till det dolda  &lt;code&gt;__VIEWSTATE&lt;/code&gt; fältet.&lt;/li&gt;&lt;li&gt;En kontroll börjar spåra förändringar av &lt;span style="font-weight: bold;"&gt;ViewState &lt;/span&gt;efter sin &lt;code&gt;OnInit&lt;/code&gt;.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Sidans &lt;code&gt;OnInit&lt;/code&gt; anropas efter alla kontollers, så vid det laget så spårar alla kontroller förändringar av sina &lt;span style="font-weight: bold;"&gt;ViewState&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;Data som binds under sidans &lt;code&gt;OnInit&lt;/code&gt; och &lt;code&gt;OnLoad&lt;/code&gt;, t.ex. i &lt;code&gt;Page_Load&lt;/code&gt;, kommer att serialiseras och skickas till klienten i   &lt;code&gt;__VIEWSTATE&lt;/code&gt;, eftersom kontrollerna spårar förändringar av &lt;span style="font-weight: bold;"&gt;ViewState&lt;/span&gt;. Detta innebär; Sätt inte properties på kontroller efter sidans  &lt;code&gt;OnInit&lt;/code&gt; om du inte vill att det ska hamna i &lt;code&gt;__VIEWSTATE&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Properties på kontroller som sätts under sidans  &lt;code&gt;OnPreInit&lt;/code&gt;, dvs. innan kontrollerna börjat spåra förändringar av &lt;span style="font-weight: bold;"&gt;ViewState&lt;/span&gt;, kommer inte att hamna i &lt;code&gt;__VIEWSTATE&lt;/code&gt;. Detta kan utnyttjas till att fylla kontroller med data som är billigt och enkelt att hämta vid varje postback, istället för att roundtrippa datat via klienten.&lt;/li&gt;&lt;li&gt;När du skapar kontroller via kod, t.ex. i metoden  &lt;code&gt;CreateChildControls&lt;/code&gt; i en custom control eller &lt;code&gt;CompositeControl&lt;/code&gt;) så se till att sätta alla defaultvärden för properties &lt;span style="font-style: italic;"&gt;innan&lt;/span&gt; du lägger till kontrollen i &lt;code&gt;Controls&lt;/code&gt; .&lt;br /&gt;Innan du lägger till den så svävar kontrollen så att säga fritt i luften. Den känner inte till något om omvärlden och och "ingen" har fått den att börja spåra förändringar av &lt;span style="font-weight: bold;"&gt;ViewState&lt;/span&gt;. Efter det att du lagt till den i &lt;code&gt;Controls&lt;/code&gt; finns det risk att kontrollen direkt efter &lt;code&gt;Add&lt;/code&gt;-anropet kommer börja spåra förändringar (en kontroll som skapas sent i en sidan lifscykel får nämligen springa ikapp övriga kontroller och kommer därför direkt att raskt knata igenom alla events och så).&lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- Bloggtoppen.se --&gt; &lt;a href="http://www.bloggtoppen.se/"&gt;&lt;img border="0" src="http://www.bloggtoppen.se/tracker.php?do=in&amp;id=12520" alt="Bloggtoppen.se" /&gt;&lt;/a&gt; &lt;!-- /Bloggtoppen.se --&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212091881452213631-1061359584956228046?l=hockeswe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hockeswe.blogspot.com/feeds/1061359584956228046/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8212091881452213631&amp;postID=1061359584956228046' title='0 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/1061359584956228046'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8212091881452213631/posts/default/1061359584956228046'/><link rel='alternate' type='text/html' href='http://hockeswe.blogspot.com/2007/01/aspnet-viewstate.html' title='Asp.Net ViewState'/><author><name>Håkan Canberger</name><uri>http://www.blogger.com/profile/07785350579880064843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
