<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" gd:etag="W/&quot;AkECQXwyeSp7ImA9WhRbGEw.&quot;"><id>tag:blogger.com,1999:blog-6511237790974218081</id><updated>2012-02-09T21:17:40.291+01:00</updated><category term="Adorner" /><category term="IQueryProvider" /><category term="Lean" /><category term="Join" /><category term="Design Time Data" /><category term="SettingsProvider" /><category term="Code Design" /><category term="Expression Blend" /><category term="Ackmed" /><category term="ICustomTypeDescriptor" /><category term="tales of an outlier" /><category term="MSTest" /><category term="IEnlistmentNotification" /><category term="Job" /><category term="OT" /><category term="SqlCe 3.5" /><category term="Virtual CD" /><category term="CueBanner" /><category term="Formula" /><category term="Community" /><category term="TDD" /><category term="Memento" /><category term="Compile Time" /><category term="Design Time" /><category term="WorkItem" /><category term="Attached Properties" /><category term="Visual Tree" /><category term="Event Listeners" /><category term="PostSharp" /><category term="IUserType" /><category term="Facility" /><category term="UX" /><category term="Behavior" /><category term="Object Database" /><category term="TextBox.UndoLimit" /><category term="Logical Tree" /><category term="TechEd" /><category term="Pattern" /><category term="UI Composition" /><category term="Validation Application Block" /><category term="Castle Windsor" /><category term="User Experience" /><category term="IWeakEventListener" /><category term="NHibernate" /><category term="WPF Interop" /><category term="Metallica" /><category term="AOP" /><category term="Team Foundation Server" /><category term="Moderazione" /><category term="Architecture" /><category term="MVC" /><category term="Log4net" /><category term="Binding" /><category term="XP" /><category term="CodeContract" /><category term="Attached Behaviors" /><category term="Designer" /><category term="EeePC" /><category term="Code Drafts" /><category term="Software Mason" /><category term="Lambda Expressions" /><category term="Visual Studio 2010" /><category term="User Stories" /><category term="Unit Tests" /><category term="Configuration" /><category term="Roslyn" /><category term="Kanban" /><category term="BUG" /><category term="Model View ViewModel" /><category term="Useless" /><category term="Why not..." /><category term="Community Days" /><category term="Anonymous Methods" /><category term="Windows 7" /><category term="ListView" /><category term="Blend" /><category term="Markup Extension" /><category term="Unsubscribe" /><category term="AsyncWorker" /><category term="TransactionScope" /><category term="TFS" /><category term="EntityFramework" /><category term="SharePoint" /><category term="ICommand" /><category term="Visual Studio Addiction" /><category term="Recaptcha" /><category term="MVP Award" /><category term="Inversion of Control" /><category term="IPreInsertEventListener" /><category term="Tracing" /><category term="Db4o" /><category term="Lego" /><category term="NHProof" /><category term="RavenDB" /><category term="Framework.Net 4.0" /><category term="Linq" /><category term="WeakEventManager" /><category term="Death Magnetic" /><category term="WeakReference" /><category term="WPF" /><category term="Fluent Interfaces" /><category term="Fluent Configuration" /><category term="UGIAlt.Net" /><category term="Utilities" /><title>Mauro and the sustainable development</title><subtitle type="html">The journey is the most important thing, not the destination.
Find your next destination and start travelling again.</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://mauroservienti.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://mauroservienti.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Mauro Servienti</name><uri>http://www.blogger.com/profile/10629055661352952427</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="23" height="32" src="http://3.bp.blogspot.com/-dm7TXYKMYyw/Tx6n9k3EMZI/AAAAAAAAAII/dqd_n1UdKsI/s220/Avatar.JPG" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>432</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/tpx" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="tpx" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;AkECQX07eCp7ImA9WhRbGEw.&quot;"><id>tag:blogger.com,1999:blog-6511237790974218081.post-98855777310928513</id><published>2012-02-09T14:37:00.000+01:00</published><updated>2012-02-09T21:17:40.300+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-09T21:17:40.300+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Software Mason" /><category scheme="http://www.blogger.com/atom/ns#" term="RavenDB" /><title>What am I learning from the document database experience?</title><content type="html">I’ve recently worked on a really interesting project based on &lt;a href="http://ravendb.net/" target="_blank"&gt;RavenDB&lt;/a&gt; and &lt;a href="http://www.nservicebus.com/" target="_blank"&gt;NServiceBus&lt;/a&gt;, there &lt;a href="http://www.guisa.org/" target="_blank"&gt;will be a lot of time&lt;/a&gt; to deeply speak about it.&lt;br /&gt;
&lt;blockquote&gt;
This argument should be treated at least in a 1h talk or far better in an open panel discussion…if someone is interested ping me, we can do that!&lt;/blockquote&gt;
Document databases perfectly suites some DDD principles, such as the concept of aggregate; &lt;em&gt;be aware&lt;/em&gt; that I’m not saying that relational databases does not suite, &lt;strong&gt;this post is not about relational versus document&lt;/strong&gt; (I dislike the “no-sql” name).&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Read on…questions&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
After the “document-db” experience I asked myself one single question: why do I need an &lt;a href="http://it.wikipedia.org/wiki/Object-relational_mapping" target="_blank"&gt;ORM&lt;/a&gt;?&lt;br /&gt;
The short answer is: &lt;em&gt;we tend to introduce an ORM to solve a problem that we have introduced&lt;/em&gt;.&lt;br /&gt;
So…if we do not introduce the first problem do we need an ORM anymore? basically yes, but now the question “moves” to: what an ORM should do for us?&lt;br /&gt;
The short answer is in the name: ORM –&amp;gt; map relational data to objects (period).&lt;br /&gt;
&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;Abuse&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
ORM(s) per se are a wonderful thing, as with everything, problems come with the abuse of the wonders &lt;img alt="Smile" class="wlEmoticon wlEmoticon-smile" src="http://lh6.ggpht.com/-yfCrTf5V1Kw/TzKg3-bEdkI/AAAAAAAABJ4/g5t_gSTs-WM/wlEmoticon-smile2.png?imgmax=800" style="border-bottom-style: none; border-left-style: none; border-right-style: none; border-top-style: none;" /&gt;…typically what I hear from the field is something like: “I want to get rid of all that SQL strings that pollute my code”…&lt;br /&gt;
…and? they end up using hql strings with NHibernate…what is the difference? why the hell you want to hide SQL code from your program and then you want to view the generated SQL using a profiler?&lt;br /&gt;
I suppose, well at least it is what generally happens to me, that when we face the design of the database we tend to forget which will be, at the application level, the usage of the data we are designing…we tend to follow design guidelines and design rules instead of saying “I need the data in that shape, period”…and then we &lt;em&gt;masturbate&lt;/em&gt; that data with an ORM to shape the perfectly normalized data in the form we really want them…&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Astute…isn’t it?&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Listen to me: give it up! try once to go back to the origin, use SQL, use Stored Procedures, design your data as you need them not as the book told you to design them…once you re-learned the “story” do you own choice, there are ton of tools out there that follows the “keep it simple, Luke” pattern:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://code.google.com/p/dapper-dot-net/" target="_blank"&gt;Dapper&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.toptensoftware.com/petapoco/" target="_blank"&gt;PetaPoco&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/markrendle/Simple.Data" target="_blank"&gt;Simple.Data&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/robconery/massive" target="_blank"&gt;Massive&lt;/a&gt;;&lt;/li&gt;
&lt;/ul&gt;
&lt;strong&gt;Conclusion(s)&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
I suppose that the human kind is basically &lt;em&gt;stupid&lt;/em&gt; and tends to forget too easily the past…”they” gave us SQL, then someone invented the ORM (I’ll repeat myself: a wonder, really) and we forgot that the ORM is basically a way to get rid of the SQL it is not a “replacement”, then ORM guys start to over-engineer giving us lot’s of features on top of ORM(s)…features that, if you use an Object Model, can be really lifesavers such as Identity Map or Unit of Work but gave us also the vacuum cleaner that let us hide under the carpet bad data design decisions…and obviously we start to use all that cool features…producing tons of joins or select n+1 and looking at SQL, yeah old hated SLQ hidden under the carpet, in a profiler to understand what is going on…why the hell our application is so slow…&lt;br /&gt;
Give a try to document databases, not because they are better than relational ones (they are not, both have pros and cons) but because they force your mind to go back to the basics, they force you to understand some DDD principles (such as Aggregates and Bounded Contexts) and they let us see the light at the and of the tunnel giving us the opportunity to completely re-think our approach to the relational model.&lt;br /&gt;
&lt;br /&gt;
.m&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6511237790974218081-98855777310928513?l=mauroservienti.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/uU9AvljIwBUtgqKtb9kpdP_cGck/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/uU9AvljIwBUtgqKtb9kpdP_cGck/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/uU9AvljIwBUtgqKtb9kpdP_cGck/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/uU9AvljIwBUtgqKtb9kpdP_cGck/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/tpx/~4/IiJEHVRmxzQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mauroservienti.blogspot.com/feeds/98855777310928513/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://mauroservienti.blogspot.com/2012/02/what-am-i-learning-from-document.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/98855777310928513?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/98855777310928513?v=2" /><link rel="alternate" type="text/html" href="http://mauroservienti.blogspot.com/2012/02/what-am-i-learning-from-document.html" title="What am I learning from the document database experience?" /><author><name>Mauro Servienti</name><uri>http://www.blogger.com/profile/10629055661352952427</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="23" height="32" src="http://3.bp.blogspot.com/-dm7TXYKMYyw/Tx6n9k3EMZI/AAAAAAAAAII/dqd_n1UdKsI/s220/Avatar.JPG" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh6.ggpht.com/-yfCrTf5V1Kw/TzKg3-bEdkI/AAAAAAAABJ4/g5t_gSTs-WM/s72-c/wlEmoticon-smile2.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CE4BRXc7fSp7ImA9WhRbFkg.&quot;"><id>tag:blogger.com,1999:blog-6511237790974218081.post-5716453828707569148</id><published>2012-02-07T23:15:00.001+01:00</published><updated>2012-02-07T23:15:54.905+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-07T23:15:54.905+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="RavenDB" /><category scheme="http://www.blogger.com/atom/ns#" term="UGIAlt.Net" /><category scheme="http://www.blogger.com/atom/ns#" term="Community" /><title>UGIAlt.Net</title><content type="html">&lt;p&gt;I would like to thank all the guys at the &lt;a href="http://ugialt.net/" target="_blank"&gt;UGIAlt.Net&lt;/a&gt; user group for the amazing conference held in Milan where I gave a talk about &lt;a href="http://ravendb.net/" target="_blank"&gt;RavenDB&lt;/a&gt;:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/-xVGuhm8EHrc/TzGil0Zs0mI/AAAAAAAABAA/Z_JeHCEWXHI/s1600-h/image%25255B2%25255D.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/-xK75f_uiSJM/TzGimeXbGtI/AAAAAAAABAE/vdakB2u7l7o/image_thumb.png?imgmax=800" width="244" height="83" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;You can find the slide deck and samples on &lt;a href="https://skydrive.live.com/?cid=e5479799f933c3ed&amp;amp;id=E5479799F933C3ED!9478" target="_blank"&gt;SkyDrive&lt;/a&gt; and the talk recording on &lt;a href="http://vimeo.com/35621329" target="_blank"&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;.m&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6511237790974218081-5716453828707569148?l=mauroservienti.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/ft3PmJAjWA5G9WlZgIFfY5LAo44/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ft3PmJAjWA5G9WlZgIFfY5LAo44/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/ft3PmJAjWA5G9WlZgIFfY5LAo44/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ft3PmJAjWA5G9WlZgIFfY5LAo44/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/tpx/~4/LAlykRq0nWI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mauroservienti.blogspot.com/feeds/5716453828707569148/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://mauroservienti.blogspot.com/2012/02/ugialtnet.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/5716453828707569148?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/5716453828707569148?v=2" /><link rel="alternate" type="text/html" href="http://mauroservienti.blogspot.com/2012/02/ugialtnet.html" title="UGIAlt.Net" /><author><name>Mauro Servienti</name><uri>http://www.blogger.com/profile/10629055661352952427</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="23" height="32" src="http://3.bp.blogspot.com/-dm7TXYKMYyw/Tx6n9k3EMZI/AAAAAAAAAII/dqd_n1UdKsI/s220/Avatar.JPG" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh6.ggpht.com/-xK75f_uiSJM/TzGimeXbGtI/AAAAAAAABAE/vdakB2u7l7o/s72-c/image_thumb.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CEQNQX8zfip7ImA9WhRbFkg.&quot;"><id>tag:blogger.com,1999:blog-6511237790974218081.post-3087869711828337719</id><published>2012-02-07T23:06:00.001+01:00</published><updated>2012-02-07T23:06:30.186+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-07T23:06:30.186+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Architecture" /><category scheme="http://www.blogger.com/atom/ns#" term="Community Days" /><category scheme="http://www.blogger.com/atom/ns#" term="Community" /><title>Community Days 2012</title><content type="html">&lt;p&gt;&lt;a href="http://www.communitydays.it" target="_blank"&gt;Community Days&lt;/a&gt; 2012 are approaching, I’m excited because I’m going to &lt;a href="http://www.communitydays.it/events/communitydays-2012/arch02/" target="_blank"&gt;give a talk&lt;/a&gt; about &lt;a href="http://www.nservicebus.com/" target="_blank"&gt;NServiceBus&lt;/a&gt; in real, real real &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://lh4.ggpht.com/-J0KGMZS7Oco/TzGgZMFS84I/AAAAAAAAA_4/b55nFnBTaw0/wlEmoticon-smile%25255B2%25255D.png?imgmax=800" /&gt;, scenario.&lt;/p&gt;  &lt;p&gt;See you there.&lt;/p&gt;  &lt;p&gt;.m&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6511237790974218081-3087869711828337719?l=mauroservienti.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/EOa_ldCDibHs7IbCST2sezSu7j0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/EOa_ldCDibHs7IbCST2sezSu7j0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/EOa_ldCDibHs7IbCST2sezSu7j0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/EOa_ldCDibHs7IbCST2sezSu7j0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/tpx/~4/9AI05oW_Yds" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mauroservienti.blogspot.com/feeds/3087869711828337719/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://mauroservienti.blogspot.com/2012/02/community-days-2012.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/3087869711828337719?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/3087869711828337719?v=2" /><link rel="alternate" type="text/html" href="http://mauroservienti.blogspot.com/2012/02/community-days-2012.html" title="Community Days 2012" /><author><name>Mauro Servienti</name><uri>http://www.blogger.com/profile/10629055661352952427</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="23" height="32" src="http://3.bp.blogspot.com/-dm7TXYKMYyw/Tx6n9k3EMZI/AAAAAAAAAII/dqd_n1UdKsI/s220/Avatar.JPG" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh4.ggpht.com/-J0KGMZS7Oco/TzGgZMFS84I/AAAAAAAAA_4/b55nFnBTaw0/s72-c/wlEmoticon-smile%25255B2%25255D.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CUMHRXg8cSp7ImA9WhRbFkw.&quot;"><id>tag:blogger.com,1999:blog-6511237790974218081.post-1150682061176688598</id><published>2012-02-07T12:17:00.001+01:00</published><updated>2012-02-07T12:17:14.679+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-07T12:17:14.679+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Software Mason" /><category scheme="http://www.blogger.com/atom/ns#" term="Roslyn" /><title>Interesting Roslyn usage(s)</title><content type="html">&lt;p&gt;&lt;a href="http://blogs.msdn.com/b/csharpfaq/archive/2012/02/06/implementing-a-code-action-using-roslyn.aspx" target="_blank"&gt;take a look here&lt;/a&gt;, really interesting…really.&lt;/p&gt;  &lt;p&gt;.m&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6511237790974218081-1150682061176688598?l=mauroservienti.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Etdotmr16aQ15ou8zTtltUhP_uc/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Etdotmr16aQ15ou8zTtltUhP_uc/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Etdotmr16aQ15ou8zTtltUhP_uc/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Etdotmr16aQ15ou8zTtltUhP_uc/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/tpx/~4/bLIgkXGoOGo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mauroservienti.blogspot.com/feeds/1150682061176688598/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://mauroservienti.blogspot.com/2012/02/interesting-roslyn-usages.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/1150682061176688598?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/1150682061176688598?v=2" /><link rel="alternate" type="text/html" href="http://mauroservienti.blogspot.com/2012/02/interesting-roslyn-usages.html" title="Interesting Roslyn usage(s)" /><author><name>Mauro Servienti</name><uri>http://www.blogger.com/profile/10629055661352952427</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="23" height="32" src="http://3.bp.blogspot.com/-dm7TXYKMYyw/Tx6n9k3EMZI/AAAAAAAAAII/dqd_n1UdKsI/s220/Avatar.JPG" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;A0MEQXk_fCp7ImA9WhRbFUw.&quot;"><id>tag:blogger.com,1999:blog-6511237790974218081.post-2213690819690820923</id><published>2012-02-06T10:10:00.000+01:00</published><updated>2012-02-06T10:10:00.744+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-06T10:10:00.744+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Software Mason" /><category scheme="http://www.blogger.com/atom/ns#" term="RavenDB" /><title>RavenDB: first contact</title><content type="html">&lt;p&gt;We have seen how to &lt;a href="http://mauroservienti.blogspot.com/2012/01/ravendb-start-your-engines.html" target="_blank"&gt;setup the development&lt;/a&gt; environment to use &lt;a href="http://ravendb.net/" target="_blank"&gt;RavenDB&lt;/a&gt;, obviously the next step is to try to use our brand new environment.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://nuget.org" target="_blank"&gt;&lt;strong&gt;NuGet&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; to the rescue&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;First of all let’s setup the Visual Studio project to use RavenDB, using nuget as simple as adding a package reference to the RavenDB nuget package:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/-VKAlD5cX7x4/TyqPGZmftTI/AAAAAAAAArw/8GvT_jhm1MI/s1600-h/image3.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/-lt7eeU6XANM/TyqPG-X-CNI/AAAAAAAAAr4/0rYXTkvpo2Y/image_thumb1.png?imgmax=800" width="306" height="69" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Figure: nuget installation dialog&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;the package installation downloads all the required dependencies and setup the application configuration file with the required connection string, that obviously must be adapted to your environment:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/-aKaemUvnWYg/TyqPH63b1eI/AAAAAAAAAr8/AKsht-munR8/s1600-h/image19.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/--WAAVPwU3Gc/TyqPIT_EJiI/AAAAAAAAAsE/nJDkFzMjAD0/image_thumb9.png?imgmax=800" width="310" height="50" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Figure: the application configuration file customized for my environment, where RavenDB server listen on port 81&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;The basics&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;RavenDB has 2 main building block that must be understood in order to manage all the features, having had previous experience with NHibernate can help in this area because the RavenDB API has been designed to help ORM users to migrate and stay in well known environment.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;IDocumentStore&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;The IDocumentStore interface is the counterpart, for ORM users, of the NHibernate ISessionFactory there should (we’ll see in future posts why “should” and not &lt;em&gt;must&lt;/em&gt;) be one document store per each RavenDB server we need to access.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/-ioK0NHYW7YM/TyqPI33o8BI/AAAAAAAAAsQ/Z-6I4oCxtQE/s1600-h/image11.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/-GfLHVY2_qqM/TyqPJ-lm6jI/AAAAAAAAAsY/HUeJQW6fcVw/image_thumb5.png?imgmax=800" width="262" height="120" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Figure: the creation and initialization of the document store&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;the document store has several properties that we can use to customize the behavior of the connection, the security and the behavior of the store itself.&lt;/p&gt;  &lt;p&gt;The only really required thing to do is to initialize, once, the store calling the quite obvious “Initialize” method.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;IDocumentSession&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;the document session interface, that mimics the NHibernate ISession behaviors, is the entry point to access data stored on a RavenDB server instance. The document session is also our “Unit Of Work” implementation that let us manage business transactions against the server.&lt;/p&gt;  &lt;p&gt;Connection to a database is as easy as:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/-B89DzITVAQE/TyqPKrSrOVI/AAAAAAAAAsc/munvnbHz1Ig/s1600-h/image15.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/-RAipPP58bNE/TyqPLLHpl6I/AAAAAAAAAsk/iFRtoCVIcV0/image_thumb7.png?imgmax=800" width="266" height="54" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Figure: the creation of a document session&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;where “myMusic” is the name of the database where I created the sample data, if we do not specify the database name the connection will be made against the default database (that always exists) or against the default database specified before the document store initialization using the DefaultDatabase property (we can also specify the default database in the connection string.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;So far so good…so what?&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;…let’s try to pick some data…just try:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/-8RrZ6kEngK8/TyqPMu1V7WI/AAAAAAAAAsw/7VIlQcbGS6Q/s1600-h/image23.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/-QjwCpFE1rrk/TyqPOiDxBSI/AAAAAAAAAs4/e8jRa_BaAT8/image_thumb11.png?imgmax=800" width="311" height="151" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Figure: some data retrieved in a rather funky way&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;Cool! what’s going on? we have done a really strange thing we have used the generic Query method, closed against a .net 4.0 &lt;em&gt;dynamic&lt;/em&gt; type, asking for the first 10 items…and we received back 10 items…not so expected as it can seem at a first look.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;A little digression…little, trust me…&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;In order to figure out what has happened when the above query has been executed we need to understand how data (document) are stored in a document database.&lt;/p&gt;  &lt;p&gt;No tables here guys &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://lh3.ggpht.com/-M3SYJsqGyts/TyqPPSkfz7I/AAAAAAAAAtA/gMTj3heR2VA/wlEmoticon-smile%25255B2%25255D.png?imgmax=800" /&gt;, the above linq query can be compared to the following, invalid, T-SQL statement:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;select top 10 *     &lt;br /&gt;go&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;That obviously has no meaning in a relational world because lacks, al least, the “from &amp;lt;&lt;em&gt;table-name&lt;/em&gt;&amp;gt;” clause. Document databases has the concept of collection that represents an homogeneous subset of data and in RavenDB the subset you want to query over is expressed by the .net generic type you choose for the Query method (it is not really true, but for the moment it’s good enough).&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Let’s move on&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;If we take a look at the database using the Raven Management Studio we can see that there are 2 different collections: Albums and Genres.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/-IXf0VSMZD0Y/TyqPQ50He6I/AAAAAAAAAtI/0vD-cRn47v8/s1600-h/image%25255B3%25255D.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/-Mbq7r6gAI1A/TyqPSIsXz0I/AAAAAAAAAtQ/yjzsWCf4oTM/image_thumb.png?imgmax=800" width="244" height="77" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Figure: collection contained in the database&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;Which is the easiest method to tell to the document session that we want to query the albums collection? remember easiest.&lt;/p&gt;  &lt;p&gt;Just define an Album type with the same shape of the json document stored in the database&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/-SK5tJNpKERk/TyqPS2NNA0I/AAAAAAAAAtY/Ordy4algwcM/s1600-h/image%25255B15%25255D.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/-x0DzTEV1qgw/TyqPUTL-IFI/AAAAAAAAAtg/Wazfrpz8KWI/image_thumb%25255B6%25255D.png?imgmax=800" width="300" height="169" /&gt;&lt;/a&gt;&lt;a href="http://lh5.ggpht.com/-L6645H5CHX0/TyqPVRiFXXI/AAAAAAAAAto/5mNd0WFv72Y/s1600-h/image%25255B16%25255D.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/-xFL-NdEkzSE/TyqPWGmtYwI/AAAAAAAAAts/BR7c9kJtAiI/image_thumb%25255B7%25255D.png?imgmax=800" width="214" height="169" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Figures: on the left side the Album type definition on the right side the json document that represents an album in the database&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;As you can see we have defined even complex types (AlbumGenre and AlbumArtist, we’ll have future posts to detail the concept of “relation”) that will be automatically mapped to the corresponding nested properties in the json document. One thing you may already have noticed is that the json document is the serialized version of the .net type.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Query&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;if we rewrite the above query using the Album type we fetch exactly 10 albums:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/-OiVMMvIAaiI/TyqPWo1ttMI/AAAAAAAAAt0/-OYcWNKStqk/s1600-h/image%25255B21%25255D.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/-FpYNZx6x80U/TyqPXIiW7PI/AAAAAAAAAt8/QFgskSp8Mss/image_thumb%25255B10%25255D.png?imgmax=800" width="409" height="139" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Figure: RavenDB query executed to retrieve 10 albums from the database&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;wundershon&lt;/em&gt; &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://lh3.ggpht.com/-M3SYJsqGyts/TyqPPSkfz7I/AAAAAAAAAtA/gMTj3heR2VA/wlEmoticon-smile%25255B2%25255D.png?imgmax=800" /&gt;…but how can RavenDB “map” &lt;strong&gt;our &lt;/strong&gt;.net type to its own internal representation? using one of the thousands of cool features that this database have: metadata.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/-9adDwbheY2w/TyqPXnwPsQI/AAAAAAAAAuE/YxMkP_9cSb8/s1600-h/image%25255B26%25255D.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/-sC8EsjDQOrw/TyqPYUMxFwI/AAAAAAAAAuM/Tt3teB1pBIw/image_thumb%25255B13%25255D.png?imgmax=800" width="244" height="113" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Figure: the same document showing the metadata tab in the management studio.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;each document has a set of extensible metadata attached to it and the important one in this case is the Raven-Entity-Name, the database engine utilizes a set of conventions to translate a .net type name to the so called “Raven tag name”:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/-LR9xtbLwvR4/TyqPYnyaOQI/AAAAAAAAAuY/lGffyUBLOyI/s1600-h/image%25255B31%25255D.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/-MFHK6b8geNU/TyqPZeThUYI/AAAAAAAAAuc/INpCnsD3G0s/image_thumb%25255B16%25255D.png?imgmax=800" width="421" height="67" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Figure: using document store conventions to map .net type name to Raven tag name.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;Enough for this post…next time is time for “storing data” &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://lh3.ggpht.com/-M3SYJsqGyts/TyqPPSkfz7I/AAAAAAAAAtA/gMTj3heR2VA/wlEmoticon-smile%25255B2%25255D.png?imgmax=800" /&gt;&lt;/p&gt;  &lt;p&gt;.m&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6511237790974218081-2213690819690820923?l=mauroservienti.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/TXg_vk53AGnI6AV4D-gTrmfFLu4/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/TXg_vk53AGnI6AV4D-gTrmfFLu4/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/TXg_vk53AGnI6AV4D-gTrmfFLu4/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/TXg_vk53AGnI6AV4D-gTrmfFLu4/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/tpx/~4/CElenL6yjw0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mauroservienti.blogspot.com/feeds/2213690819690820923/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://mauroservienti.blogspot.com/2012/02/ravendb-first-contact.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/2213690819690820923?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/2213690819690820923?v=2" /><link rel="alternate" type="text/html" href="http://mauroservienti.blogspot.com/2012/02/ravendb-first-contact.html" title="RavenDB: first contact" /><author><name>Mauro Servienti</name><uri>http://www.blogger.com/profile/10629055661352952427</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="23" height="32" src="http://3.bp.blogspot.com/-dm7TXYKMYyw/Tx6n9k3EMZI/AAAAAAAAAII/dqd_n1UdKsI/s220/Avatar.JPG" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh4.ggpht.com/-lt7eeU6XANM/TyqPG-X-CNI/AAAAAAAAAr4/0rYXTkvpo2Y/s72-c/image_thumb1.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;D0EERXo5cSp7ImA9WhRbEE8.&quot;"><id>tag:blogger.com,1999:blog-6511237790974218081.post-7949070944698359561</id><published>2012-01-31T17:00:00.000+01:00</published><updated>2012-01-31T17:00:04.429+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-31T17:00:04.429+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Software Mason" /><category scheme="http://www.blogger.com/atom/ns#" term="Lean" /><category scheme="http://www.blogger.com/atom/ns#" term="Kanban" /><title>it works (period)</title><content type="html">&lt;p&gt;&lt;strong&gt;2 years ago…&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;I wrote, speaking about task boards (concrete board):&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/-S6Sopowkjns/TyfptgUaLoI/AAAAAAAAAXo/ita1oNz3g2A/s1600-h/IMAGE_017_22.jpg"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="IMAGE_017_2" border="0" alt="IMAGE_017_2" src="http://lh5.ggpht.com/-Q0bzZn5c4Pk/TyfpuM-p-dI/AAAAAAAAAXs/ZWiXTH1jVgw/IMAGE_017_2_thumb.jpg?imgmax=800" width="244" height="184" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Interaction with a concrete panel, directly accessible by the customer has a great collateral effect:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;our client says: I would love to have also this small feature…it’s a cheap change for you guys (WTF…I can say if it’s cheap or not…not you…&lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://lh3.ggpht.com/-Sg9hd49Nnm4/TyfpugfxVsI/AAAAAAAAAX0/qKuniCGgttA/wlEmoticon-smile2.png?imgmax=800" /&gt;)       &lt;ul&gt;       &lt;li&gt;immediately a story takes its own place on the board; &lt;/li&gt;        &lt;li&gt;the “traffic” on the panel increases; &lt;/li&gt;        &lt;li&gt;our client directly perceives that stuff to do has increased, increased proportionally to each request; &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;The rate of questions like “which is the state of the art?” has dramatically dropped; &lt;/li&gt;    &lt;li&gt;The client think a lot, looking at the board, before asking for a change request; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;These only to say that online tools a really cool, but being able to physically touch the backlog has its own pros.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;2 years later…&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Today I can state that it works &amp;lt;cit.&amp;gt;, the board is not the same (from the design point of view) now it’s much more a Kanban board, than a Scrum one, with WIP limits determined by column sizes:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/-6Mo1n59P7w4/TyfpvOcM3YI/AAAAAAAAAX8/QtQU0_g_J78/s1600-h/WP_0000593.jpg"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="WP_000059" border="0" alt="WP_000059" src="http://lh5.ggpht.com/-8Cie24QVJhU/Tyfpv-BqIZI/AAAAAAAAAYE/Kue_iBByB5w/WP_000059_thumb.jpg?imgmax=800" width="244" height="184" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;the effect is the same, and my PM only asks me “how you doing” in front of the coffee machine just to know how the weekend has gone and not to know how the project is growing &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smilewithtongueout" alt="Smile with tongue out" src="http://lh6.ggpht.com/-dpYO5cMSFE4/TyfpwOmCc-I/AAAAAAAAAYM/q6TECkvb5Hc/wlEmoticon-smilewithtongueout2.png?imgmax=800" /&gt;&lt;/p&gt;  &lt;p&gt;.m&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6511237790974218081-7949070944698359561?l=mauroservienti.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/ptNVhhy12hRTkp9jwsp8HJ3kvog/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ptNVhhy12hRTkp9jwsp8HJ3kvog/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/ptNVhhy12hRTkp9jwsp8HJ3kvog/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ptNVhhy12hRTkp9jwsp8HJ3kvog/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/tpx/~4/1Sy24UUoP5g" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mauroservienti.blogspot.com/feeds/7949070944698359561/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://mauroservienti.blogspot.com/2012/01/it-works-period.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/7949070944698359561?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/7949070944698359561?v=2" /><link rel="alternate" type="text/html" href="http://mauroservienti.blogspot.com/2012/01/it-works-period.html" title="it works (period)" /><author><name>Mauro Servienti</name><uri>http://www.blogger.com/profile/10629055661352952427</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="23" height="32" src="http://3.bp.blogspot.com/-dm7TXYKMYyw/Tx6n9k3EMZI/AAAAAAAAAII/dqd_n1UdKsI/s220/Avatar.JPG" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh5.ggpht.com/-Q0bzZn5c4Pk/TyfpuM-p-dI/AAAAAAAAAXs/ZWiXTH1jVgw/s72-c/IMAGE_017_2_thumb.jpg?imgmax=800" height="72" width="72" /><thr:total>2</thr:total></entry><entry gd:etag="W/&quot;DUIFQHwzcCp7ImA9WhRUFko.&quot;"><id>tag:blogger.com,1999:blog-6511237790974218081.post-4557154333131894128</id><published>2012-01-27T16:18:00.001+01:00</published><updated>2012-01-27T16:18:31.288+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-27T16:18:31.288+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Software Mason" /><category scheme="http://www.blogger.com/atom/ns#" term="RavenDB" /><title>RavenDB: start your engines</title><content type="html">&lt;p&gt;This post is intended to be an introduction to &lt;a href="http://ravendb.net/" target="_blank"&gt;RavenDB&lt;/a&gt; and as all the introduction will deal with the basic steps required to setup the development machine.&lt;/p&gt;  &lt;p&gt;The first step is to download the RavenDB binaries from the RavenDB site: &lt;a href="http://ravendb.net/download#builds"&gt;http://ravendb.net/download#builds&lt;/a&gt;.     &lt;br /&gt;&lt;em&gt;Once downloaded remember to unblock the compressed archive before extracting files to the hard drive.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;First run&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;After the file extraction the directory structure should be something like the following:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/-778ZsdtXOA0/TyBpxqbb8rI/AAAAAAAAAI0/QVAgiES2L_g/s1600-h/image6.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/-3RbNNgc0ZUg/TyBpyaTL_UI/AAAAAAAAAI8/3sRxmchTNlM/image_thumb4.png?imgmax=800" width="244" height="229" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Figure: file and folder structure from RavenDB build 573.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;There are 2 different server versions (the highlighted folders in the above figure):&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;“Server” folder contains server binaries already setup to run as a console application or as a Windows service; &lt;/li&gt;    &lt;li&gt;“Web” folder contains server binaries setup to run as an IIS hosted application; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;During the development process the console version is a real life saver because it gives real time access to server logs. In order to start the console version it’s enough to jump into the server folder and double click on the Raven.Server.exe file.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/-2F-3XBMvBYw/TyBpzqAyXVI/AAAAAAAAAJA/1gA83tuVU6E/s1600-h/image10.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/-vlxyGeYGh0A/TyBp0CXepzI/AAAAAAAAAJM/I53RrN946tY/image_thumb7.png?imgmax=800" width="205" height="69" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;What happens is that the server starts, the first time it can take some time due to the operation performed to setup the environment fir the first time. Once the server is started the console should look like the following screenshot:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/-Yp05aDPS1g8/TyBp2HaNWQI/AAAAAAAAAJU/a1qKFvySA64/s1600-h/image16.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/-zCtfAZ4tvmo/TyBp3C176qI/AAAAAAAAAJc/3eu4isUr8Jk/image_thumb9.png?imgmax=800" width="244" height="127" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Figure: the console running a RavenDB server instance.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;Side note: you can be presented with the Windows Firewall authorization dialog, as the following:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/-Dv8Wo5sCgOg/TyBp5QsPWhI/AAAAAAAAAJk/QnvsEosmpbc/s1600-h/image13.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/-ft05sXh5AGA/TyBp6W96tWI/AAAAAAAAAJs/w2YHAz9X6nE/image_thumb8.png?imgmax=800" width="244" height="193" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Obviously you need to give appropriate permissions if you need to access your local server from another machine.&lt;/p&gt;  &lt;p&gt;The console immediately gives some important information:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;The data directory where data are stored; &lt;/li&gt;    &lt;li&gt;The server url, host name and listening port; &lt;/li&gt;    &lt;li&gt;The storage engine type, on Windows the default is Esent; &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&lt;strong&gt;And now?&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Once the server is running the first thing we can do is trying to connect using the builtin management studio, the studio is a Silverlight application that can be launched simply pointing the browser to the listening server Uri:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/-vUj-HnD7jGY/TyBp8udl2UI/AAAAAAAAAJ0/1-P9tWz0A-Y/s1600-h/image19.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/-DCGnghUcQCE/TyBp-bsaYuI/AAAAAAAAAJ8/ARBrNwdWRbg/image_thumb10.png?imgmax=800" width="244" height="98" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Figure: the RavenDB management studio running in Chrome.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;Obviously the database, the default database that is created at server startup, is empty. At the bottom of the “summary” page there is a button that starts the creation process of a bunch of sample data. After the creation of the sample data your collections should look something like:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/-fEOdIkfHOEQ/TyBp_2NpfBI/AAAAAAAAAKE/rPy1UvJqyYw/s1600-h/image22.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/-hxF0iV1TaJ0/TyBqAsiuI8I/AAAAAAAAAKM/6xQQ2kkzUwM/image_thumb11.png?imgmax=800" width="244" height="155" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Figure: database collections just after the sample data creation process has completed.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;The server console immediately confirms that something is going on at the server side:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/-n816WFN8Yic/TyBqB_7qizI/AAAAAAAAAKU/L-EQs3gzJhQ/s1600-h/image25.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/-X2q2Eg-Yx2E/TyBqC-cfU2I/AAAAAAAAAKc/QVLXqDxo6zw/image_thumb12.png?imgmax=800" width="244" height="127" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Figure: the RavenDB server console showing real time logs.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Are you “secure”?&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;no…it’s not an Italian false friend, I’m pretty sure &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-winkingsmile" alt="Winking smile" src="http://lh5.ggpht.com/-2DQHXrxSFbI/TyBqDZGj6_I/AAAAAAAAAKg/WJL_Ac2UiVk/wlEmoticon-winkingsmile2.png?imgmax=800" /&gt; One question that some readers could raise is: how can it be that the server let a connected, and apparently anonymous, application to write data?&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Well…&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;The first thing we need to understand is the RavenDB security model: when running in the console mode the default security model is Windows authentication (oAuth is an option too) and the access level, the anonymous access level, can be controlled via the server configuration file:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/-kVVlsuQuluA/TyLAP9stQxI/AAAAAAAAALM/L1wGHhybkOI/s1600-h/image262.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/-4pLPtRqZ68A/TyBqFeFJSuI/AAAAAAAAALU/iZaHkTOggnc/image26_thumb1.png?imgmax=800" width="244" height="109" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Figure: the configuration file showing the Raven/AnonymousAccess configuration setting.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;The anonymous access setting support 3 different values:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;None: anonymous access is not allowed; &lt;/li&gt;    &lt;li&gt;Get: anonymous clients has just read-only permissions; &lt;/li&gt;    &lt;li&gt;All: anonymous clients are full trusted clients and can do everything; &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&lt;strong&gt;So?&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;As we can see the current running value is “Get”, but since the studio is connecting to localhost it is basically running in “intranet” mode and thus is passing the current user credentials to the RavenDB server that, using Windows authentication, can trust the incoming requests: that’s why we could create data even if no one asked us any credential.&lt;/p&gt;  &lt;p&gt;Enough for the moment…next time we’ll see how to connect to the server using our own application. &lt;/p&gt;  &lt;p&gt;.m&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6511237790974218081-4557154333131894128?l=mauroservienti.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Xf0sBNoeOzfQ_QD6Xd_xh8jAnM4/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Xf0sBNoeOzfQ_QD6Xd_xh8jAnM4/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Xf0sBNoeOzfQ_QD6Xd_xh8jAnM4/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Xf0sBNoeOzfQ_QD6Xd_xh8jAnM4/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/tpx/~4/17ZugX46bAo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mauroservienti.blogspot.com/feeds/4557154333131894128/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://mauroservienti.blogspot.com/2012/01/ravendb-start-your-engines.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/4557154333131894128?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/4557154333131894128?v=2" /><link rel="alternate" type="text/html" href="http://mauroservienti.blogspot.com/2012/01/ravendb-start-your-engines.html" title="RavenDB: start your engines" /><author><name>Mauro Servienti</name><uri>http://www.blogger.com/profile/10629055661352952427</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="23" height="32" src="http://3.bp.blogspot.com/-dm7TXYKMYyw/Tx6n9k3EMZI/AAAAAAAAAII/dqd_n1UdKsI/s220/Avatar.JPG" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh5.ggpht.com/-3RbNNgc0ZUg/TyBpyaTL_UI/AAAAAAAAAI8/3sRxmchTNlM/s72-c/image_thumb4.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DE8CR3Y6cSp7ImA9WhRUFUU.&quot;"><id>tag:blogger.com,1999:blog-6511237790974218081.post-273914224122980625</id><published>2012-01-26T15:07:00.001+01:00</published><updated>2012-01-26T15:07:46.819+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-26T15:07:46.819+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Why not..." /><title>This blog is moving…</title><content type="html">&lt;p&gt;it is a requirement! I cannot go on scrounging hosting off &lt;a href="http://www.codewrecks.com/blog/" target="_blank"&gt;Gian Maria&lt;/a&gt; and &lt;a href="http://www.primordialcode.com/" target="_blank"&gt;Alessandro&lt;/a&gt; and at the same time I do not want to pay an hosting plan just to host my own blog, after 3 years I can safely say that it is not sustainable….and since this blog title is “Mauro and the sustainable development”… &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://lh4.ggpht.com/-3dA6_cGpO2g/TyD6Yc2Kf5I/AAAAAAAAAK8/VVThksNoMlE/wlEmoticon-smile%25255B2%25255D.png?imgmax=800" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;So far so good…but what’s happening?&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Well…lot’s of things:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;if you are reading this post means that the &lt;a href="http://feeds.feedburner.com/tpx" target="_blank"&gt;FeedBurner feed&lt;/a&gt; has been successfully updated to point to the new blog: &lt;a href="http://mauroservienti.blogspot.com/"&gt;http://mauroservienti.blogspot.com/&lt;/a&gt;; &lt;/li&gt;    &lt;li&gt;the “old” blog (&lt;a href="http://milestone.topics.it"&gt;http://milestone.topics.it&lt;/a&gt;) is still alive and will be online until the posts migration process has been completed:       &lt;ul&gt;       &lt;li&gt;I’ve written a tool to migrate posts from the old blog to Blogger, but blogger has a post limit (well a sort of) of 50 posts a day, so the migration process will last something like 16 days; &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;at the end of the migration process the old blog address will be redirected here in order to complete the migration; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;This basically means that by the 15 of February I can free some resources of the Gian Maria and Alessandro server &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smilewithtongueout" alt="Smile with tongue out" src="http://lh4.ggpht.com/-90TJHugbBms/TyD6Y-KIw_I/AAAAAAAAALA/qNrUQZbhdWo/wlEmoticon-smilewithtongueout%25255B2%25255D.png?imgmax=800" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Why BlogSpot?&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;There were, when I decided to move a couple of weeks ago, 2 main competitor:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;WordPress; &lt;/li&gt;    &lt;li&gt;BlogSpot; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Both free and with lots of interesting features, really a lot &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://lh4.ggpht.com/-3dA6_cGpO2g/TyD6Yc2Kf5I/AAAAAAAAAK8/VVThksNoMlE/wlEmoticon-smile%25255B2%25255D.png?imgmax=800" /&gt;, but I was looking mainly for 2 features:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Custom domain, I need to point milestone.topics.it to the blog; &lt;/li&gt;    &lt;li&gt;Custom pages: the ability top create “pages” other then posts; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Both the competitors offer these features but the custom domain is a paid feature for WordPress…BlogSpot is the winner…easy &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://lh4.ggpht.com/-3dA6_cGpO2g/TyD6Yc2Kf5I/AAAAAAAAAK8/VVThksNoMlE/wlEmoticon-smile%25255B2%25255D.png?imgmax=800" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;In the End…&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;I’d like to thank:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;First of all &lt;a href="http://imperugo.tostring.it/" target="_blank"&gt;Ugo&lt;/a&gt; for &lt;a href="http://dexterblogengine.codeplex.com/" target="_blank"&gt;Dexter&lt;/a&gt; and the support during these 3 year; &lt;/li&gt;    &lt;li&gt;Gian Maria and Alessandro for the free hosting during the last months; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Thanks guys, I owe you a dinner.&lt;/p&gt;  &lt;p&gt;.m&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6511237790974218081-273914224122980625?l=mauroservienti.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/qB6sypXKnU3rLjjP6CxhClraqKc/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/qB6sypXKnU3rLjjP6CxhClraqKc/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/qB6sypXKnU3rLjjP6CxhClraqKc/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/qB6sypXKnU3rLjjP6CxhClraqKc/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/tpx/~4/BFtCNbz5c60" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mauroservienti.blogspot.com/feeds/273914224122980625/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://mauroservienti.blogspot.com/2012/01/this-blog-is-moving.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/273914224122980625?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/273914224122980625?v=2" /><link rel="alternate" type="text/html" href="http://mauroservienti.blogspot.com/2012/01/this-blog-is-moving.html" title="This blog is moving…" /><author><name>Mauro Servienti</name><uri>http://www.blogger.com/profile/10629055661352952427</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="23" height="32" src="http://3.bp.blogspot.com/-dm7TXYKMYyw/Tx6n9k3EMZI/AAAAAAAAAII/dqd_n1UdKsI/s220/Avatar.JPG" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh4.ggpht.com/-3dA6_cGpO2g/TyD6Yc2Kf5I/AAAAAAAAAK8/VVThksNoMlE/s72-c/wlEmoticon-smile%25255B2%25255D.png?imgmax=800" height="72" width="72" /><thr:total>1</thr:total></entry><entry gd:etag="W/&quot;DEUFR34-eCp7ImA9WhRbF00.&quot;"><id>tag:blogger.com,1999:blog-6511237790974218081.post-2573652220480824185</id><published>2010-01-30T18:21:00.000+01:00</published><updated>2012-02-08T14:03:36.050+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-08T14:03:36.050+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Why not..." /><title>DotNetMarche: Spettacolo!</title><content type="html">&lt;span&gt;volevo ringraziare tutti, ma proprio tutti i partecipanti al &lt;a href="http://dotnetmarche.org/eventi/Default.aspx?IDevento=33" target="_blank"&gt;Workshop di ieri&lt;/a&gt; organizzato da &lt;a href="http://dotnetmarche.org/" target="_blank"&gt;DotNetMarche&lt;/a&gt;.&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Giornata perfetta e serata perfettissima: il porco ha fatto la sua porca figura! :-), un grazie particolare a &lt;a href="http://www.codewrecks.com/blog/" target="_blank"&gt;Gian Maria&lt;/a&gt; per l’ospitalità e lo scarrozzamento.&lt;/span&gt;&lt;br&gt;  &lt;span&gt;.m&lt;/span&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6511237790974218081-2573652220480824185?l=mauroservienti.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/l_XxwCqLdMhD7Ma1H5D1WrobV_A/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/l_XxwCqLdMhD7Ma1H5D1WrobV_A/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/l_XxwCqLdMhD7Ma1H5D1WrobV_A/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/l_XxwCqLdMhD7Ma1H5D1WrobV_A/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/tpx/~4/1Wu-L37mQlo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mauroservienti.blogspot.com/feeds/2573652220480824185/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/dotnetmarche-spettacolo.html#comment-form" title="7 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/2573652220480824185?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/2573652220480824185?v=2" /><link rel="alternate" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/dotnetmarche-spettacolo.html" title="DotNetMarche: Spettacolo!" /><author><name>Mauro Servienti</name><uri>http://www.blogger.com/profile/10629055661352952427</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="23" height="32" src="http://3.bp.blogspot.com/-dm7TXYKMYyw/Tx6n9k3EMZI/AAAAAAAAAII/dqd_n1UdKsI/s220/Avatar.JPG" /></author><thr:total>7</thr:total></entry><entry gd:etag="W/&quot;DEUFRHsyfip7ImA9WhRbF00.&quot;"><id>tag:blogger.com,1999:blog-6511237790974218081.post-4994231036738999946</id><published>2010-01-30T12:39:00.000+01:00</published><updated>2012-02-08T14:03:35.596+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-08T14:03:35.596+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="WPF" /><category scheme="http://www.blogger.com/atom/ns#" term="Software Mason" /><category scheme="http://www.blogger.com/atom/ns#" term="Markup Extension" /><category scheme="http://www.blogger.com/atom/ns#" term="Binding" /><title>CommandBinding: MarkupExtension</title><content type="html">&lt;span&gt;Estendere il motore di DataBinding, a oggi, è impossibile perchè è tutto &lt;em&gt;internal&lt;/em&gt; e/o &lt;em&gt;sealed&lt;/em&gt;… immagino abbiano avuto i loro buoni motivi e posso immaginare anche quali siano, sta di fatto che è una gran menata…&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Possiamo però partire da &lt;a href="http://www.hardcodet.net/2008/04/wpf-custom-binding-class" target="_blank"&gt;questo post&lt;/a&gt;, come suggerito da &lt;a href="http://blogs.ugidotnet.org/spaccabit" target="_blank"&gt;Giuseppe&lt;/a&gt;, e wrappare la classe Binding in una nostra classe Binding esponendo le stesse identitche proprietà che saranno dei meri proxy verso la classe Binding reale; facendo infine semplicemente questo:&lt;/span&gt;&lt;br&gt;  &lt;blockquote&gt;   &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public override object &lt;/span&gt;ProvideValue( &lt;span style="color: #2b91af"&gt;IServiceProvider &lt;/span&gt;provider )
{
    &lt;span style="color: blue"&gt;return &lt;/span&gt;binding.ProvideValue( provider );
}&lt;/pre&gt;
  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/blockquote&gt;

&lt;span&gt;Nel momento in cui la nostra markup extension viene effettivamente invocata l’unica cosa che possiamo fare è passare la palla alla vera markup extension con cui Wpf è in grado di interagire.&lt;/span&gt;&lt;br&gt;

&lt;span&gt;Ma non è ancora tutto perso… se usiamo M-V-VM siamo probabilmente molto avvezzi al concetto di DelegateCommand/RelayCommand e alla possibilità di scrivere una cosa di questo genere:&lt;/span&gt;&lt;br&gt;

&lt;blockquote&gt;
  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;command = &lt;span style="color: #2b91af"&gt;DelegateCommand&lt;/span&gt;.Create()
    .AddKeyGesture(
            System.Windows.Input.&lt;span style="color: #2b91af"&gt;Key&lt;/span&gt;.S,
            System.Windows.Input.&lt;span style="color: #2b91af"&gt;ModifierKeys&lt;/span&gt;.Control )
    .OnExecute( o =&gt; { &lt;span style="color: green"&gt;/* execution logic */ &lt;/span&gt;} );&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;span&gt;con lo scopo di creare un ICommand a cui sia implicitamente associata la combinazione Ctrl+S peccato che quella cosa non funzioni perchè nessuno (aka la classe Binding) si preoccupa di eseguire la registrazione degli Input Bindings…&lt;/span&gt;&lt;br&gt;

&lt;span&gt;Sfruttando quindi la nostra bella markup extension perchè non realizzare qualcosa del genere:&lt;/span&gt;&lt;br&gt;

&lt;blockquote&gt;
  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;CommandBinding &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;BindingDecoratorBase
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;public override object &lt;/span&gt;ProvideValue( &lt;span style="color: #2b91af"&gt;IServiceProvider &lt;/span&gt;provider )
    {
        &lt;span style="color: blue"&gt;var &lt;/span&gt;b = &lt;span style="color: blue"&gt;base&lt;/span&gt;.ProvideValue( provider );
        &lt;span style="color: blue"&gt;this&lt;/span&gt;.OnProvideValue( provider, b );
        &lt;span style="color: blue"&gt;return &lt;/span&gt;b;
    }

    &lt;span style="color: blue"&gt;protected virtual void &lt;/span&gt;OnProvideValue( &lt;span style="color: #2b91af"&gt;IServiceProvider &lt;/span&gt;provider, &lt;span style="color: #2b91af"&gt;Object &lt;/span&gt;value )
    {
        &lt;span style="color: #2b91af"&gt;FrameworkElement &lt;/span&gt;fe;
        &lt;span style="color: #2b91af"&gt;DependencyProperty &lt;/span&gt;dp;

        &lt;span style="color: blue"&gt;if&lt;/span&gt;( &lt;span style="color: blue"&gt;this&lt;/span&gt;.TryGetTargetItems&lt;&lt;span style="color: #2b91af"&gt;FrameworkElement&lt;/span&gt;&gt;( provider, &lt;span style="color: blue"&gt;out &lt;/span&gt;fe, &lt;span style="color: blue"&gt;out &lt;/span&gt;dp ) )
        {
            &lt;span style="color: #2b91af"&gt;RoutedEventHandler &lt;/span&gt;reh = &lt;span style="color: blue"&gt;null&lt;/span&gt;;
            reh = ( s, e ) =&gt;
            {
                fe.Loaded -= reh;
                &lt;span style="color: blue"&gt;this&lt;/span&gt;.OnTargetLoaded( fe, dp );
            };
            fe.Loaded += reh;
        }
        &lt;span style="color: blue"&gt;else
        &lt;/span&gt;{
            &lt;span style="color: #2b91af"&gt;FrameworkContentElement &lt;/span&gt;fce;
            &lt;span style="color: blue"&gt;if&lt;/span&gt;( &lt;span style="color: blue"&gt;this&lt;/span&gt;.TryGetTargetItems&lt;&lt;span style="color: #2b91af"&gt;FrameworkContentElement&lt;/span&gt;&gt;( provider, &lt;span style="color: blue"&gt;out &lt;/span&gt;fce, &lt;span style="color: blue"&gt;out &lt;/span&gt;dp ) )
            {
                &lt;span style="color: #2b91af"&gt;RoutedEventHandler &lt;/span&gt;reh = &lt;span style="color: blue"&gt;null&lt;/span&gt;;
                reh = ( s, e ) =&gt;
                {
                    fce.Loaded -= reh;
                    &lt;span style="color: blue"&gt;this&lt;/span&gt;.OnTargetLoaded( fce, dp );
                };
                fce.Loaded += reh;
            }
        }
    }&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;span&gt;Con &lt;em&gt;TryGetTargetItems&lt;/em&gt; definita così:&lt;/span&gt;&lt;br&gt;

&lt;blockquote&gt;
  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;protected virtual bool &lt;/span&gt;TryGetTargetItems&lt;T&gt;( &lt;span style="color: #2b91af"&gt;IServiceProvider &lt;/span&gt;provider, &lt;span style="color: blue"&gt;out &lt;/span&gt;T target, &lt;span style="color: blue"&gt;out &lt;/span&gt;&lt;span style="color: #2b91af"&gt;DependencyProperty &lt;/span&gt;dp )
    &lt;span style="color: blue"&gt;where &lt;/span&gt;T : &lt;span style="color: #2b91af"&gt;DependencyObject
&lt;/span&gt;{
    target = &lt;span style="color: blue"&gt;null&lt;/span&gt;;
    dp = &lt;span style="color: blue"&gt;null&lt;/span&gt;;
    &lt;span style="color: blue"&gt;if&lt;/span&gt;( provider == &lt;span style="color: blue"&gt;null &lt;/span&gt;) &lt;span style="color: blue"&gt;return false&lt;/span&gt;;

    &lt;span style="color: blue"&gt;var &lt;/span&gt;service = provider.GetService( &lt;span style="color: blue"&gt;typeof&lt;/span&gt;( &lt;span style="color: #2b91af"&gt;IProvideValueTarget &lt;/span&gt;) ) &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IProvideValueTarget&lt;/span&gt;;
    &lt;span style="color: blue"&gt;if&lt;/span&gt;( service == &lt;span style="color: blue"&gt;null &lt;/span&gt;) &lt;span style="color: blue"&gt;return false&lt;/span&gt;;

    target = service.TargetObject &lt;span style="color: blue"&gt;as &lt;/span&gt;T;
    dp = service.TargetProperty &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;DependencyProperty&lt;/span&gt;;
    &lt;span style="color: blue"&gt;return &lt;/span&gt;target != &lt;span style="color: blue"&gt;null &lt;/span&gt;&amp;&amp; dp != &lt;span style="color: blue"&gt;null&lt;/span&gt;;
}&lt;/pre&gt;
  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/blockquote&gt;

&lt;span&gt;Abbiamo la necessità di sapere quando il target del Binding è “Loaded”, tracciamo sia FrameworkElement (eg Button) che FrameworkContentElement (eg Hyperlink) perchè purtroppo (&lt;grrr…&gt;) non hanno lo stesso ancestor e quindi hanno 2 eventi Loaded diversi… poco male, basta saperlo.&lt;/span&gt;&lt;br&gt;

&lt;pre class="code"&gt;    &lt;span style="color: blue"&gt;protected virtual void &lt;/span&gt;OnTargetLoaded( &lt;span style="color: #2b91af"&gt;DependencyObject &lt;/span&gt;target, &lt;span style="color: #2b91af"&gt;DependencyProperty &lt;/span&gt;targetProperty )
    {
        &lt;span style="color: blue"&gt;var &lt;/span&gt;source = target &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ICommandSource&lt;/span&gt;;
        &lt;span style="color: blue"&gt;var &lt;/span&gt;command = &lt;span style="color: blue"&gt;this&lt;/span&gt;.GetCommand( target, targetProperty );
        &lt;span style="color: blue"&gt;this&lt;/span&gt;.SetInputBindings( target, source, command );
    }&lt;/pre&gt;

&lt;span&gt;A questo punto quando il target è Loaded ci limitiamo ad estrarre dalla DepenedencyProperty (omesso per brevità) il valore dell’ICommand e non facciamo altro che impostare gli imput bindings sul root element, anche qui la funzione ricorsiva che va alla ricerca del root element è omessa:&lt;/span&gt;&lt;br&gt;

&lt;blockquote&gt;
  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;protected virtual void &lt;/span&gt;SetInputBindings( &lt;span style="color: #2b91af"&gt;DependencyObject &lt;/span&gt;target, &lt;span style="color: #2b91af"&gt;ICommandSource &lt;/span&gt;source, &lt;span style="color: #2b91af"&gt;IBindableCommand &lt;/span&gt;command)
{
    &lt;span style="color: blue"&gt;if&lt;/span&gt;( source != &lt;span style="color: blue"&gt;null &lt;/span&gt;&amp;&amp; command != &lt;span style="color: blue"&gt;null &lt;/span&gt;&amp;&amp; command.InputBindings != &lt;span style="color: blue"&gt;null &lt;/span&gt;)
    {
        &lt;span style="color: blue"&gt;var &lt;/span&gt;rootElement = &lt;span style="color: blue"&gt;this&lt;/span&gt;.GetRootElement( target &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;FrameworkElement &lt;/span&gt;);
        &lt;span style="color: blue"&gt;foreach&lt;/span&gt;( &lt;span style="color: #2b91af"&gt;InputBinding &lt;/span&gt;ib &lt;span style="color: blue"&gt;in &lt;/span&gt;command.InputBindings )
        {
            &lt;span style="color: blue"&gt;if&lt;/span&gt;( ib.CommandParameter != source.CommandParameter )
            {
                ib.CommandParameter = source.CommandParameter;
            }

            rootElement.InputBindings.Add( ib );
        }
    }
}&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;span&gt;Togo, adesso lo possiamo usare così:&lt;/span&gt;&lt;br&gt;

&lt;blockquote&gt;
  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;Button &lt;/span&gt;&lt;span style="color: red"&gt;Height&lt;/span&gt;&lt;span style="color: blue"&gt;="23" &lt;/span&gt;&lt;span style="color: red"&gt;Command&lt;/span&gt;&lt;span style="color: blue"&gt;="{&lt;/span&gt;&lt;span style="color: #a31515"&gt;cmd&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;CommandBinding &lt;/span&gt;&lt;span style="color: red"&gt;Path&lt;/span&gt;&lt;span style="color: blue"&gt;=ExecuteSampleCommand}" /&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;span&gt;Ottenendo gratis la registrazione degli input bindings.&lt;/span&gt;&lt;br&gt;

&lt;span&gt;&lt;em&gt;Ma non è finita… Stay tuned!&lt;/em&gt;&lt;/span&gt;&lt;br&gt;

&lt;span&gt;.m&lt;/span&gt;&lt;br&gt;

&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6511237790974218081-4994231036738999946?l=mauroservienti.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/iHtc-MDd-E4vU5T5io9Qmi241ag/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/iHtc-MDd-E4vU5T5io9Qmi241ag/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/iHtc-MDd-E4vU5T5io9Qmi241ag/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/iHtc-MDd-E4vU5T5io9Qmi241ag/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/tpx/~4/YlB7yf-YRiQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mauroservienti.blogspot.com/feeds/4994231036738999946/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/commandbinding-markupextension.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/4994231036738999946?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/4994231036738999946?v=2" /><link rel="alternate" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/commandbinding-markupextension.html" title="CommandBinding: MarkupExtension" /><author><name>Mauro Servienti</name><uri>http://www.blogger.com/profile/10629055661352952427</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="23" height="32" src="http://3.bp.blogspot.com/-dm7TXYKMYyw/Tx6n9k3EMZI/AAAAAAAAAII/dqd_n1UdKsI/s220/Avatar.JPG" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DEUFRXsycCp7ImA9WhRbF00.&quot;"><id>tag:blogger.com,1999:blog-6511237790974218081.post-4994295890616323522</id><published>2010-01-28T06:31:00.000+01:00</published><updated>2012-02-08T14:03:34.598+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-08T14:03:34.598+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="User Experience" /><category scheme="http://www.blogger.com/atom/ns#" term="WPF" /><category scheme="http://www.blogger.com/atom/ns#" term="Behavior" /><title>UserExperience: ma quanto mi costi?</title><content type="html">&lt;span&gt;Wpf mi ha catapultato in un mondo affascinante e che conosco poco, il mondo della User Experience, la cosa bella è che da &lt;a href="https://www.blogger.com/feeds/6511237790974218081/posts/default/4973415113868715536" target="_blank"&gt;lunedì&lt;/a&gt; verrò assorbito e avvolto totalmente da questo mondo in quanto uno dei principali focus di &lt;a href="http://www.gaia.is.it" target="_blank"&gt;Gaia&lt;/a&gt;.&lt;/span&gt;&lt;br&gt;  &lt;span&gt;L’esperienza di questi ultimi mesi però mi ha fatto rivalutare la scala dei “costi” dello sviluppo mettendo ampiamente in testa alla classifica della cosa più onerosa proprio una User Experience di qualità.&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Wpf in questa direzione aiuta veramente tanto perchè se penso alle stesse cose fatte con Windows Forms decisamente meglio un carciofo nel… ;-)&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Giusto per capirci, ne parleremo parecchio, osservate gli esempi qui di seguito:&lt;/span&gt;&lt;br&gt;  &lt;span&gt;&lt;a href="https://lh3.googleusercontent.com/-xFJws0IBt1I/TzJylpZaLkI/AAAAAAAABJM/N3GdGbr833E/f9c77d19-1034-42cd-b887-4d2553f5a71e.png" rel="shadowbox"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="https://lh3.googleusercontent.com/-CoIJEWdm8jc/TzJylC4EONI/AAAAAAAABJI/fa7Dufj-CtI/5b8803a9-b7ae-4366-bcb6-60791ec9afa2.png" width="192" height="124"&gt;&lt;/a&gt; &lt;a href="https://lh6.googleusercontent.com/-MWqt7G3lcaw/TzJynN-zdpI/AAAAAAAABJg/GSVj9WxtpqE/6f7d0e1f-a073-4c6f-b53b-33fe986373f3.png" rel="shadowbox"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="https://lh6.googleusercontent.com/-9pn-4ZZKUSU/TzJymGZjsSI/AAAAAAAABJU/WWfz37K2idE/de007905-3247-464c-833b-cbfd0e26d842.png" width="192" height="124"&gt;&lt;/a&gt; &lt;/span&gt;&lt;br&gt;  &lt;ul&gt;   &lt;li&gt;Sono un wizard, e anche se io odio tanto gli wizard, per l’utente finale sono veramente la manna in termini di semplificazione del processo e di focus sulle cose importanti, ma… passare da uno singolo “screen” ad uno wizard comporta come minimo un po’ di problemi nella gestione della validazione che passa da globale a &lt;em&gt;scoped&lt;/em&gt; alla pagina che l’utente sta guardando; e non è proprio un’operazione semplice;&lt;/li&gt;    &lt;li&gt;Ma non solo, anche un wizard ha i suoi problemi, la prima versione che ho rilasciato era “bloccante” (vedi lo screenshot di sinistra) era quindi impossibile passare alla pagina successiva se quella corrente era in uno stato invalido. Questo però comporta un problema per l’utilizzatore… &lt;em&gt;&lt;u&gt;mancanza di feedback&lt;/u&gt;&lt;/em&gt;:&lt;/li&gt;    &lt;ul&gt;     &lt;li&gt;l’utente arriva sulla pagina in questione;&lt;/li&gt;      &lt;li&gt;il pulsante “Avanti” è disabilitato perchè la pagina non è valida;&lt;/li&gt;      &lt;li&gt;ma l’utente non capisce perchè, ed essendo “Avanti” disabilitato non ha nessun mezzo per triggerare la validazione;&lt;/li&gt;   &lt;/ul&gt;    &lt;li&gt;In termini di UX la seconda soluzione è sicuramente migliore, anche se complica parecchio le cose:&lt;/li&gt;    &lt;ul&gt;     &lt;li&gt;Il pulsante “Avanti” è sempre attivo;&lt;/li&gt;      &lt;li&gt;la prima volta che si arriva sulla pagina non ci sono errori;&lt;/li&gt;      &lt;li&gt;se si pigia il pulsante avanti e la pagina non è valida:&lt;/li&gt;      &lt;ul&gt;       &lt;li&gt;il cambio pagina viene bloccato;&lt;/li&gt;        &lt;li&gt;la validazione viene &lt;em&gt;triggherata&lt;/em&gt;;&lt;/li&gt;        &lt;li&gt;i controlli non validi vengono evidenziati (e questo con M-V-VM e IDataErrorInfo è abbastanza un delirio);&lt;/li&gt;     &lt;/ul&gt;      &lt;li&gt;Oppure ci sono situazioni in cui potrebbe aver senso lasciare che l’utente prosegua nel processo e abbia, oltre alla validazione contestuale, un riepilogo degli errori in ultima “pagina”;&lt;/li&gt;   &lt;/ul&gt; &lt;/ul&gt;  &lt;span&gt;Giusto per capire perchè Wpf in questo senso è la manna, per fare tutto quello di cui sopra il designer si deve limitare ad utilizzare (e configurare) un &lt;em&gt;Behavior&lt;/em&gt;:&lt;/span&gt;&lt;br&gt;  &lt;span&gt;&lt;a href="https://lh6.googleusercontent.com/-H_j347jN6dU/TzJypIbjJxI/AAAAAAAABJs/dH9vqxNYMJg/fe4de2ea-8ffb-422f-810e-d111eacbd7c9.png" rel="shadowbox"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="https://lh6.googleusercontent.com/-utYM-iFfkGw/TzJyoHVbGgI/AAAAAAAABJo/T8AqmrlnzAo/2778266f-a8fb-40f9-9b58-41c4c5571280.png" width="322" height="84"&gt;&lt;/a&gt;&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Spettacolo! &lt;/span&gt;&lt;br&gt;  &lt;span&gt;.m&lt;/span&gt;&lt;br&gt;  &lt;blockquote&gt;   &lt;span&gt;&lt;em&gt;n.d.r.&lt;/em&gt;: Il controllo Wizard è gentilmente offerto da: &lt;a href="http://www.divelements.com/net/controls/wizardframeworkwpf/" target="_blank"&gt;divelements.com&lt;/a&gt;.&lt;/span&gt;&lt;br&gt; &lt;/blockquote&gt;        &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6511237790974218081-4994295890616323522?l=mauroservienti.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/J8YQgraZnrB1xXN8U0kJWyLFZpk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/J8YQgraZnrB1xXN8U0kJWyLFZpk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/J8YQgraZnrB1xXN8U0kJWyLFZpk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/J8YQgraZnrB1xXN8U0kJWyLFZpk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/tpx/~4/ba32U_fcMl0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mauroservienti.blogspot.com/feeds/4994295890616323522/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/userexperience-ma-quanto-mi-costi.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/4994295890616323522?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/4994295890616323522?v=2" /><link rel="alternate" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/userexperience-ma-quanto-mi-costi.html" title="UserExperience: ma quanto mi costi?" /><author><name>Mauro Servienti</name><uri>http://www.blogger.com/profile/10629055661352952427</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="23" height="32" src="http://3.bp.blogspot.com/-dm7TXYKMYyw/Tx6n9k3EMZI/AAAAAAAAAII/dqd_n1UdKsI/s220/Avatar.JPG" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lh3.googleusercontent.com/-CoIJEWdm8jc/TzJylC4EONI/AAAAAAAABJI/fa7Dufj-CtI/s72-c/5b8803a9-b7ae-4366-bcb6-60791ec9afa2.png" height="72" width="72" /><thr:total>1</thr:total></entry><entry gd:etag="W/&quot;DEYNQHY-fyp7ImA9WhRbF00.&quot;"><id>tag:blogger.com,1999:blog-6511237790974218081.post-791404741474718746</id><published>2010-01-27T12:14:00.000+01:00</published><updated>2012-02-08T14:03:11.857+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-08T14:03:11.857+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Software Mason" /><category scheme="http://www.blogger.com/atom/ns#" term="Fluent Interfaces" /><category scheme="http://www.blogger.com/atom/ns#" term="Code Design" /><title>Fluently.Design().Me: quanto è facile prenderlo per i fondelli :-)</title><content type="html">&lt;span&gt;…l’intellisense :-)&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Questo test è meraviglioso, generics e anonymous types alla massima potenza:&lt;/span&gt;&lt;br&gt;  &lt;blockquote&gt;   &lt;pre class="code"&gt;[&lt;span style="color: #2b91af"&gt;TestMethod&lt;/span&gt;]
&lt;span style="color: blue"&gt;public void &lt;/span&gt;asyncWorker_expecting_anonymous_type_as_result_should_correctly_set_result()
{
    &lt;span style="color: blue"&gt;var &lt;/span&gt;wa = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ManualResetEvent&lt;/span&gt;( &lt;span style="color: blue"&gt;false &lt;/span&gt;);

    &lt;span style="color: blue"&gt;var &lt;/span&gt;expected = &lt;span style="color: #a31515"&gt;"result"&lt;/span&gt;;
    &lt;span style="color: blue"&gt;var &lt;/span&gt;actual = &lt;span style="color: #a31515"&gt;""&lt;/span&gt;;

    &lt;span style="color: blue"&gt;var &lt;/span&gt;worker = &lt;span style="color: #2b91af"&gt;AsyncWorker&lt;/span&gt;.Using( expected )
        .AndExpecting( &lt;span style="color: blue"&gt;new &lt;/span&gt;{ Sample = &lt;span style="color: #a31515"&gt;"" &lt;/span&gt;} )
        .Configure( cfg =&gt;
        {
            cfg.After = e =&gt; actual = e.Result.Sample;
        } )
        .Execute( e =&gt; e.Result = &lt;span style="color: blue"&gt;new &lt;/span&gt;{ Sample = e.Argument } );

    worker.Completed += ( s, e ) =&gt; wa.Set();
    wa.WaitOne();

    actual.ShouldBeEqualTo( expected );
}&lt;/pre&gt;
  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/blockquote&gt;

&lt;span&gt;con “AndExpecting()” definito così:&lt;/span&gt;&lt;br&gt;

&lt;blockquote&gt;
  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public interface &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IInputWorker&lt;/span&gt;&lt;T&gt;
{
    &lt;span style="color: #2b91af"&gt;IConfiguredInputWorker&lt;/span&gt;&lt;T&gt; Configure( &lt;span style="color: #2b91af"&gt;Action&lt;/span&gt;&lt;&lt;span style="color: #2b91af"&gt;IInputWorkerConfiguration&lt;/span&gt;&lt;T&gt;&gt; cfg );
    &lt;span style="color: #2b91af"&gt;IWorker &lt;/span&gt;Execute( &lt;span style="color: #2b91af"&gt;Action&lt;/span&gt;&lt;&lt;span style="color: #2b91af"&gt;IAsyncArgs&lt;/span&gt;&lt;T&gt;&gt; async );

    &lt;span style="color: #2b91af"&gt;IInputOutputWorker&lt;/span&gt;&lt;T, TResult&gt; AndExpecting&lt;TResult&gt;();
    &lt;span style="color: #2b91af"&gt;IInputOutputWorker&lt;/span&gt;&lt;T, TResult&gt; AndExpecting&lt;TResult&gt;( TResult sample ); 
}&lt;/pre&gt;
  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/blockquote&gt;

&lt;span&gt;Sempre perchè anche la coding experience vuole la sua parte… un po’ come l’occhio :-)&lt;/span&gt;&lt;br&gt;

&lt;span&gt;&lt;strong&gt;A che scopo?&lt;/strong&gt;&lt;/span&gt;&lt;br&gt;

&lt;span&gt;Semplicemente evitare la creazione di una tupla/dto in molti contesti in cui gli anonymous type(s) sono una soluzione ottimale.&lt;/span&gt;&lt;br&gt;

&lt;span&gt;L’inghippo è che con i generics siete obbligati a specificare il tipo T (in questo caso TResult) ma non è possibile specificare come tipo T un anonymous type; è però possibile, come evidenziato dal test, ingannare l’intellisense sfruttando la “&lt;em&gt;Type Inference&lt;/em&gt;”: in questo caso passiamo al metodo AndExpecting&lt;TResult&gt;() un tipo anonimo al solo fine di &lt;em&gt;stimolare&lt;/em&gt; la Type Inference e far si che il tipo della proprietà “Result” abbia la stessa firma del tipo che abbiamo usato come esempio…&lt;/span&gt;&lt;br&gt;

&lt;span&gt;figo :-)&lt;/span&gt;&lt;br&gt;

&lt;span&gt;.m&lt;/span&gt;&lt;br&gt;

&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6511237790974218081-791404741474718746?l=mauroservienti.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/YY2AVCGNY1cmZ8wCo6BE3Segx44/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/YY2AVCGNY1cmZ8wCo6BE3Segx44/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/YY2AVCGNY1cmZ8wCo6BE3Segx44/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/YY2AVCGNY1cmZ8wCo6BE3Segx44/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/tpx/~4/9LUHq2gAF-U" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mauroservienti.blogspot.com/feeds/791404741474718746/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/fluentlydesignme-quanto-e-facile.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/791404741474718746?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/791404741474718746?v=2" /><link rel="alternate" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/fluentlydesignme-quanto-e-facile.html" title="Fluently.Design().Me: quanto è facile prenderlo per i fondelli :-)" /><author><name>Mauro Servienti</name><uri>http://www.blogger.com/profile/10629055661352952427</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="23" height="32" src="http://3.bp.blogspot.com/-dm7TXYKMYyw/Tx6n9k3EMZI/AAAAAAAAAII/dqd_n1UdKsI/s220/Avatar.JPG" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DEYMSHY_eip7ImA9WhRbF00.&quot;"><id>tag:blogger.com,1999:blog-6511237790974218081.post-6806515215775329247</id><published>2010-01-26T20:36:00.000+01:00</published><updated>2012-02-08T14:03:09.842+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-08T14:03:09.842+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Why not..." /><title>Accorrete gente, accorrete :-)</title><content type="html">&lt;span&gt;Dunque dunque… mi stavo quasi dimenticando.&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Se venerdì 29/1 siete in zona Jesi e non avete nulla di meglio da fare potreste venirci a trovare all’evento di &lt;a href="http://dotnetmarche.org/eventi/Default.aspx?IDevento=33"&gt;DotNetMarche&lt;/a&gt; su Wpf e dintorni.&lt;/span&gt;&lt;br&gt;  &lt;span&gt;E se non vi va di sentirci blaterare di UI Compositione Model-View-ViewModel potete sempre aggregarvi per la cena il cui titolo è: &lt;em&gt;&lt;strong&gt;Sua maestà… il Porco&lt;/strong&gt;&lt;/em&gt;… (slurp ;-) )&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Questo il menù:&lt;/span&gt;&lt;br&gt;  &lt;blockquote&gt;   &lt;span&gt;Aperitivo Peppe Cotto, con Ciauscolo, Vino Cotto di Loro e altre Porcherie      &lt;br&gt;Vellutata di Zucca con Cotechino e Crostini       &lt;br&gt;Pasta e Fagioli con Cotiche e Codine       &lt;br&gt;Maialino in porchetta con patata alla griglia con Lardo di Cinta Senese       &lt;br&gt;Dolce Cremoso al Mascarpone       &lt;br&gt;Vini dell’Azienda Agricola Piantate Lunghe di Candia&lt;/span&gt;&lt;br&gt; &lt;/blockquote&gt;  &lt;span&gt;… sono commosso :-)&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Cioè… vi rendete conto: Vellutata di Zucca con Cotechino e Crostini…&lt;/span&gt;&lt;br&gt;  &lt;span&gt;.m&lt;/span&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6511237790974218081-6806515215775329247?l=mauroservienti.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Q2bPrevxKbpBihwkgekk_DttLpA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Q2bPrevxKbpBihwkgekk_DttLpA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Q2bPrevxKbpBihwkgekk_DttLpA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Q2bPrevxKbpBihwkgekk_DttLpA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/tpx/~4/cVqJHKlN8Lg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mauroservienti.blogspot.com/feeds/6806515215775329247/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/accorrete-gente-accorrete.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/6806515215775329247?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/6806515215775329247?v=2" /><link rel="alternate" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/accorrete-gente-accorrete.html" title="Accorrete gente, accorrete :-)" /><author><name>Mauro Servienti</name><uri>http://www.blogger.com/profile/10629055661352952427</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="23" height="32" src="http://3.bp.blogspot.com/-dm7TXYKMYyw/Tx6n9k3EMZI/AAAAAAAAAII/dqd_n1UdKsI/s220/Avatar.JPG" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DEYMSHo7fip7ImA9WhRbF00.&quot;"><id>tag:blogger.com,1999:blog-6511237790974218081.post-926478342719061078</id><published>2010-01-26T04:40:00.000+01:00</published><updated>2012-02-08T14:03:09.406+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-08T14:03:09.406+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Software Mason" /><title>Dimenticavo… once again :-)</title><content type="html">&lt;span&gt;Abbiamo parlato di “Ensure” e del suo rapporto con lo StackTrace ma mi sono dimenticato il pezzetto importante e giustamente &lt;a href="http://it.linkedin.com/in/antonioparata"&gt;Antonio&lt;/a&gt; se ne è accorto :-)&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Eccoci:&lt;/span&gt;&lt;br&gt;  &lt;blockquote&gt;   &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;SourceInfo
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;public readonly static &lt;/span&gt;&lt;span style="color: #2b91af"&gt;SourceInfo &lt;/span&gt;Empty = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;SourceInfo&lt;/span&gt;( &lt;span style="color: #a31515"&gt;""&lt;/span&gt;, &lt;span style="color: #a31515"&gt;""&lt;/span&gt;, &lt;span style="color: #2b91af"&gt;MemberTypes&lt;/span&gt;.Custom );

    &lt;span style="color: blue"&gt;public &lt;/span&gt;SourceInfo( &lt;span style="color: #2b91af"&gt;String &lt;/span&gt;methodName, &lt;span style="color: #2b91af"&gt;String &lt;/span&gt;className, &lt;span style="color: #2b91af"&gt;MemberTypes &lt;/span&gt;sourceType )
    {
        &lt;span style="color: blue"&gt;this&lt;/span&gt;.MethodName = methodName;
        &lt;span style="color: blue"&gt;this&lt;/span&gt;.ClassName = className;
        &lt;span style="color: blue"&gt;this&lt;/span&gt;.SourceType = sourceType;
    }

    &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;String &lt;/span&gt;MethodName { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;private set&lt;/span&gt;; }
    &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;String &lt;/span&gt;ClassName { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;private set&lt;/span&gt;; }
    &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MemberTypes &lt;/span&gt;SourceType { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;private set&lt;/span&gt;; }
}&lt;/pre&gt;
  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/blockquote&gt;

&lt;span&gt;Utilizzando questa come dto possiamo scrivere qualcosa del tipo:&lt;/span&gt;&lt;br&gt;

&lt;blockquote&gt;
  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public static class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Ensure
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;public static &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Ensure&lt;/span&gt;&lt;T&gt; That&lt;T&gt;( T obj )
    {
        &lt;span style="color: #2b91af"&gt;SourceInfo &lt;/span&gt;si = &lt;span style="color: #2b91af"&gt;SourceInfo&lt;/span&gt;.Empty;

        &lt;span style="color: blue"&gt;var &lt;/span&gt;st = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;StackTrace&lt;/span&gt;( 1 );
        &lt;span style="color: blue"&gt;if&lt;/span&gt;( st.FrameCount &gt; 0 )
        {
            &lt;span style="color: blue"&gt;var &lt;/span&gt;f = st.GetFrame( 0 );
            &lt;span style="color: blue"&gt;var &lt;/span&gt;mi = f.GetMethod();
            &lt;span style="color: blue"&gt;if&lt;/span&gt;( mi != &lt;span style="color: blue"&gt;null &lt;/span&gt;)
            {
                si = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;SourceInfo&lt;/span&gt;( mi.DeclaringType.Name, mi.Name, mi.MemberType );
            }
        }

        &lt;span style="color: blue"&gt;return new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Ensure&lt;/span&gt;&lt;T&gt;( obj, si );
    }
}&lt;/pre&gt;
  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/blockquote&gt;

&lt;span&gt;Che altro non fa che recuperare le informazioni sullo stack frame precedente al nostro che è necessariamente il chiamante.&lt;/span&gt;&lt;br&gt;

&lt;span&gt;A questo punto diventa abbastanza banale far passare un test come questo:&lt;/span&gt;&lt;br&gt;

&lt;blockquote&gt;
  &lt;pre class="code"&gt;[&lt;span style="color: #2b91af"&gt;TestMethod&lt;/span&gt;]
&lt;span style="color: blue"&gt;public void &lt;/span&gt;ensure_getFullErrorMessage_should_contain_all_relevant_information()
{
    &lt;span style="color: blue"&gt;var &lt;/span&gt;obj = &lt;span style="color: #2b91af"&gt;Ensure&lt;/span&gt;.That( &lt;span style="color: #a31515"&gt;"" &lt;/span&gt;);
    &lt;span style="color: #2b91af"&gt;String &lt;/span&gt;actual = obj.GetFullErrorMessage( &lt;span style="color: #a31515"&gt;"validator specific message" &lt;/span&gt;);

    &lt;span style="color: blue"&gt;var &lt;/span&gt;containsClassName = actual.Contains( &lt;span style="color: blue"&gt;typeof&lt;/span&gt;( &lt;span style="color: #2b91af"&gt;ValidatorTest &lt;/span&gt;).Name );
    &lt;span style="color: blue"&gt;var &lt;/span&gt;containsMethodName = actual.Contains( &lt;span style="color: blue"&gt;typeof&lt;/span&gt;( &lt;span style="color: #2b91af"&gt;ValidatorTest &lt;/span&gt;).Name );

    containsClassName.ShouldBeTrue();
    containsMethodName.ShouldBeTrue();
}&lt;/pre&gt;
  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/blockquote&gt;

&lt;span&gt;.m&lt;/span&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6511237790974218081-926478342719061078?l=mauroservienti.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/C4huwlvt9RsumndvCB7TRyvp23Y/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/C4huwlvt9RsumndvCB7TRyvp23Y/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/C4huwlvt9RsumndvCB7TRyvp23Y/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/C4huwlvt9RsumndvCB7TRyvp23Y/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/tpx/~4/M7YkR7YkOPM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mauroservienti.blogspot.com/feeds/926478342719061078/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/dimenticavo-once-again.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/926478342719061078?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/926478342719061078?v=2" /><link rel="alternate" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/dimenticavo-once-again.html" title="Dimenticavo… once again :-)" /><author><name>Mauro Servienti</name><uri>http://www.blogger.com/profile/10629055661352952427</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="23" height="32" src="http://3.bp.blogspot.com/-dm7TXYKMYyw/Tx6n9k3EMZI/AAAAAAAAAII/dqd_n1UdKsI/s220/Avatar.JPG" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DEYMRn0zeSp7ImA9WhRbF00.&quot;"><id>tag:blogger.com,1999:blog-6511237790974218081.post-312756305616436846</id><published>2010-01-21T16:52:00.000+01:00</published><updated>2012-02-08T14:03:07.381+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-08T14:03:07.381+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="WPF" /><category scheme="http://www.blogger.com/atom/ns#" term="Software Mason" /><category scheme="http://www.blogger.com/atom/ns#" term="Behavior" /><title>Wpf: Ogni tanto penso che si siano fumati il cervello…</title><content type="html">&lt;span&gt;Si si avete capito bene, quelli che hanno disegnato l’api di Wpf :-S&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Provate a fare una Window ridimensionabile con il mouse (con il ResizeGrip per intenderci) ma ne massimizzabile ne minimizzabile… con Windows Forms era una banalità, con Wpf non si può :-o&lt;/span&gt;&lt;br&gt;  &lt;span&gt;&lt;strong&gt;WindowControlBoxBehavior&lt;/strong&gt;&lt;/span&gt;&lt;br&gt;  &lt;span&gt;la soluzione, pezza secondo me, è questa:&lt;/span&gt;&lt;br&gt;  &lt;blockquote&gt;   &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public sealed class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;WindowControlBoxBehavior &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;Behavior&lt;/span&gt;&lt;&lt;span style="color: #2b91af"&gt;Window&lt;/span&gt;&gt;
{&lt;span style="color: green"&gt;
    &lt;/span&gt;&lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Boolean &lt;/span&gt;AllowMaximize
    {
        &lt;span style="color: blue"&gt;get&lt;/span&gt;;
        &lt;span style="color: blue"&gt;set&lt;/span&gt;;
    }
&lt;span style="color: green"&gt;
    &lt;/span&gt;&lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Boolean &lt;/span&gt;AllowMinimize
    {
        &lt;span style="color: blue"&gt;get&lt;/span&gt;;
        &lt;span style="color: blue"&gt;set&lt;/span&gt;;
    }

    &lt;span style="color: #2b91af"&gt;RoutedEventHandler &lt;/span&gt;h;

    &lt;span style="color: blue"&gt;public &lt;/span&gt;WindowControlBoxBehavior()
    {
        h = ( s, e ) =&gt;
        {
            &lt;span style="color: blue"&gt;var &lt;/span&gt;isDesign = &lt;span style="color: #2b91af"&gt;DesignTimeHelper&lt;/span&gt;.GetIsInDesignMode();
            &lt;span style="color: blue"&gt;var &lt;/span&gt;hWnd = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;WindowInteropHelper&lt;/span&gt;( &lt;span style="color: blue"&gt;this&lt;/span&gt;.AssociatedObject ).Handle;

            &lt;span style="color: blue"&gt;if&lt;/span&gt;( !isDesign &amp;&amp; hWnd != &lt;span style="color: #2b91af"&gt;IntPtr&lt;/span&gt;.Zero &amp;&amp; ( !&lt;span style="color: blue"&gt;this&lt;/span&gt;.AllowMaximize || !&lt;span style="color: blue"&gt;this&lt;/span&gt;.AllowMinimize ) )
            {
                &lt;span style="color: blue"&gt;var &lt;/span&gt;windowLong = &lt;span style="color: #2b91af"&gt;NativeMethods&lt;/span&gt;.GetWindowLongPtr( hWnd, &lt;span style="color: #2b91af"&gt;Constants&lt;/span&gt;.GWL_STYLE );

                &lt;span style="color: blue"&gt;if&lt;/span&gt;( !&lt;span style="color: blue"&gt;this&lt;/span&gt;.AllowMaximize )
                {
                    windowLong = windowLong &amp; ~&lt;span style="color: #2b91af"&gt;Constants&lt;/span&gt;.WS_MAXIMIZEBOX;
                }

                &lt;span style="color: blue"&gt;if&lt;/span&gt;( !&lt;span style="color: blue"&gt;this&lt;/span&gt;.AllowMinimize )
                {
                    windowLong = windowLong &amp; ~&lt;span style="color: #2b91af"&gt;Constants&lt;/span&gt;.WS_MINIMIZEBOX;
                }

                &lt;span style="color: #2b91af"&gt;NativeMethods&lt;/span&gt;.SetWindowLongPtr( hWnd, &lt;span style="color: #2b91af"&gt;Constants&lt;/span&gt;.GWL_STYLE, windowLong );
            }
        };
    }

    &lt;span style="color: blue"&gt;protected override void &lt;/span&gt;OnAttached()
    {
        &lt;span style="color: blue"&gt;base&lt;/span&gt;.OnAttached();
        &lt;span style="color: blue"&gt;this&lt;/span&gt;.AssociatedObject.Loaded += h;
    }

    &lt;span style="color: blue"&gt;protected override void &lt;/span&gt;OnDetaching()
    {
        &lt;span style="color: blue"&gt;this&lt;/span&gt;.AssociatedObject.Loaded -= h;
        &lt;span style="color: blue"&gt;base&lt;/span&gt;.OnDetaching();
    }
}&lt;/pre&gt;
  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/blockquote&gt;

&lt;span&gt;un po’ di sano P/Invoke utilizzabile via xaml così:&lt;/span&gt;&lt;br&gt;

&lt;blockquote&gt;
  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;i&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;Interaction.Behaviors&lt;/span&gt;&lt;span style="color: blue"&gt;&gt;
    &lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;bhv&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;WindowControlBoxBehavior &lt;/span&gt;&lt;span style="color: red"&gt;AllowMaximize&lt;/span&gt;&lt;span style="color: blue"&gt;="False" &lt;/span&gt;&lt;span style="color: red"&gt;AllowMinimize&lt;/span&gt;&lt;span style="color: blue"&gt;="False" /&gt;
&lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;i&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;Interaction.Behaviors&lt;/span&gt;&lt;span style="color: blue"&gt;&gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/blockquote&gt;

&lt;span&gt;producendo il risultato desiderato:&lt;/span&gt;&lt;br&gt;

&lt;span&gt;&lt;a href="https://lh3.googleusercontent.com/-oeBZgaUkWS4/TzJygnh-hmI/AAAAAAAABIw/XdQAXZogfws/298c0b1d-54bb-43a0-86c9-ea6a7387181b.png" rel="shadowbox"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="https://lh4.googleusercontent.com/-uzE-tcrVszQ/TzJygJjRygI/AAAAAAAABIo/QPQwneXK9pM/9b70f997-30b0-4669-9668-f39d75157bf9.png" width="244" height="106"&gt;&lt;/a&gt; &lt;a href="https://lh3.googleusercontent.com/-7p8qv_YOcIY/TzJyiFVsGlI/AAAAAAAABI8/F6OiqAPsg20/e735d941-97d3-4808-9856-8a92a446928c.png" rel="shadowbox"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="https://lh5.googleusercontent.com/-ja_aUEvJNu0/TzJyhmzYJ8I/AAAAAAAABI0/W2p7GlhQrvw/ecf1d948-e43c-4a2a-9fe9-d487114da266.png" width="139" height="106"&gt;&lt;/a&gt;&lt;/span&gt;&lt;br&gt;

&lt;span&gt;dove i bottoni per massimizzare e minimizzare non ci sono ma la finestra resta comunque ridimensionabile.&lt;/span&gt;&lt;br&gt;

&lt;span&gt;.m&lt;/span&gt;&lt;br&gt;





&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6511237790974218081-312756305616436846?l=mauroservienti.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/i8z7fU-eS88g49e3oV7nEdDjnhA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/i8z7fU-eS88g49e3oV7nEdDjnhA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/i8z7fU-eS88g49e3oV7nEdDjnhA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/i8z7fU-eS88g49e3oV7nEdDjnhA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/tpx/~4/gt4SBabZV0A" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mauroservienti.blogspot.com/feeds/312756305616436846/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/wpf-ogni-tanto-penso-che-si-siano.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/312756305616436846?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/312756305616436846?v=2" /><link rel="alternate" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/wpf-ogni-tanto-penso-che-si-siano.html" title="Wpf: Ogni tanto penso che si siano fumati il cervello…" /><author><name>Mauro Servienti</name><uri>http://www.blogger.com/profile/10629055661352952427</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="23" height="32" src="http://3.bp.blogspot.com/-dm7TXYKMYyw/Tx6n9k3EMZI/AAAAAAAAAII/dqd_n1UdKsI/s220/Avatar.JPG" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lh4.googleusercontent.com/-uzE-tcrVszQ/TzJygJjRygI/AAAAAAAABIo/QPQwneXK9pM/s72-c/9b70f997-30b0-4669-9668-f39d75157bf9.png" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DEYDQn0zeip7ImA9WhRbF00.&quot;"><id>tag:blogger.com,1999:blog-6511237790974218081.post-2134762265175199047</id><published>2010-01-21T16:29:00.000+01:00</published><updated>2012-02-08T14:02:53.382+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-08T14:02:53.382+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Team Foundation Server" /><title>VS2008 Forward Compatibility Update: BUG</title><content type="html">&lt;span&gt;o come diamine l’hanno chiamata :-D, insomma questa KB: &lt;a href="http://www.microsoft.com/downloads/details.aspx?displaylang=en&amp;FamilyID=cf13ea45-d17b-4edc-8e6c-6c5b208ec54d"&gt;VS90SP1-KB974558-x86&lt;/a&gt;, okkio che c’è il rischio che vi &lt;em&gt;sminchi&lt;/em&gt; (termine tecnico) la parte di Unit Testing di Visual Studio 2008.&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Ne approfitto per ringraziare &lt;a href="http://blogs.msdn.com/teams_wit_tools/"&gt;John Nierenberg&lt;/a&gt; che mi ha personalmente seguito nell’identificazione del BUG e mi ha pure fornito un workaround.&lt;/span&gt;&lt;br&gt;  &lt;span&gt;&lt;strong&gt;Il problema&lt;/strong&gt;&lt;/span&gt;&lt;br&gt;  &lt;span&gt;L’aggiornamento in oggetto è necessario per rendere compatibile il Team Explorer di VS2008 con TFS 2010, senza l’aggiornamento l’essenziale funziona ma non è detto che si comporti come si deve (senza alcune cose in effetti fanno un po’ le bizze)&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Sta di fatto che l’update si porta dietro una modifica al comportamento della finestra dei Test Results che quando si apre cerca nel Team Explorer un riferimento al Team Project corrente… giustamente se non c’è nessun Team Project il tutto sbomba, portando nella migliore delle ipotesi al fallimento dei test…&lt;/span&gt;&lt;br&gt;  &lt;span&gt;&lt;strong&gt;Il workaround&lt;/strong&gt;&lt;/span&gt;&lt;br&gt;  &lt;span&gt;La soluzione, per chi è affetto dal problema, in attesa della RTM banalmente è quella di essere connessi ad un TFS, uno qualsiasi anche senza nessun Team Project.&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Ne approfitto per ringraziare pubblicamente sia John che tutto il team di TFS che sta facendo &lt;u&gt;un lavoro fondamentale&lt;/u&gt;: &lt;strong&gt;ascoltare i feedback&lt;/strong&gt;.&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Sono iscritto/partecipo ad una mailing list interna, &lt;a href="http://www.geniodelmale.info/"&gt;insieme&lt;/a&gt; ad &lt;a href="http://www.codewrecks.com/blog/"&gt;alcuni&lt;/a&gt; &lt;a href="http://blogs.ugidotnet.org/janky/Default.aspx"&gt;illustri&lt;/a&gt; &lt;a href="http://blogs.ugidotnet.org/j3r/Default.aspx"&gt;colleghi&lt;/a&gt;, del team e c’è un’attività/proattività che definire frenetica è poco, i tempi di risposta spesso sono nell’ordine di pochi minuti nonostante i fusi orari dei partecipanti sparsi un po’ in tutto il mondo, e le discussioni spessissimo sfociano in modifiche a quella che sarà l’RTM di TFS2010 o quella che sarà la &lt;em&gt;vnext&lt;/em&gt;.&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Complimenti! decisamente.&lt;/span&gt;&lt;br&gt;  &lt;span&gt;.m&lt;/span&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6511237790974218081-2134762265175199047?l=mauroservienti.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/tRtXQ7weLJwMdFjVgtBolB5RtbM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/tRtXQ7weLJwMdFjVgtBolB5RtbM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/tRtXQ7weLJwMdFjVgtBolB5RtbM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/tRtXQ7weLJwMdFjVgtBolB5RtbM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/tpx/~4/jIwIcQlKc_c" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mauroservienti.blogspot.com/feeds/2134762265175199047/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/vs2008-forward-compatibility-update-bug.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/2134762265175199047?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/2134762265175199047?v=2" /><link rel="alternate" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/vs2008-forward-compatibility-update-bug.html" title="VS2008 Forward Compatibility Update: BUG" /><author><name>Mauro Servienti</name><uri>http://www.blogger.com/profile/10629055661352952427</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="23" height="32" src="http://3.bp.blogspot.com/-dm7TXYKMYyw/Tx6n9k3EMZI/AAAAAAAAAII/dqd_n1UdKsI/s220/Avatar.JPG" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DEYDQ3w8fyp7ImA9WhRbF00.&quot;"><id>tag:blogger.com,1999:blog-6511237790974218081.post-2784755461343838063</id><published>2010-01-21T14:04:00.000+01:00</published><updated>2012-02-08T14:02:52.277+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-08T14:02:52.277+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Why not..." /><title>Questi due hanno un concetto di fatica tutto loro…</title><content type="html">&lt;span&gt;&lt;a href="https://lh5.googleusercontent.com/-kei5rHX1UH4/TzJyepQER1I/AAAAAAAABIc/ihnEY-YFrtw/70ef0687-0911-4c97-8770-f45073d8e640.jpg" rel="shadowbox"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="La fatica :-)" border="0" alt="La fatica :-)" src="https://lh4.googleusercontent.com/-bQvRBTj_EsM/TzJyeGU95GI/AAAAAAAABIY/KqTt5KwezVI/7b0bf870-aeb6-4142-b8ec-4059e1b6285c.jpg" width="244" height="184"&gt;&lt;/a&gt; &lt;/span&gt;&lt;br&gt;  &lt;span&gt;non ho parole…&lt;/span&gt;&lt;br&gt;  &lt;span&gt;.m&lt;/span&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6511237790974218081-2784755461343838063?l=mauroservienti.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/b4k8seKwvhwl1tgyzYdhGbjCsns/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/b4k8seKwvhwl1tgyzYdhGbjCsns/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/b4k8seKwvhwl1tgyzYdhGbjCsns/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/b4k8seKwvhwl1tgyzYdhGbjCsns/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/tpx/~4/FpFHSmRicJ8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mauroservienti.blogspot.com/feeds/2784755461343838063/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/questi-due-hanno-un-concetto-di-fatica.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/2784755461343838063?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/2784755461343838063?v=2" /><link rel="alternate" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/questi-due-hanno-un-concetto-di-fatica.html" title="Questi due hanno un concetto di fatica tutto loro…" /><author><name>Mauro Servienti</name><uri>http://www.blogger.com/profile/10629055661352952427</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="23" height="32" src="http://3.bp.blogspot.com/-dm7TXYKMYyw/Tx6n9k3EMZI/AAAAAAAAAII/dqd_n1UdKsI/s220/Avatar.JPG" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lh4.googleusercontent.com/-bQvRBTj_EsM/TzJyeGU95GI/AAAAAAAABIY/KqTt5KwezVI/s72-c/7b0bf870-aeb6-4142-b8ec-4059e1b6285c.jpg" height="72" width="72" /><thr:total>1</thr:total></entry><entry gd:etag="W/&quot;DEYCQnYyeip7ImA9WhRbF00.&quot;"><id>tag:blogger.com,1999:blog-6511237790974218081.post-1987895078580154007</id><published>2010-01-21T12:15:00.000+01:00</published><updated>2012-02-08T14:02:43.892+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-08T14:02:43.892+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Software Mason" /><title>Confrontarsi “smuove” i neuroni</title><content type="html">&lt;span&gt;Questo è un fatto, comodo, &lt;a href="https://www.blogger.com/feeds/6511237790974218081/posts/default/697151370555572637"&gt;da tempo&lt;/a&gt;:&lt;/span&gt;&lt;br&gt;  &lt;blockquote&gt;   &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;readonly &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IEntityViewModelFactory &lt;/span&gt;viewModelFactory;

&lt;span style="color: blue"&gt;public &lt;/span&gt;PaymentMethodEditorViewModel( &lt;span style="color: #2b91af"&gt;IEntityViewModelFactory &lt;/span&gt;viewModelFactory )
{
    &lt;span style="color: #2b91af"&gt;Ensure&lt;/span&gt;.That( viewModelFactory ).Named( &lt;span style="color: #a31515"&gt;"viewModelFactory" &lt;/span&gt;).IsNotNull();

    &lt;span style="color: blue"&gt;this&lt;/span&gt;.viewModelFactory = viewModelFactory;
}&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;span&gt;se la validazione fallisce a runtime vi beccate un sana ArgumentNullException. Ci sono una notevole quantità di metodi e di extension methods che servono per validare gli scenari più disparati:&lt;/span&gt;&lt;br&gt;

&lt;blockquote&gt;
  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;void &lt;/span&gt;MyMethod( &lt;span style="color: #2b91af"&gt;String &lt;/span&gt;argument )
{
    &lt;span style="color: #2b91af"&gt;Ensure&lt;/span&gt;.That( argument )
        .Named( &lt;span style="color: #a31515"&gt;"argument" &lt;/span&gt;)
        .WithMessage( &lt;span style="color: #a31515"&gt;"...ti sei dimenticato il parametro :-)" &lt;/span&gt;)
        .IsNotNullNorEmpty();
}&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;span&gt;Fino a ieri aveva un solo difetto: era complessivamente complesso capire dove fosse realmente fallita la validazione perchè l’exception viene sollevata dalla libreria di validazione e non dal codice chiamante quindi l’unica possibilità era armarsi di pazienza e spulciare lo StackTrace… con l’inghippo che se il tutto è in un &lt;a href="https://www.blogger.com/feeds/6511237790974218081/posts/default/1247491366421390124"&gt;mondo&lt;/a&gt; multi-threading lo StackTrace è tutto tranne che developer friendly :-)&lt;/span&gt;&lt;br&gt;

&lt;span&gt;Una paio di giorni fa durante una &lt;em&gt;ciaccolata&lt;/em&gt; con &lt;a href="http://cradle.aspitalia.com/"&gt;Marco De Sanctis&lt;/a&gt; salta fuori l’inghippo di cui sopra e stuzzicato dalla possbilità di risolverlo mi armo di curiosità e, grazie anche a uno scambio di mail con un paio di MVP d’oltreoceano (mirate a capire se c’era modo di ingannare il debugger), scopro che:&lt;/span&gt;&lt;br&gt;

&lt;ul&gt;
  &lt;li&gt;La proprietà StackTrace della classe Exception è virtual… :-) &lt;/li&gt;

  &lt;li&gt;c’è quindi la possibilità di manipolare a runtime lo StackTrace e rimuovere le informazioni che non servono…; &lt;/li&gt;

  &lt;li&gt;…ma questo probabilmente è poco bello oltre al fatto che comporterebbe una gerarchia custom di Exception; &lt;/li&gt;
&lt;/ul&gt;

&lt;span&gt;perchè quindi non limitarsi ad utilizzare lo StackTrace per recuparare le informazioni necessarie a dettagliare meglio l’errore? facendo si che questo snippet:&lt;/span&gt;&lt;br&gt;

&lt;blockquote&gt;
  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;static void &lt;/span&gt;Main( &lt;span style="color: blue"&gt;string&lt;/span&gt;[] args )
{
    &lt;span style="color: blue"&gt;try
    &lt;/span&gt;{
        &lt;span style="color: #2b91af"&gt;Ensure&lt;/span&gt;.That( args )
            .Named( &lt;span style="color: #a31515"&gt;"args" &lt;/span&gt;)
            .WithMessage( &lt;span style="color: #a31515"&gt;"Missing console arguments." &lt;/span&gt;)
            .IsFalse( v =&gt; v.Length == 0 );
    }
    &lt;span style="color: blue"&gt;catch&lt;/span&gt;( &lt;span style="color: #2b91af"&gt;ArgumentException &lt;/span&gt;e )
    {
        &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(e);
    }

    &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.Read();
}&lt;/pre&gt;
  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/blockquote&gt;

&lt;span&gt;produca questo:&lt;/span&gt;&lt;br&gt;

&lt;span&gt;&lt;a href="https://lh4.googleusercontent.com/-ibyAg-DM3Mk/TzJycbHcEHI/AAAAAAAABIM/JzLnrGSrjwA/e9938ad1-c70d-453c-b47b-699e02150745.png" rel="shadowbox"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="https://lh3.googleusercontent.com/-lhn5_GQ6-9w/TzJyb33N4VI/AAAAAAAABII/-hUo37cCDvo/c4604a47-9230-4194-b958-585c5ef25274.png" width="244" height="97"&gt;&lt;/a&gt; &lt;/span&gt;&lt;br&gt;

&lt;span&gt;Sempre perchè anche il developer vuole la sua parte :-)&lt;/span&gt;&lt;br&gt;

&lt;span&gt;.m&lt;/span&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6511237790974218081-1987895078580154007?l=mauroservienti.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/fFI0XZQSbeGUKz1myVW7jrptUDM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/fFI0XZQSbeGUKz1myVW7jrptUDM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/fFI0XZQSbeGUKz1myVW7jrptUDM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/fFI0XZQSbeGUKz1myVW7jrptUDM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/tpx/~4/lUEljArv2D8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mauroservienti.blogspot.com/feeds/1987895078580154007/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/confrontarsi-smuove-i-neuroni.html#comment-form" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/1987895078580154007?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/1987895078580154007?v=2" /><link rel="alternate" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/confrontarsi-smuove-i-neuroni.html" title="Confrontarsi “smuove” i neuroni" /><author><name>Mauro Servienti</name><uri>http://www.blogger.com/profile/10629055661352952427</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="23" height="32" src="http://3.bp.blogspot.com/-dm7TXYKMYyw/Tx6n9k3EMZI/AAAAAAAAAII/dqd_n1UdKsI/s220/Avatar.JPG" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lh3.googleusercontent.com/-lhn5_GQ6-9w/TzJyb33N4VI/AAAAAAAABII/-hUo37cCDvo/s72-c/c4604a47-9230-4194-b958-585c5ef25274.png" height="72" width="72" /><thr:total>4</thr:total></entry><entry gd:etag="W/&quot;DEYBR3w7eSp7ImA9WhRbF00.&quot;"><id>tag:blogger.com,1999:blog-6511237790974218081.post-9136862159197105888</id><published>2010-01-21T11:04:00.000+01:00</published><updated>2012-02-08T14:02:36.201+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-08T14:02:36.201+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Software Mason" /><title>…dimenticavo :-)</title><content type="html">&lt;span&gt;&lt;a href="http://milestone.topics.it/blog/post/confrontarsi-smuove-i-neuroni"&gt;Anche io invecchio&lt;/a&gt;, uffa :-P&lt;/span&gt;&lt;br&gt;  &lt;span&gt;la chiaccherata con &lt;a href="http://cradle.aspitalia.com/"&gt;Marco de Sanctis&lt;/a&gt; era volta a capire perchè non avessi usato una sintassi di questo genere:&lt;/span&gt;&lt;br&gt;  &lt;blockquote&gt;   &lt;pre class="code"&gt;&lt;span style="color: #2b91af"&gt;Ensure&lt;/span&gt;.That( () =&gt; args )
    .WithMessage( &lt;span style="color: #a31515"&gt;"Missing console arguments." &lt;/span&gt;)
    .IsFalse( v =&gt; v.Length == 0 );&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;span&gt;che utilizzando le lambda mi permetteva di pigliare due piccioni con una fava:&lt;/span&gt;&lt;br&gt;

&lt;ul&gt;
  &lt;li&gt;rimuovere il nome del parametro che è una stringa non refactoring-friendly; &lt;/li&gt;

  &lt;li&gt;e passare contestualmente il valore da ispezionare; &lt;/li&gt;
&lt;/ul&gt;

&lt;span&gt;In effetti quella cosa in origine c’era:&lt;/span&gt;&lt;br&gt;

&lt;blockquote&gt;
  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;internal &lt;/span&gt;Ensure( System.Linq.Expressions.&lt;span style="color: #2b91af"&gt;Expression&lt;/span&gt;&lt;&lt;span style="color: #2b91af"&gt;Func&lt;/span&gt;&lt;T&gt;&gt; obj )
{
    &lt;span style="color: blue"&gt;if&lt;/span&gt;( obj == &lt;span style="color: blue"&gt;null &lt;/span&gt;)
    {
        &lt;span style="color: blue"&gt;throw new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ArgumentNullException&lt;/span&gt;( &lt;span style="color: #a31515"&gt;"obj"&lt;/span&gt;, &lt;span style="color: #a31515"&gt;"Cannot use a null Expression&lt;Func&lt;T&gt;&gt; as Ensure ctor parameter." &lt;/span&gt;);
    }

    &lt;span style="color: #2b91af"&gt;Func&lt;/span&gt;&lt;T&gt; func = obj.Compile();
    &lt;span style="color: blue"&gt;this&lt;/span&gt;.inspectedObject = func();

    &lt;span style="color: blue"&gt;var &lt;/span&gt;expression = obj.Body &lt;span style="color: blue"&gt;as &lt;/span&gt;System.Linq.Expressions.&lt;span style="color: #2b91af"&gt;MemberExpression&lt;/span&gt;;
    &lt;span style="color: blue"&gt;var &lt;/span&gt;member = expression.Member &lt;span style="color: blue"&gt;as &lt;/span&gt;System.Reflection.&lt;span style="color: #2b91af"&gt;FieldInfo&lt;/span&gt;;
    &lt;span style="color: blue"&gt;this&lt;/span&gt;.Name = member.Name;
}&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;span&gt;Decisamente figoso, peccato che quella chiamata a Compile(), per poi poter ottenere il valore, abbia un costo notevole che inficia in maniera percettibile sulle prestazioni complessive.&lt;/span&gt;&lt;br&gt;

&lt;span&gt;Il suggerimento resta comunque valido per soddisfare il primo punto e poter scrivere questo:&lt;/span&gt;&lt;br&gt;

&lt;blockquote&gt;
  &lt;pre class="code"&gt;&lt;span style="color: #2b91af"&gt;Ensure&lt;/span&gt;.That( args )
    &lt;u&gt;&lt;strong&gt;.Named( () =&gt; args )
&lt;/strong&gt;&lt;/u&gt;    .WithMessage( &lt;span style="color: #a31515"&gt;"Missing console arguments." &lt;/span&gt;)
    .IsFalse( v =&gt; v.Length == 0 );&lt;/pre&gt;
  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/blockquote&gt;

&lt;span&gt;.m&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/span&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6511237790974218081-9136862159197105888?l=mauroservienti.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/FHZcmr7hR2gEK1CA3UUsxIOts68/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/FHZcmr7hR2gEK1CA3UUsxIOts68/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/FHZcmr7hR2gEK1CA3UUsxIOts68/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/FHZcmr7hR2gEK1CA3UUsxIOts68/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/tpx/~4/6hsAC5RfcDA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mauroservienti.blogspot.com/feeds/9136862159197105888/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/dimenticavo.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/9136862159197105888?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/9136862159197105888?v=2" /><link rel="alternate" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/dimenticavo.html" title="…dimenticavo :-)" /><author><name>Mauro Servienti</name><uri>http://www.blogger.com/profile/10629055661352952427</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="23" height="32" src="http://3.bp.blogspot.com/-dm7TXYKMYyw/Tx6n9k3EMZI/AAAAAAAAAII/dqd_n1UdKsI/s220/Avatar.JPG" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DEYBRHk8eCp7ImA9WhRbF00.&quot;"><id>tag:blogger.com,1999:blog-6511237790974218081.post-2940093177295818889</id><published>2010-01-21T06:39:00.000+01:00</published><updated>2012-02-08T14:02:35.770+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-08T14:02:35.770+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="WPF" /><category scheme="http://www.blogger.com/atom/ns#" term="Software Mason" /><category scheme="http://www.blogger.com/atom/ns#" term="WeakReference" /><category scheme="http://www.blogger.com/atom/ns#" term="IWeakEventListener" /><category scheme="http://www.blogger.com/atom/ns#" term="WeakEventManager" /><title>Wpf: WeakEventManager</title><content type="html">&lt;span&gt;Ci siamo da poco scontrati con il concetto di &lt;a href="https://www.blogger.com/feeds/6511237790974218081/posts/default/4317899770139266210" target="_blank"&gt;Logical e Visual Tree&lt;/a&gt; e con l’evidente necessità di tenere in ordine la memoria per consentire al GC di fare il suo lavoro quando serve, risulta però evidente, sempre più al crescere della soluzione, che lasciare per strada qualcosa potrebbe essere molto facile.&lt;/span&gt;&lt;br&gt;  &lt;span&gt;&lt;strong&gt;Weak*&lt;/strong&gt;&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Abbiamo già visto &lt;a href="https://www.blogger.com/feeds/6511237790974218081/posts/default/6242762352963266156"&gt;come una WeakReference&lt;/a&gt; possa essere un’ottima soluzione ad alcune problematiche, ribaltiamo adesso lo scenario e mettiamoci nel panni di una classe che aggancia un handler ad un evento: se la classe (target) che ha agganciato l’evento non ha modo di sapere quando e se il sender va &lt;em&gt;out-of-scope&lt;/em&gt; è evidente che questo può portare ad un &lt;em&gt;.net-memory-leak&lt;/em&gt; perchè il nostro target sta impedendo che il GC possa liberare la memoria occupata dal sender.&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Wpf introduce il supporto a questo scenario estendendo il concetto di WeakReference e introducendo quello di &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.weakeventmanager.aspx"&gt;WeakEventManager&lt;/a&gt;: un weak event manager è qualcuno che si mette in mezzo tra il sender e il target facendo da ponte tra i due e gestendo internamente una &lt;em&gt;sorta&lt;/em&gt; di weak reference in modo che se il sender esce dallo scope possa venir correttamente gestito dal GC.&lt;/span&gt;&lt;br&gt;  &lt;span&gt;&lt;strong&gt;Si, ok… ma come si fa?&lt;/strong&gt;&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Inquadriamo prima il potenziale problema con un esempio:&lt;/span&gt;&lt;br&gt;  &lt;span&gt;&lt;a href="https://lh4.googleusercontent.com/-rAXdVplFEzs/TzJyaRUEzRI/AAAAAAAABIA/hWzGYpJP2dQ/5f97a86f-6f74-49ba-a1a6-fce35d1b9eda.png" rel="shadowbox"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="https://lh6.googleusercontent.com/-xi6g6k8pFtw/TzJyZ7-kcjI/AAAAAAAABH4/SeBbarYjrW4/dfbdac9d-eeba-4377-8a36-eb6663cc91ec.png" width="244" height="135"&gt;&lt;/a&gt; &lt;/span&gt;&lt;br&gt;  &lt;span&gt;In una UI come quella qui sopra succedono generalmente un po’ di cose, tra cui:&lt;/span&gt;&lt;br&gt;  &lt;ul&gt;   &lt;li&gt;I bottoncini “impegnato” e “stampa” si attivano disattivano in base alla selezione nel documento sottostante… a patto che:      &lt;ul&gt;       &lt;li&gt;Un documento sottostamte esista…; &lt;/li&gt;        &lt;li&gt;Un documento sottostante sia il documento attivo; &lt;/li&gt;        &lt;li&gt;etc… &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;Il ribbon reagisce al cambio di documento corrente “seguendo” come un segugio, sulla base di un set di regole il documento attivo: ad esempio se selezionate il documento “Home” automaticamente la tab “Home” del ribbon diventa quella attiva e se tornate ai risultati della ricerca la tab “Pubblicazioni” diventa quella attiva; ma se vi spostate su Home e poi manualmente riportate il ribbon su “Pubblicazioni” allora i pulsanti (di cui sopra) reagiscono di conseguenza disattivandosi perchè il documento attivo non è quello giusto; &lt;/li&gt; &lt;/ul&gt;  &lt;span&gt;Come potete immaginare in tutto questo giro di handling di eventi ce ne sono una vera montagna, non solo…, la cosa è complicata dal fatto che alcune parti di quella UI sono iniettate a runtime e sanno poco o nulla di chi le sta ospitando e chi le ospita proprio non sa nulla di loro.&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Grazie al supporto dei command di Wpf diventa comunque abbastanza facile far funzionare il tutto:&lt;/span&gt;&lt;br&gt;  &lt;blockquote&gt;   &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;.PrintCommand = &lt;span style="color: #2b91af"&gt;DelegateCommand&lt;/span&gt;.Create()
    .TriggerUsing( &lt;span style="color: blue"&gt;this&lt;/span&gt;.regionMonitor )
    .TriggerUsing( &lt;span style="color: blue"&gt;this&lt;/span&gt;.listChangedMonitor )
    .OnCanExecute( o =&gt;
    {
        &lt;span style="color: blue"&gt;var &lt;/span&gt;canExecute = &lt;span style="color: blue"&gt;false&lt;/span&gt;;
        &lt;span style="color: blue"&gt;this&lt;/span&gt;.regionMonitor.TryGetViewModel&lt;&lt;span style="color: #2b91af"&gt;IPublicationListViewModel&lt;/span&gt;&gt;( &lt;span style="color: blue"&gt;this&lt;/span&gt;.regionMonitor.ActiveContent, vm =&gt;
        {
            canExecute = vm.SelectedItems.Count() == 1;
        } );

        &lt;span style="color: blue"&gt;return &lt;/span&gt;canExecute;
    } )
    .OnExecute( o =&gt;
    {
&lt;span style="color: green"&gt;        &lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;.PrintSelection( &lt;span style="color: blue"&gt;this&lt;/span&gt;.actualPrinterSettings );
    } );&lt;/pre&gt;
  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/blockquote&gt;

&lt;span&gt;Ho già parlato sia di &lt;a href="https://www.blogger.com/feeds/6511237790974218081/posts/default/1069924125365624508"&gt;DelegateCommand che di trigger&lt;/a&gt; quindi vado al sodo… TriggerUsing() &lt;u&gt;faceva&lt;/u&gt; una cosa del genere:&lt;/span&gt;&lt;br&gt;

&lt;blockquote&gt;
  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IBindableCommand &lt;/span&gt;TriggerUsing( &lt;span style="color: #2b91af"&gt;IMonitor &lt;/span&gt;source )
{
    source.Changed += onSourceChanged;
    &lt;span style="color: blue"&gt;return this&lt;/span&gt;;
}&lt;/pre&gt;
  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/blockquote&gt;

&lt;span&gt;adesso si è posto il problema che in quello scenario complesso questa &lt;em&gt;dipendenza&lt;/em&gt; diretta porta, in alcuni casi, il GC a mordersi la coda.&lt;/span&gt;&lt;br&gt;

&lt;span&gt;&lt;strong&gt;Please welcome the “WeakEventManager”&lt;/strong&gt;&lt;/span&gt;&lt;br&gt;

&lt;span&gt;La linee guida dicono di:&lt;/span&gt;&lt;br&gt;

&lt;ul&gt;
  &lt;li&gt;Creare una classe ad hoc, che eredita da WeakEventManager, ed è specilizzata per la gestione di un particolare evento: MonitorChangedWeakEventManager; &lt;/li&gt;

  &lt;li&gt;Implementare sul “gestore” dell’evento, in questo caso quindi il DelegateCommand, l’interfaccia &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.iweakeventlistener.aspx"&gt;IWeakEventListener&lt;/a&gt;; &lt;/li&gt;

  &lt;li&gt;Modificare il codice di “aggancio” dell’evento e passare la responsabilità al WeakEventManager di turno; &lt;/li&gt;
&lt;/ul&gt;

&lt;span&gt;Partiamo quindi dal fondo, TriggerUsing() diventa:&lt;/span&gt;&lt;br&gt;

&lt;blockquote&gt;
  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IBindableCommand &lt;/span&gt;TriggerUsing( &lt;span style="color: #2b91af"&gt;IMonitor &lt;/span&gt;source )
{
    &lt;span style="color: #2b91af"&gt;MonitorChangedWeakEventManager&lt;/span&gt;.AddListener( source, &lt;span style="color: blue"&gt;this &lt;/span&gt;);

    &lt;span style="color: blue"&gt;return this&lt;/span&gt;;
}&lt;/pre&gt;
  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/blockquote&gt;

&lt;span&gt;Non agganciamo più direttamente l’evento ma deleghiamo; per far si che comunque la notifica dell’evento arrivi da noi implementiamo l’interfaccia:&lt;/span&gt;&lt;br&gt;

&lt;blockquote&gt;
  &lt;pre class="code"&gt;&lt;span style="color: #2b91af"&gt;Boolean IWeakEventListener&lt;/span&gt;.ReceiveWeakEvent( &lt;span style="color: #2b91af"&gt;Type &lt;/span&gt;managerType, &lt;span style="color: blue"&gt;object &lt;/span&gt;sender, &lt;span style="color: #2b91af"&gt;EventArgs &lt;/span&gt;e )
{
    &lt;span style="color: blue"&gt;if&lt;/span&gt;( managerType == &lt;span style="color: blue"&gt;typeof&lt;/span&gt;( &lt;span style="color: #2b91af"&gt;MonitorChangedWeakEventManager &lt;/span&gt;) )
    {
        &lt;span style="color: blue"&gt;this&lt;/span&gt;.OnTriggerChanged( ( &lt;span style="color: #2b91af"&gt;IMonitor &lt;/span&gt;)sender );
    }
    &lt;span style="color: blue"&gt;else
    &lt;/span&gt;{
&lt;span style="color: green"&gt;        &lt;/span&gt;&lt;span style="color: blue"&gt;return false&lt;/span&gt;;
    }

    &lt;span style="color: blue"&gt;return true&lt;/span&gt;;
}&lt;/pre&gt;
  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/blockquote&gt;

&lt;span&gt;Questo è quanto: quando il WeakEventManager deve notificarci chiama ReceiveWeakEvent passandoci il tipo di manager, in modo da consentirci di prendere decisioni sulla base di chi sia il gestore, e passandoci i classici “sender” e “args”. Nostro compito è ritonare un Boolean che confermi o meno se l’evento ci è &lt;em&gt;piaciuto&lt;/em&gt;… :-)&lt;/span&gt;&lt;br&gt;

&lt;span&gt;&lt;strong&gt;Il cuore del giochetto&lt;/strong&gt;&lt;/span&gt;&lt;br&gt;

&lt;span&gt;Il tutto è gestito in maniera abbastanza semplice dal nostro manager specializzato:&lt;/span&gt;&lt;br&gt;

&lt;blockquote&gt;
  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public sealed class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MonitorChangedWeakEventManager &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;WeakEventManager
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;static &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MonitorChangedWeakEventManager &lt;/span&gt;GetCurrentManager()
    {
        &lt;span style="color: blue"&gt;var &lt;/span&gt;mt = &lt;span style="color: blue"&gt;typeof&lt;/span&gt;( &lt;span style="color: #2b91af"&gt;MonitorChangedWeakEventManager &lt;/span&gt;);

        &lt;span style="color: blue"&gt;var &lt;/span&gt;manager = ( &lt;span style="color: #2b91af"&gt;MonitorChangedWeakEventManager &lt;/span&gt;)&lt;span style="color: #2b91af"&gt;WeakEventManager&lt;/span&gt;.GetCurrentManager( mt );
        &lt;span style="color: blue"&gt;if&lt;/span&gt;( manager == &lt;span style="color: blue"&gt;null &lt;/span&gt;)
        {
            manager = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MonitorChangedWeakEventManager&lt;/span&gt;();
            &lt;span style="color: #2b91af"&gt;WeakEventManager&lt;/span&gt;.SetCurrentManager( mt, manager );
        }

        &lt;span style="color: blue"&gt;return &lt;/span&gt;manager;
    }

    &lt;span style="color: blue"&gt;public static void &lt;/span&gt;AddListener( &lt;span style="color: #2b91af"&gt;IMonitor &lt;/span&gt;source, &lt;span style="color: #2b91af"&gt;IWeakEventListener &lt;/span&gt;listener )
    {
        &lt;span style="color: #2b91af"&gt;MonitorChangedWeakEventManager
            &lt;/span&gt;.GetCurrentManager()
            .ProtectedAddListener( source, listener );
    }

    &lt;span style="color: blue"&gt;public static void &lt;/span&gt;RemoveListener( &lt;span style="color: #2b91af"&gt;IMonitor &lt;/span&gt;source, &lt;span style="color: #2b91af"&gt;IWeakEventListener &lt;/span&gt;listener )
    {
        &lt;span style="color: #2b91af"&gt;MonitorChangedWeakEventManager
            &lt;/span&gt;.GetCurrentManager()
            .ProtectedRemoveListener( source, listener );
    }

    &lt;span style="color: blue"&gt;private &lt;/span&gt;MonitorChangedWeakEventManager()
    {

    }

    &lt;span style="color: blue"&gt;void &lt;/span&gt;OnChanged( &lt;span style="color: blue"&gt;object &lt;/span&gt;sender, &lt;span style="color: #2b91af"&gt;EventArgs &lt;/span&gt;args )
    {
        &lt;span style="color: blue"&gt;base&lt;/span&gt;.DeliverEvent( sender, args );
    }

    &lt;span style="color: blue"&gt;protected override void &lt;/span&gt;StartListening( &lt;span style="color: blue"&gt;object &lt;/span&gt;source )
    {
        &lt;span style="color: blue"&gt;var &lt;/span&gt;trigger = source &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IMonitor&lt;/span&gt;;
        &lt;span style="color: blue"&gt;if&lt;/span&gt;( trigger != &lt;span style="color: blue"&gt;null &lt;/span&gt;)
        {
            trigger.Changed += OnChanged;
        }
    }

    &lt;span style="color: blue"&gt;protected override void &lt;/span&gt;StopListening( &lt;span style="color: blue"&gt;object &lt;/span&gt;source )
    {
        &lt;span style="color: blue"&gt;var &lt;/span&gt;trigger = source &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IMonitor&lt;/span&gt;;
        &lt;span style="color: blue"&gt;if&lt;/span&gt;( trigger != &lt;span style="color: blue"&gt;null &lt;/span&gt;)
        {
            trigger.Changed -= OnChanged;
        }
    }
}&lt;/pre&gt;
  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;GetCurrentManager() sostanzialmente è un singleton e si appoggia a WeakEventManager per persistere la reference; &lt;/li&gt;

  &lt;li&gt;AddListener e RemoveListener sono i &lt;u&gt;nostri&lt;/u&gt; entry point che delegano alla classe base l’operatività; &lt;/li&gt;

  &lt;li&gt;StartListening e StopListening vengono invocati dalla classe base per gestire il vero e proprio aggiancio/sgancio dell’handler; &lt;/li&gt;

  &lt;li&gt;Infine OnChanged, il nostro handler, utilizza il metodo DeliverEvent della classe base per &lt;em&gt;dispatchare&lt;/em&gt; in maniera sicura l’evento; &lt;/li&gt;
&lt;/ul&gt;

&lt;span&gt;Nulla di trascendentale, anzi alla lunga un po’ noiosetto da scrivere, ma per molte situazioni ottimo e risolutivo.&lt;/span&gt;&lt;br&gt;

&lt;span&gt;.m&lt;/span&gt;&lt;br&gt;

&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6511237790974218081-2940093177295818889?l=mauroservienti.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/D1_zFKD9EPmsvJtkmcmk2nSFF7M/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/D1_zFKD9EPmsvJtkmcmk2nSFF7M/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/D1_zFKD9EPmsvJtkmcmk2nSFF7M/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/D1_zFKD9EPmsvJtkmcmk2nSFF7M/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/tpx/~4/fiFLsMQYDf0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mauroservienti.blogspot.com/feeds/2940093177295818889/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/wpf-weakeventmanager.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/2940093177295818889?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/2940093177295818889?v=2" /><link rel="alternate" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/wpf-weakeventmanager.html" title="Wpf: WeakEventManager" /><author><name>Mauro Servienti</name><uri>http://www.blogger.com/profile/10629055661352952427</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="23" height="32" src="http://3.bp.blogspot.com/-dm7TXYKMYyw/Tx6n9k3EMZI/AAAAAAAAAII/dqd_n1UdKsI/s220/Avatar.JPG" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lh6.googleusercontent.com/-xi6g6k8pFtw/TzJyZ7-kcjI/AAAAAAAABH4/SeBbarYjrW4/s72-c/dfbdac9d-eeba-4377-8a36-eb6663cc91ec.png" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DEYASHo5eCp7ImA9WhRbF00.&quot;"><id>tag:blogger.com,1999:blog-6511237790974218081.post-2443771977997412979</id><published>2010-01-20T19:40:00.000+01:00</published><updated>2012-02-08T14:02:29.420+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-08T14:02:29.420+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="WPF" /><category scheme="http://www.blogger.com/atom/ns#" term="Why not..." /><category scheme="http://www.blogger.com/atom/ns#" term="Design Time" /><category scheme="http://www.blogger.com/atom/ns#" term="Designer" /><title>Wpf, i tool e il bisogno di produttività…</title><content type="html">&lt;span&gt;Secondo siamo ancora molto lontani dal vedere la luce. Il problema stavolta non è M-V-VM, come per ogni pattern di presentazione, imho, la produttività si misura nel lungo periodo mixando la produttività iniziale con la produttività del processo di manutenzione e di estensione.&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Il problema di fondo è ancora il designer, quello di Visual Studio 2008 è pressochè inesistente mentre Blend se la cavicchia… ma proprio cavicchia. Non ho ancora avuto modo di stressare quello di Visual Studio 2010, ma da quel che sento in giro non farà di certo faville.&lt;/span&gt;&lt;br&gt;  &lt;span&gt;&lt;strong&gt;Cos’è che mi fa lamentare?&lt;/strong&gt;&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Il designer Windows Forms è ottimo ma probabilmente se ci ragioniamo quello che lo rende ottimo non è tanto il designer in se quanto il paradigma che ci sta intorno: Fixed Layout.&lt;/span&gt;&lt;br&gt;  &lt;span&gt;&lt;strong&gt;Flow Layout&lt;/strong&gt;&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Wpf introduce e spinge pesantemente, e per chi arriva dal mondo web in questo senso il salto &lt;u&gt;&lt;em&gt;forse&lt;/em&gt;&lt;/u&gt; è più facile, il concetto di Flow Layout e mano a mano che lo si usa ci si rende conto che adattare il layout al contenuto è cosa buona e giusta.&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Questo però introduce un paio di problemi: &lt;/span&gt;&lt;br&gt;  &lt;ol&gt;   &lt;li&gt;non potete più avere come strumento di design qualcosa di mediocre;&lt;/li&gt;    &lt;li&gt;è fondamentale prototipizzare!&lt;/li&gt; &lt;/ol&gt;  &lt;span&gt;Per il secondo punto, a oggi per me, la carta è ancora lo strumento principe: facile, immediato, velocissimo… mi permette di raggiungere lo scopo, che è capire come organizzare le informazioni, in brevissimo tempo; per il primo punto invece siamo in altissimo mare… :-(&lt;/span&gt;&lt;br&gt;  &lt;span&gt;.m&lt;/span&gt;&lt;br&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6511237790974218081-2443771977997412979?l=mauroservienti.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/8kp9BxxXvgcJTV0IeQxKx0mFoQU/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/8kp9BxxXvgcJTV0IeQxKx0mFoQU/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/8kp9BxxXvgcJTV0IeQxKx0mFoQU/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/8kp9BxxXvgcJTV0IeQxKx0mFoQU/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/tpx/~4/2BtUkJ_2dAA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mauroservienti.blogspot.com/feeds/2443771977997412979/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/wpf-i-tool-e-il-bisogno-di-produttivita.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/2443771977997412979?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/2443771977997412979?v=2" /><link rel="alternate" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/wpf-i-tool-e-il-bisogno-di-produttivita.html" title="Wpf, i tool e il bisogno di produttività…" /><author><name>Mauro Servienti</name><uri>http://www.blogger.com/profile/10629055661352952427</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="23" height="32" src="http://3.bp.blogspot.com/-dm7TXYKMYyw/Tx6n9k3EMZI/AAAAAAAAAII/dqd_n1UdKsI/s220/Avatar.JPG" /></author><thr:total>1</thr:total></entry><entry gd:etag="W/&quot;DEYARn46cSp7ImA9WhRbF00.&quot;"><id>tag:blogger.com,1999:blog-6511237790974218081.post-3511359177506965381</id><published>2010-01-20T18:00:00.000+01:00</published><updated>2012-02-08T14:02:27.019+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-08T14:02:27.019+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Software Mason" /><category scheme="http://www.blogger.com/atom/ns#" term="Fluent Interfaces" /><category scheme="http://www.blogger.com/atom/ns#" term="Code Design" /><title>Fluently.Design().Me: inganniamo l’intellisense :-)</title><content type="html">&lt;span&gt;
	&lt;em&gt;Per la felicità di &lt;a href="http://blog.raffaeu.com/Default.aspx" target="_blank"&gt;Raffaeu&lt;/a&gt; ;-)&lt;/em&gt;&lt;/span&gt;&lt;br&gt;
&lt;span&gt;
	Eravamo rimasti qua:&lt;/span&gt;&lt;br&gt;
&lt;span&gt;
	&lt;a href="https://lh5.googleusercontent.com/-AYfULW6OGSA/TzJyUriAbXI/AAAAAAAABG8/WQdHT42-J8w/93c98f75-0ae8-49ee-b03e-92921a3080f2.png" rel="shadowbox"&gt;&lt;img alt="image_thumb[2]" border="0" height="159" src="https://lh4.googleusercontent.com/-h5rDeLv1FD8/TzJyUEgZvCI/AAAAAAAABG4/8ZNbM7PAI_c/03b2c6db-e678-48b4-8ea8-931e1686d511.png" style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image_thumb[2]" width="229"&gt;&lt;/a&gt;&lt;a href="https://lh3.googleusercontent.com/-ivYp-gInQm0/TzJyVypxNUI/AAAAAAAABHM/7UM0kjUKmnc/81535458-a66f-4a0f-a441-54a08d3f8329.png" rel="shadowbox"&gt;&lt;img alt="image_thumb[1]" border="0" height="159" src="https://lh6.googleusercontent.com/-5ynlJpppWZ4/TzJyVDy_yGI/AAAAAAAABHE/bSz09dHGsKM/4c1142bf-f6b7-4837-aaba-62a23096d9cf.png" style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image_thumb[1]" width="244"&gt;&lt;/a&gt;&lt;/span&gt;&lt;br&gt;
&lt;span&gt;
	Il giochetto è più semplice del previsto, avete quasi sempre due attori:&lt;/span&gt;&lt;br&gt;
&lt;ul&gt;
	&lt;li&gt;
		Un entry point che tipicamente è una classe statica non generica che espone dei metodi generici;&lt;/li&gt;
	&lt;li&gt;
		Una classe che viene istanziata e ritornata dall’entry point;&lt;/li&gt;
&lt;/ul&gt;
&lt;span&gt;
	Una cosa del tipo:&lt;/span&gt;&lt;br&gt;
&lt;blockquote&gt;
	&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;static class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MyFluentEntryPoint
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;public static &lt;/span&gt;&lt;span style="color: #2b91af"&gt;FluentEngine&lt;/span&gt;&lt;t&gt; Having&lt;t&gt;( T value )
    {
        &lt;span style="color: blue"&gt;return new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;FluentEngine&lt;/span&gt;&lt;t&gt;( value );
    }
}&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/pre&gt;&lt;/blockquote&gt;
&lt;span&gt;
	&lt;t&gt;&lt;t&gt;&lt;t&gt;
	&lt;p&gt;
		e un engine così definito:&lt;/p&gt;
	&lt;blockquote&gt;
		&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;FluentEngine&lt;/span&gt;&lt;t&gt;
{
    &lt;span style="color: blue"&gt;readonly &lt;/span&gt;T value;

    &lt;span style="color: blue"&gt;public &lt;/span&gt;FluentEngine( T value )
    {
        &lt;span style="color: blue"&gt;this&lt;/span&gt;.value = value;
    }
}&lt;/t&gt;&lt;/pre&gt;&lt;/blockquote&gt;
	&lt;t&gt;
	&lt;p&gt;
		Adesso per semplicità immaginiamo di voler essere in grado di fare 2 operazioni:&lt;/p&gt;
	&lt;ul&gt;
		&lt;li&gt;
			configurare l’engine appena creato;&lt;/li&gt;
		&lt;li&gt;
			mandare in esecuzione l’engine;&lt;/li&gt;
	&lt;/ul&gt;
	&lt;blockquote&gt;
		&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;FluentEngine&lt;/span&gt;&lt;t&gt;
{
    &lt;span style="color: blue"&gt;readonly &lt;/span&gt;T value;

    &lt;span style="color: blue"&gt;public &lt;/span&gt;FluentEngine( T value )
    {
        &lt;span style="color: blue"&gt;this&lt;/span&gt;.value = value;
    }

    &lt;span style="color: #2b91af"&gt;FluentEngine&lt;/span&gt;&lt;t&gt; Configure()
    {
        &lt;span style="color: blue"&gt;return this&lt;/span&gt;;
    }

    &lt;span style="color: #2b91af"&gt;FluentEngine&lt;/span&gt;&lt;t&gt; Execute()
    {
        &lt;span style="color: blue"&gt;return this&lt;/span&gt;;
    }
}&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/pre&gt;&lt;/blockquote&gt;
	&lt;t&gt;&lt;t&gt;&lt;t&gt;
	&lt;p&gt;
		Funzionare funziona ma incappate nel solito problema della “coding experience”:&lt;/p&gt;
	&lt;p&gt;
		&lt;a href="https://lh3.googleusercontent.com/-28cMyT_9S8Q/TzJyW_OBbQI/AAAAAAAABHY/Rr-hdB-CGgA/64648756-8877-4a29-8676-b3d81d1552b3.png" rel="shadowbox"&gt;&lt;img alt="image" border="0" height="151" src="https://lh6.googleusercontent.com/-LkooWJCN488/TzJyWb8GFiI/AAAAAAAABHU/wnZCWVN50ts/36fe6d84-64bf-4c93-bff3-f95010c22570.png" style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" width="244"&gt;&lt;/a&gt;&lt;/p&gt;
	&lt;p&gt;
		Allora fate un secondo tentativo… fallimentare :-), almeno io ci sono incappato:&lt;/p&gt;
	&lt;ul&gt;
		&lt;li&gt;
			togliete il metodo Execute da FluentEngine;&lt;/li&gt;
		&lt;li&gt;
			create un ConfiguredFluentEngine:&lt;/li&gt;
	&lt;/ul&gt;
	&lt;blockquote&gt;
		&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ConfiguredFluentEngine&lt;/span&gt;&lt;t&gt;
{
    &lt;span style="color: blue"&gt;readonly &lt;/span&gt;T value;

    &lt;span style="color: blue"&gt;public &lt;/span&gt;ConfiguredFluentEngine( T value )
    {
        &lt;span style="color: blue"&gt;this&lt;/span&gt;.value = value;
    }

    &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ConfiguredFluentEngine&lt;/span&gt;&lt;t&gt; Execute()
    {
        &lt;span style="color: blue"&gt;return this&lt;/span&gt;;
    }
}&lt;/t&gt;&lt;/t&gt;&lt;/pre&gt;&lt;/blockquote&gt;
	&lt;t&gt;&lt;t&gt;
	&lt;p&gt;
		e cambiate la firma di Configure():&lt;/p&gt;
	&lt;blockquote&gt;
		&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ConfiguredFluentEngine&lt;/span&gt;&lt;t&gt; Configure()
{
    &lt;span style="color: blue"&gt;return new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ConfiguredFluentEngine&lt;/span&gt;&lt;t&gt;( &lt;span style="color: blue"&gt;this&lt;/span&gt;.value );
}&lt;/t&gt;&lt;/t&gt;&lt;/pre&gt;&lt;/blockquote&gt;
	&lt;t&gt;&lt;t&gt;
	&lt;p&gt;
		funzionare funziona… avete risolto un problema e ve ne siete creati altri 2, figo:&lt;/p&gt;
	&lt;ul&gt;
		&lt;li&gt;
			se l’engine deve poter essere mandato in esecuzione anche senza la configurazione il metodo Excute lo dovete lasciare anche su FluentEngine pagando lo scotto di dover:
			&lt;ul&gt;
				&lt;li&gt;
					o duplicare l’implementazione di Execute;&lt;/li&gt;
				&lt;li&gt;
					o introdurre una terza classe per gestire l’esecuzione;&lt;/li&gt;
			&lt;/ul&gt;
		&lt;/li&gt;
		&lt;li&gt;
			dovete preoccuparvi del mantenimento dello stato nel passaggio da una classe all’altra, e il nostro esempio è triviale in questo senso ma complicarsi la vita è &lt;em&gt;moltissimo facilissimo&lt;/em&gt;;&lt;/li&gt;
	&lt;/ul&gt;
	&lt;p&gt;
		Possiamo quindi asserire che non va bene :-) In realtà la soluzione è molto ma molto più semplice e l’abbiamo sotto gli occhi tutte le volte che usiamo una Fluent Interface fatta come si deve: &lt;em&gt;interface…&lt;/em&gt; appunto :-)&lt;/p&gt;
	&lt;p&gt;
		&lt;strong&gt;Desiderata&lt;/strong&gt;&lt;/p&gt;
	&lt;p&gt;
		Definiamo quello di cui abbiamo bisogno:&lt;/p&gt;
	&lt;blockquote&gt;
		&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;interface &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IConfiguredFluentEngine&lt;/span&gt;&lt;t&gt;
{
    &lt;span style="color: #2b91af"&gt;IFluentEngine&lt;/span&gt;&lt;t&gt; Execute();
}

&lt;span style="color: blue"&gt;interface &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IFluentEngine&lt;/span&gt;&lt;t&gt;&lt;span style="color: #2b91af"&gt;
&lt;/span&gt;{
    &lt;span style="color: #2b91af"&gt;IFluentEngine&lt;/span&gt;&lt;t&gt; Execute();
    &lt;span style="color: #2b91af"&gt;IConfiguredFluentEngine&lt;/span&gt;&lt;t&gt; Configure();
}&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/pre&gt;&lt;/blockquote&gt;
	&lt;t&gt;&lt;t&gt;&lt;t&gt;&lt;t&gt;&lt;t&gt;
	&lt;p&gt;
		e modifichiamo l’entry point di conseguenza:&lt;/p&gt;
	&lt;blockquote&gt;
		&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;static class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MyFluentEntryPoint
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;public static &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IFluentEngine&lt;/span&gt;&lt;t&gt; Having&lt;t&gt;( T value )
    {
        &lt;span style="color: blue"&gt;return new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;FluentEngine&lt;/span&gt;&lt;t&gt;( value );
    }
}&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/pre&gt;&lt;/blockquote&gt;
	&lt;t&gt;&lt;t&gt;&lt;t&gt;
	&lt;p&gt;
		A questo punto non ci resta che fare la cosa più banale di tutte: implementare tutte i contratti sulla stessa classe:&lt;/p&gt;
	&lt;blockquote&gt;
		&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;FluentEngine&lt;/span&gt;&lt;t&gt; : &lt;span style="color: #2b91af"&gt;IFluentEngine&lt;/span&gt;&lt;t&gt;, &lt;span style="color: #2b91af"&gt;IConfiguredFluentEngine&lt;/span&gt;&lt;t&gt;
{
    &lt;span style="color: blue"&gt;readonly &lt;/span&gt;T value;

    &lt;span style="color: blue"&gt;public &lt;/span&gt;FluentEngine( T value )
    {
        &lt;span style="color: blue"&gt;this&lt;/span&gt;.value = value;
    }

    &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IConfiguredFluentEngine&lt;/span&gt;&lt;t&gt; Configure()
    {
        &lt;span style="color: blue"&gt;return this&lt;/span&gt;;
    }

    &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IFluentEngine&lt;/span&gt;&lt;t&gt; Execute()
    {
        &lt;span style="color: blue"&gt;return this&lt;/span&gt;;
    }
}&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/pre&gt;&lt;/blockquote&gt;
	&lt;t&gt;&lt;t&gt;&lt;t&gt;&lt;t&gt;&lt;t&gt;
	&lt;p&gt;
		garantendoci questo:&lt;/p&gt;
	&lt;p&gt;
		&lt;a href="https://lh6.googleusercontent.com/-U3-B4plZIcM/TzJyYSmOkkI/AAAAAAAABHs/UVgKJzVMfbs/d5459732-5914-4787-bf12-6c65351a4f7e.png" rel="shadowbox"&gt;&lt;img alt="image" border="0" height="154" src="https://lh5.googleusercontent.com/-7gRDtFP-bMw/TzJyXZ2ZTrI/AAAAAAAABHo/TOZlPbtFjXg/c67a4429-afed-4cb3-ac4f-c80ca267f70b.png" style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" width="244"&gt;&lt;/a&gt;&lt;/p&gt;
	&lt;p&gt;
		è ovvio che se complichiamo/estendiamo/necessitiamo di dare al developer una experience più corposa le cose si complicano e non di poco, ma il concetto resta sempre lo stesso: una singola classe che implementa contratti diversi, del resto la vostra necessità in questo caso è “semplicemente” ingannare l’intellisense :-)&lt;/p&gt;
	&lt;p&gt;
		&lt;em&gt;Non è tutto… stay tuned.&lt;/em&gt;&lt;/p&gt;
	&lt;p&gt;
		.m&lt;/p&gt;
	&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/span&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6511237790974218081-3511359177506965381?l=mauroservienti.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/_DlRQVQwWTAc7JmMhgwJOzXBg-Q/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/_DlRQVQwWTAc7JmMhgwJOzXBg-Q/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/_DlRQVQwWTAc7JmMhgwJOzXBg-Q/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/_DlRQVQwWTAc7JmMhgwJOzXBg-Q/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/tpx/~4/ZWc58zVxIKM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mauroservienti.blogspot.com/feeds/3511359177506965381/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/fluentlydesignme-inganniamo.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/3511359177506965381?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/3511359177506965381?v=2" /><link rel="alternate" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/fluentlydesignme-inganniamo.html" title="Fluently.Design().Me: inganniamo l’intellisense :-)" /><author><name>Mauro Servienti</name><uri>http://www.blogger.com/profile/10629055661352952427</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="23" height="32" src="http://3.bp.blogspot.com/-dm7TXYKMYyw/Tx6n9k3EMZI/AAAAAAAAAII/dqd_n1UdKsI/s220/Avatar.JPG" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lh4.googleusercontent.com/-h5rDeLv1FD8/TzJyUEgZvCI/AAAAAAAABG4/8ZNbM7PAI_c/s72-c/03b2c6db-e678-48b4-8ea8-931e1686d511.png" height="72" width="72" /><thr:total>3</thr:total></entry><entry gd:etag="W/&quot;DEYGR34_fSp7ImA9WhRbF00.&quot;"><id>tag:blogger.com,1999:blog-6511237790974218081.post-3165371633605505277</id><published>2010-01-20T10:33:00.000+01:00</published><updated>2012-02-08T14:02:06.045+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-08T14:02:06.045+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="WPF" /><category scheme="http://www.blogger.com/atom/ns#" term="Software Mason" /><category scheme="http://www.blogger.com/atom/ns#" term="Attached Properties" /><category scheme="http://www.blogger.com/atom/ns#" term="Behavior" /><title>Behavior vs Attached Property #2</title><content type="html">&lt;span&gt;Vorrei sottolineare un’altra differenza non da poco tra Behavior e Attached Property, oltre a quelle di cui ho &lt;a href="https://www.blogger.com/feeds/6511237790974218081/posts/default/6762931204738498267" target="_blank"&gt;già parlato&lt;/a&gt;, e che &lt;a href="http://blogs.ugidotnet.org/corrado"&gt;Corrado&lt;/a&gt; nei commenti ha integrato.&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Una Attached Property, in quanto &lt;u&gt;proprietà&lt;/u&gt;, necessita che venga &lt;em&gt;settato&lt;/em&gt; un valore al fine di “attivarla”, mentre un Behavior, in quanto &lt;u&gt;comportamento&lt;/u&gt;, è molto più simile ad un metodo e, &lt;a href="https://www.blogger.com/feeds/6511237790974218081/posts/default/7672574535407411798" target="_blank"&gt;come evidenziato&lt;/a&gt;, non è necessario &lt;em&gt;nulla&lt;/em&gt; perchè venga attivato:&lt;/span&gt;&lt;br&gt;  &lt;blockquote&gt;   &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;TextBox &lt;/span&gt;&lt;span style="color: red"&gt;Height&lt;/span&gt;&lt;span style="color: blue"&gt;="23" &lt;/span&gt;&lt;span style="color: red"&gt;Text&lt;/span&gt;&lt;span style="color: blue"&gt;="{&lt;/span&gt;&lt;span style="color: #a31515"&gt;Binding &lt;/span&gt;&lt;span style="color: red"&gt;DataSource&lt;/span&gt;&lt;span style="color: blue"&gt;.&lt;/span&gt;&lt;span style="color: red"&gt;StreetNumber&lt;/span&gt;&lt;span style="color: blue"&gt;}"&lt;/span&gt;&lt;span style="color: blue"&gt;&gt;
    &lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;i&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;Interaction.Behaviors&lt;/span&gt;&lt;span style="color: blue"&gt;&gt;
        &lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;behaviors&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;DisableUndoManagerBehavior &lt;/span&gt;&lt;span style="color: blue"&gt;/&gt;
    &lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;i&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;Interaction.Behaviors&lt;/span&gt;&lt;span style="color: blue"&gt;&gt;
&lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;TextBox&lt;/span&gt;&lt;span style="color: blue"&gt;&gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/blockquote&gt;

&lt;span&gt;Un discreto vantaggio :-)&lt;/span&gt;&lt;br&gt;

&lt;span&gt;.m&lt;/span&gt;&lt;br&gt;

&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6511237790974218081-3165371633605505277?l=mauroservienti.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/JQAC0lc8kRg6FuPUKoFDarWqhKc/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/JQAC0lc8kRg6FuPUKoFDarWqhKc/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/JQAC0lc8kRg6FuPUKoFDarWqhKc/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/JQAC0lc8kRg6FuPUKoFDarWqhKc/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/tpx/~4/ZCrJywXkzqE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mauroservienti.blogspot.com/feeds/3165371633605505277/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/behavior-vs-attached-property-2.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/3165371633605505277?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/3165371633605505277?v=2" /><link rel="alternate" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/behavior-vs-attached-property-2.html" title="Behavior vs Attached Property #2" /><author><name>Mauro Servienti</name><uri>http://www.blogger.com/profile/10629055661352952427</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="23" height="32" src="http://3.bp.blogspot.com/-dm7TXYKMYyw/Tx6n9k3EMZI/AAAAAAAAAII/dqd_n1UdKsI/s220/Avatar.JPG" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DEYGRHg6fyp7ImA9WhRbF00.&quot;"><id>tag:blogger.com,1999:blog-6511237790974218081.post-8648847395517022010</id><published>2010-01-20T09:17:00.000+01:00</published><updated>2012-02-08T14:02:05.617+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-08T14:02:05.617+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Memento" /><title>Atomicità: ad ognuno la sua :-)</title><content type="html">&lt;span&gt;L’utente ha il suo concetto di atomicità, il developer ha il suo…&lt;/span&gt;&lt;br&gt;  &lt;span&gt;&lt;strong&gt;Utente 1 – Developer 0&lt;/strong&gt;&lt;/span&gt;&lt;br&gt;  &lt;span&gt;&lt;a href="https://lh4.googleusercontent.com/-9DSVmbNsOEM/TzJyTDt55CI/AAAAAAAABGs/YWSiD8PR77A/f9a199f3-90d8-471b-9f21-3e9149d9e38d.png" rel="shadowbox"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="https://lh4.googleusercontent.com/-UZ5rU3Lf5zQ/TzJySpxj5jI/AAAAAAAABGo/KOy3_t9wgJ4/2293e5d2-e7a1-4dd8-ba1d-2912db9cdbe2.png" width="244" height="214"&gt;&lt;/a&gt; &lt;/span&gt;&lt;br&gt;  &lt;span&gt;L’utente crea un nuovo “Calendario”, poco importa cosa sia, diciamo che è un master-detail decisamente classico. Poi, dopo averlo creato, lo organizza come meglio crede e una delle cose che fa è rimuovere le pubblicazioni che non ci saranno, ad esempio quelle del mese di Agosto.&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Quello che succede è:&lt;/span&gt;&lt;br&gt;  &lt;ul&gt;   &lt;li&gt;Uno degli elementi viene rimosso dalla lista; &lt;/li&gt;    &lt;li&gt;Tutti gli elementi successivi a quello rimosso vengono modificati per aggiornare, tra le tante, il “numero” dell’Uscita; &lt;/li&gt; &lt;/ul&gt;  &lt;span&gt;Poi… cambia idea e fa un bel sano “Undo” :-)&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Quello che per noi sono &lt;em&gt;n&lt;/em&gt; operazioni per l’utente corrispondono ad una sola operazione, quindi il livello di atomicità è diverso e naturalmente &lt;em&gt;vince&lt;/em&gt; l’utente. Quindi il &lt;a href="/search/label/Memento" target="_blank"&gt;nostro memento&lt;/a&gt; deve supportare una cosa come questa:&lt;/span&gt;&lt;br&gt;  &lt;blockquote&gt;   &lt;pre class="code"&gt;[&lt;span style="color: #2b91af"&gt;TestMethod&lt;/span&gt;]
&lt;span style="color: blue"&gt;public void &lt;/span&gt;changeTrackingService_atomicOperation_should_set_isChanged_only_on_operation_completed()
{
    &lt;span style="color: blue"&gt;var &lt;/span&gt;target = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ChangeTrackingService&lt;/span&gt;();

    &lt;span style="color: blue"&gt;var &lt;/span&gt;person = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Person&lt;/span&gt;( target );
    &lt;span style="color: blue"&gt;var &lt;/span&gt;list = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;PersonCollection&lt;/span&gt;( target );

    &lt;span style="color: blue"&gt;using&lt;/span&gt;( &lt;span style="color: blue"&gt;var &lt;/span&gt;actual = target.BeginAtomicOperation() )
    {
        person.Name = &lt;span style="color: #a31515"&gt;"Mauro"&lt;/span&gt;;
        list.Add( person );
        person.Name = &lt;span style="color: #a31515"&gt;"Mauro Servienti"&lt;/span&gt;;

        target.IsChanged.ShouldBeFalse();

        actual.Complete();
    }

    target.IsChanged.ShouldBeTrue();
}

[&lt;span style="color: #2b91af"&gt;TestMethod&lt;/span&gt;]
&lt;span style="color: blue"&gt;public void &lt;/span&gt;changeTrackingService_using_atomicOperation_should_fully_rollback_using_one_undo()
{
    &lt;span style="color: blue"&gt;var &lt;/span&gt;target = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ChangeTrackingService&lt;/span&gt;();

    &lt;span style="color: blue"&gt;var &lt;/span&gt;person = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Person&lt;/span&gt;( target );
    &lt;span style="color: blue"&gt;var &lt;/span&gt;list = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;PersonCollection&lt;/span&gt;( target );

    &lt;span style="color: blue"&gt;using&lt;/span&gt;( &lt;span style="color: blue"&gt;var &lt;/span&gt;actual = target.BeginAtomicOperation() )
    {
        person.Name = &lt;span style="color: #a31515"&gt;"Mauro"&lt;/span&gt;;
        list.Add( person );
        person.Name = &lt;span style="color: #a31515"&gt;"Mauro Servienti"&lt;/span&gt;;

        actual.Complete();
    }

    target.Undo();

    list.Count.ShouldBeEqualTo( 0 );
    person.Name.ShouldBeEqualTo( &lt;span style="color: #2b91af"&gt;String&lt;/span&gt;.Empty );
}&lt;/pre&gt;
  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/blockquote&gt;

&lt;span&gt;e naturalmente questa, un filino più complessa:&lt;/span&gt;&lt;br&gt;

&lt;blockquote&gt;
  &lt;pre class="code"&gt;[&lt;span style="color: #2b91af"&gt;TestMethod&lt;/span&gt;]
&lt;span style="color: blue"&gt;public void &lt;/span&gt;changeTrackingService_using_atomicOperation_redo_should_reapply_all_changes_with_one_pass()
{
    &lt;span style="color: blue"&gt;var &lt;/span&gt;target = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ChangeTrackingService&lt;/span&gt;();

    &lt;span style="color: blue"&gt;var &lt;/span&gt;person = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Person&lt;/span&gt;( target );
    &lt;span style="color: blue"&gt;var &lt;/span&gt;list = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;PersonCollection&lt;/span&gt;( target );

    &lt;span style="color: blue"&gt;using&lt;/span&gt;( &lt;span style="color: blue"&gt;var &lt;/span&gt;actual = target.BeginAtomicOperation() )
    {
        person.Name = &lt;span style="color: #a31515"&gt;"Mauro"&lt;/span&gt;;
        list.Add( person );
        person.Name = &lt;span style="color: #a31515"&gt;"Mauro Servienti"&lt;/span&gt;;

        actual.Complete();
    }

    target.Undo();
    target.Redo();

    list.Count.ShouldBeEqualTo( 1 );
    person.Name.ShouldBeEqualTo( &lt;span style="color: #a31515"&gt;"Mauro Servienti" &lt;/span&gt;);
}&lt;/pre&gt;
  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/blockquote&gt;

&lt;span&gt;Tutti i test passano, e sono stati frutto della &lt;a href="https://www.blogger.com/feeds/6511237790974218081/posts/default/6903117572790280786" target="_blank"&gt;mia esternazione :-)&lt;/a&gt;, il secondo è, per ora, frutto di un hack che mi piace decisamente poco, uno &lt;em&gt;special case&lt;/em&gt; interno al motore di Change Tracking.&lt;/span&gt;&lt;br&gt;

&lt;span&gt;&lt;em&gt;Utente 1 – Developer 1: palla al centro :-)&lt;/em&gt;&lt;/span&gt;&lt;br&gt;

&lt;span&gt;Questo però, fortunatamente o meno per voi :-), mi ha ricordato che abbiamo &lt;a href="/search/label/Memento" target="_blank"&gt;qualcosa in sospeso&lt;/a&gt;: date tempo al tempo ;-)&lt;/span&gt;&lt;br&gt;

&lt;span&gt;.m&lt;/span&gt;&lt;br&gt;

&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6511237790974218081-8648847395517022010?l=mauroservienti.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/_SrFc39WwR1PGke3stAjdSR3EZs/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/_SrFc39WwR1PGke3stAjdSR3EZs/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/_SrFc39WwR1PGke3stAjdSR3EZs/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/_SrFc39WwR1PGke3stAjdSR3EZs/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/tpx/~4/lPvwaljbhTs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mauroservienti.blogspot.com/feeds/8648847395517022010/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/atomicita-ad-ognuno-la-sua.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/8648847395517022010?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/8648847395517022010?v=2" /><link rel="alternate" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/atomicita-ad-ognuno-la-sua.html" title="Atomicità: ad ognuno la sua :-)" /><author><name>Mauro Servienti</name><uri>http://www.blogger.com/profile/10629055661352952427</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="23" height="32" src="http://3.bp.blogspot.com/-dm7TXYKMYyw/Tx6n9k3EMZI/AAAAAAAAAII/dqd_n1UdKsI/s220/Avatar.JPG" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lh4.googleusercontent.com/-UZ5rU3Lf5zQ/TzJySpxj5jI/AAAAAAAABGo/KOy3_t9wgJ4/s72-c/2293e5d2-e7a1-4dd8-ba1d-2912db9cdbe2.png" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DEYFSHg7cCp7ImA9WhRbF00.&quot;"><id>tag:blogger.com,1999:blog-6511237790974218081.post-7672574535407411798</id><published>2010-01-20T08:35:00.000+01:00</published><updated>2012-02-08T14:01:59.608+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-08T14:01:59.608+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Software Mason" /><category scheme="http://www.blogger.com/atom/ns#" term="BUG" /><category scheme="http://www.blogger.com/atom/ns#" term="TextBox.UndoLimit" /><title>Wpf TextBox.UndoLimit “sbomba” by design :-)</title><content type="html">&lt;span&gt;… che a casa mia si chiama BUG, e come tale è &lt;a href="http://social.msdn.microsoft.com/forums/en-US/wpf/thread/c6d9bca4-7832-4816-be94-a8e8f6e32007/" target="_blank"&gt;riconosciuto&lt;/a&gt;.&lt;/span&gt;&lt;br&gt;  &lt;span&gt;&lt;strong&gt;Un po’ di storia&lt;/strong&gt;&lt;/span&gt;&lt;br&gt;  &lt;span&gt;Se cercate di fare questo:&lt;/span&gt;&lt;br&gt;  &lt;blockquote&gt;   &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;TextBox &lt;/span&gt;&lt;span style="color: red"&gt;UndoLimit&lt;/span&gt;&lt;span style="color: blue"&gt;="0" &lt;/span&gt;&lt;span style="color: red"&gt;Text&lt;/span&gt;&lt;span style="color: blue"&gt;="{&lt;/span&gt;&lt;span style="color: #a31515"&gt;Binding &lt;/span&gt;&lt;span style="color: red"&gt;DataSource&lt;/span&gt;&lt;span style="color: blue"&gt;.&lt;/span&gt;&lt;span style="color: red"&gt;Zone&lt;/span&gt;&lt;span style="color: blue"&gt;, ...&lt;/span&gt;&lt;/pre&gt;
  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/blockquote&gt;

&lt;span&gt;con lo scopo di disabilitare il supporto per l’Undo offerto da Wpf, vi beccate una sonora exception “&lt;em&gt;Cannot use UndoService while it is disabled&lt;/em&gt;”… l’inghippo è che quella cosa sbomba da paura a runtime se avete impostato un Binding sulla proprietà Text. Lo snippet qui sotto, grabbato con Reflector, spiega molto bene il problema:&lt;/span&gt;&lt;br&gt;

&lt;span&gt;&lt;a href="https://lh3.googleusercontent.com/-Ps1vQA-nlq4/TzJyODV0lKI/AAAAAAAABFs/DtJhXLvBqN0/5cdfefb8-3da6-420a-857b-f2e376dbd595.png" rel="shadowbox"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="https://lh5.googleusercontent.com/-_YmwfjLPclk/TzJyNpkcKqI/AAAAAAAABFo/7yilo05wJk8/7f7f4192-51f9-460e-9afe-c2157ed68dec.png" width="244" height="44"&gt;&lt;/a&gt;&lt;/span&gt;&lt;br&gt;

&lt;span&gt;Quella chiamata a Clear() scoppia perchè avete impostato UndoLimit a “0” disabilitando di fatto l’UndoManager. &lt;/span&gt;&lt;br&gt;

&lt;span&gt;&lt;strong&gt;Possibili Workaround&lt;/strong&gt;&lt;/span&gt;&lt;br&gt;

&lt;span&gt;San Google propone una serie di possibili soluzioni:&lt;/span&gt;&lt;br&gt;

&lt;span&gt;&lt;a href="https://lh5.googleusercontent.com/-YGm1Q6ddk2k/TzJyPBkGnkI/AAAAAAAABGA/JZRDNsbC2qY/db03419e-eca5-4eb1-be6a-89d52fe8d210.png" rel="shadowbox"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="https://lh5.googleusercontent.com/-zuYIQoNO5aQ/TzJyOVpVHTI/AAAAAAAABF0/fK3F5_XCd9o/b03a0bd1-0aa1-4d9c-81d8-afc6f7b154dd.png" width="244" height="85"&gt;&lt;/a&gt; 

  &lt;br&gt;&lt;font size="1"&gt;(&lt;/font&gt;&lt;a href="http://infosysblogs.com/microsoft/2008/03/wpf_textbox_memory_leak_issue_1.html" target="_blank"&gt;&lt;font size="1"&gt;fonte&lt;/font&gt;&lt;/a&gt;&lt;font size="1"&gt;)&lt;/font&gt;&lt;/span&gt;&lt;br&gt;

&lt;span&gt;Come lo stesso autore dice, non funziona :-), e ne &lt;a href="http://www.infosysblogs.com/microsoft/2008/03/wpf_textbox_memory_issue.html" target="_blank"&gt;propone un’altra&lt;/a&gt;:&lt;/span&gt;&lt;br&gt;

&lt;span&gt;&lt;a href="https://lh3.googleusercontent.com/-d23oMOzgpFQ/TzJyQY2DbPI/AAAAAAAABGM/u7hfzJK6Cs0/7d4c74c3-ef1e-49d1-a454-2841ddcb2176.png" rel="shadowbox"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="https://lh5.googleusercontent.com/-gw8QmTnPlT4/TzJyP9Sb6sI/AAAAAAAABGE/EEDc9EwTH50/227075ec-1f13-41b3-b99e-0b2af22f3fc8.png" width="244" height="55"&gt;&lt;/a&gt; &lt;/span&gt;&lt;br&gt;

&lt;span&gt;Ma sinceramente a me non va neanche questa, nonostante in molti siano decisamente soddisfatti, non ho errori semplicemente non succede nulla.&lt;/span&gt;&lt;br&gt;

&lt;span&gt;Un terzo, fallimentare tentativo, è stato creare una Attached Property che impostasse l’UndoLimit dopo l’evento Loaded, perchè alla fine il problema sta proprio li, ma anche questo fallisce perchè in fase di Unload del controllo la proprietà Text viene resettata e quindi il codice cerca di fare nuovamente il reset (&lt;em&gt;Clear()&lt;/em&gt;) dell’UndoManager.&lt;/span&gt;&lt;br&gt;

&lt;span&gt;Alla fine, partendo da un &lt;a href="http://social.msdn.microsoft.com/forums/en-US/wpf/thread/a4476d22-bf5e-4ca4-969e-7bffb8564277/" target="_blank"&gt;hint trovato sui Microsoft Forum&lt;/a&gt;, la &lt;u&gt;pezza&lt;/u&gt; definitiva è questo Behavior:&lt;/span&gt;&lt;br&gt;

&lt;blockquote&gt;
  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public sealed class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;DisableUndoManagerBehavior &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;Behavior&lt;/span&gt;&lt;&lt;span style="color: #2b91af"&gt;TextBox&lt;/span&gt;&gt;
{
    &lt;span style="color: blue"&gt;protected override void &lt;/span&gt;OnAttached()
    {
        &lt;span style="color: blue"&gt;base&lt;/span&gt;.OnAttached();

        &lt;span style="color: blue"&gt;var &lt;/span&gt;cb = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;CommandBinding&lt;/span&gt;();
        cb.Command = &lt;span style="color: #2b91af"&gt;ApplicationCommands&lt;/span&gt;.Undo;
        cb.CanExecute += ( s, e ) =&gt; e.CanExecute = &lt;span style="color: blue"&gt;this&lt;/span&gt;.AssociatedObject.IsFocused;
        cb.Executed += ( s, e ) =&gt; e.Handled = &lt;span style="color: blue"&gt;true&lt;/span&gt;;

        &lt;span style="color: blue"&gt;this&lt;/span&gt;.AssociatedObject.CommandBindings.Add( cb );
    }
}&lt;/pre&gt;
  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/blockquote&gt;

&lt;span&gt;che utilizzato così:&lt;/span&gt;&lt;br&gt;

&lt;blockquote&gt;
  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;TextBox &lt;/span&gt;&lt;span style="color: red"&gt;Text&lt;/span&gt;&lt;span style="color: blue"&gt;="{&lt;/span&gt;&lt;span style="color: #a31515"&gt;Binding &lt;/span&gt;&lt;span style="color: red"&gt;DataSource&lt;/span&gt;&lt;span style="color: blue"&gt;.&lt;/span&gt;&lt;span style="color: red"&gt;Zone&lt;/span&gt;&lt;span style="color: blue"&gt;}"&lt;/span&gt;&lt;span style="color: blue"&gt;&gt;
    &lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;i&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;Interaction.Behaviors&lt;/span&gt;&lt;span style="color: blue"&gt;&gt;
        &lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;behaviors&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;DisableUndoManagerBehavior &lt;/span&gt;&lt;span style="color: blue"&gt;/&gt;
    &lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;i&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;Interaction.Behaviors&lt;/span&gt;&lt;span style="color: blue"&gt;&gt;
&lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;TextBox&lt;/span&gt;&lt;span style="color: blue"&gt;&gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/blockquote&gt;

&lt;span&gt;produce l’effetto desiderato, in realtà l’UndoManager non viene disabilitato ma semplicemente &lt;em&gt;reso innoquo&lt;/em&gt;.&lt;/span&gt;&lt;br&gt;

&lt;span&gt;&lt;strong&gt;…e Wpf 4.0?&lt;/strong&gt;&lt;/span&gt;&lt;br&gt;

&lt;span&gt;Funziona come si deve senza costringerci a fare i salti mortali, e il fido Reflector conferma:&lt;/span&gt;&lt;br&gt;

&lt;span&gt;&lt;a href="https://lh5.googleusercontent.com/-JT8SA88zow8/TzJyRXLNkUI/AAAAAAAABGc/c5QhbfWms98/ac70ce41-764a-4e30-b83a-fc705d0d2a63.png" rel="shadowbox"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="https://lh5.googleusercontent.com/-AQp_zWYSUT4/TzJyQ-ivUcI/AAAAAAAABGU/eSACKYIJaXw/7024be90-a95e-488b-801f-2a4539ef4310.png" width="244" height="74"&gt;&lt;/a&gt; &lt;/span&gt;&lt;br&gt;

&lt;span&gt;Vi chiederete… perchè devi disabilitare il suppporto per l’Undo? perchè se avete un &lt;a href="/search/label/Memento" target="_blank"&gt;vostro motore&lt;/a&gt; per gestire il change tracking… ;-)&lt;/span&gt;&lt;br&gt;

&lt;span&gt;.m&lt;/span&gt;&lt;br&gt;





&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6511237790974218081-7672574535407411798?l=mauroservienti.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/7RLT5fA5ofrY6Xoy__Lp3hFOtWQ/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/7RLT5fA5ofrY6Xoy__Lp3hFOtWQ/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/7RLT5fA5ofrY6Xoy__Lp3hFOtWQ/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/7RLT5fA5ofrY6Xoy__Lp3hFOtWQ/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/tpx/~4/hcJzFauzpWg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://mauroservienti.blogspot.com/feeds/7672574535407411798/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/wpf-textboxundolimit-sbomba-by-design.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/7672574535407411798?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6511237790974218081/posts/default/7672574535407411798?v=2" /><link rel="alternate" type="text/html" href="http://mauroservienti.blogspot.com/2010/01/wpf-textboxundolimit-sbomba-by-design.html" title="Wpf TextBox.UndoLimit “sbomba” by design :-)" /><author><name>Mauro Servienti</name><uri>http://www.blogger.com/profile/10629055661352952427</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="23" height="32" src="http://3.bp.blogspot.com/-dm7TXYKMYyw/Tx6n9k3EMZI/AAAAAAAAAII/dqd_n1UdKsI/s220/Avatar.JPG" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lh5.googleusercontent.com/-_YmwfjLPclk/TzJyNpkcKqI/AAAAAAAABFo/7yilo05wJk8/s72-c/7f7f4192-51f9-460e-9afe-c2157ed68dec.png" height="72" width="72" /><thr:total>0</thr:total></entry></feed>

