{"id":1004,"date":"2010-10-05T00:00:00","date_gmt":"2010-10-05T00:00:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/one-application-in-both-wpf-and-silverlight\/"},"modified":"2021-05-17T18:36:30","modified_gmt":"2021-05-17T18:36:30","slug":"one-application-in-both-wpf-and-silverlight","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/development\/dotnet-development\/one-application-in-both-wpf-and-silverlight\/","title":{"rendered":"One application in both WPF and Silverlight"},"content":{"rendered":"<div id=\"pretty\">\n<p class=\"start\">There seems to be lots of interest in porting Windows Presentation Foundation (WPF) and WinForms application to Silverlight, and occasionally from Silverlight applications to WPF as well. \u00a0Because of this, I wanted to see how feasible it was to maintain the bulk of my code in a single code-base, and provide just the code- glue to support the framework. \u00a0I happened to have a cool looking erlight application, so I decided to convert this to WPF in the hope that it would give me an insight to the tasks of porting between the two frameworks. It did.<\/p>\n<p>I had to come to terms with the reality that one cannot hope or expect to share 100% of the code base by merely inserting conditional compilation preprocessor directives in any application more complex than the&#8217; Hello World&#8217; application.\u00a0<\/p>\n<h1>First Magic Ingredient: Preprocessor Directives<\/h1>\n<p>Preprocessor directives are the basic way of \u00a0maintaining\u00a0 a single code base, whilst porting to WPF , WinForms and Silverlight.\u00a0 Preprocessor directives are basically just conditional statements within your code.\u00a0 They are different from the regular conditional statements in a sense that\u00a0 they don&#8217;t execute at run time.\u00a0 They are interpreted by the compiler before it performs the compilation passes.\u00a0 If a block of code is in a conditional statement that returns true, then that block will get compiled: If it returns false, then that block of code doesn&#8217;t get compiled.\u00a0 For example, In the following code I am telling the compiler that if the code file that is being compiled is in a Silverlight project then compile this section of the code otherwise compile the other section of the code that would be used with regular .net applications such as WinForms, or WPF.<\/p>\n<pre class=\"lang:c# theme:vs2012\">#if SILVERLIGHT \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 IPopupWindow popWindow = new ChildWindowEx(); \r\n#else \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 IpopupWindow popWindow = new WPFPopupWindowEx(); \r\n#endif\u00a0 \r\n<\/pre>\n<p>Visual Studio is very smart when it comes to conditional preprocessor directives.\u00a0 It will automatically gray out the inapplicable code block based on the condition.\u00a0 For example, if this code was part of the Silverlight project then the <b>else<\/b> block will automatically be grayed out.<\/p>\n<h1>Second Magic Ingredient: Linking to a file<\/h1>\n<p>The second Magic Ingredient is linking files within projects.\u00a0 We are all used to right clicking the project <i>file -&gt; Add -&gt; New Item&#8230;<\/i> to add a new item of course: But if you look right below that, there is another option that says &#8220;<i>Existing Item&#8230;&#8221;.<\/i>\u00a0 Now you can click that and select a file from your WPF project to share in the\u00a0 Silverlight port of that project.\u00a0 However, that isn&#8217;t really what we want, because it creates a copy of that file into the Silverlight project.\u00a0 But if you click the drop arrow of that Add split button on the &#8220;<i>Add Existing Item<\/i>&#8221; dialog, instead of clicking the add button, then you will reveal another option of &#8220;<i>Add as a Link<\/i>&#8220;: That is the one you want to click.\u00a0 That will just create a short cut of that file in your current project.\u00a0 If you combine this technique with preprocessor directives you can then share code between two different projects targeted for two different platforms.\u00a0<\/p>\n<h1>Maintaining the balance:<\/h1>\n<p>When you are aiming to achieve a single code base, you shouldn&#8217;t compromise your code readability. You will always come across a code file where no common code would be possible.\u00a0 This code would become unreadable if you just used conditional compilation.\u00a0 If we are using single code base to make applications more maintainable then this would defeat the purpose. We&#8217;re aiming to decrease the time to update or make changes to applications, and to reduce bugs by sharing the same logic. If the code isn&#8217;t readable then, for sure, it will not be easy to maintain. On the contrary, it will take more time to make changes.\u00a0<\/p>\n<p>So in the case where a file has a considerable difference between platforms there are two possible solutions.<\/p>\n<ul>\n<li>You could split the file into two.\u00a0 One half will contain the code (logic) common to both, which will be easily shared between the two platforms, and the other half will have a version for each platform.<\/li>\n<li>You could subclass the original file and create two separate versions of the derived class one for each platform.<\/li>\n<\/ul>\n<p>Which approach you use depends on which method provides the best maintainability and portability of the code, both now and in the future.\u00a0 I have used both techniques.<\/p>\n<h1>Other Challenges<\/h1>\n<p>Even though one won&#8217;t be able to share 100% of the code base, we can on average share good 70% if the application is well\u00a0architected. \u00a0<\/p>\n<p>There are ways of increasing the proportion of common code by careful planning. You will, for example, notice if you are going to Silverlight to WPF that there is no <b>ChildWindow<\/b> or <b>BusyIndicator <\/b>classes. \u00a0Both of these classes are very common in Silverlight application. \u00a0One alternative is to use Window class, spawn a new window, in WPF to replace both of those. This is the natural solution in the Windows environment. \u00a0However, if you need exactly the same behavior as in Silverlight for <b>ChildWindow<\/b> and <b>BusyIndicator<\/b> classes, then it&#8217;s actually not that difficult to create those control from scratch in WPF. And if you port between Silverlight and WPF regularly, than it might be good idea to create those controls as they would come handy for future projects. \u00a0For my demonstration I need exactly this <b>ChildWindow<\/b> and <b>BusyIndicato<\/b>r functionality in Silverlight for my WPF conversion, so I ended up creating those controls.<\/p>\n<p>Although you can achieve a lot by bringing the two versions to a common denominator, you may lose functionality if you take this too far. As an example of this, my Silverlight application uses some beautiful transitions between screens. \u00a0Those are custom transition made possible via the projection plane properties in Silverlight. As you know, there is no projection plane in WPF. \u00a0They have something more powerful, which is ViewPort3D. \u00a0So in such cases where the other framework offer better and more powerful options then I think one should not be afraid to deviate a little and take advantage of those. \u00a0In other words, it&#8217;s better to not have the\u00a0conversion\u00a0so exact that the applications are 100% identical if one can exploit the unique features of the platform to make the converted application better than the original. \u00a0In this case I believe that the 3D transitions that I used in\u00a0converted\u00a0WPF application are better than the transitions in the Silverlight application.<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Because Silverlight is a development of Windows Presentation Foundation, and the technologies are so interlinked, it would seem obvious that there would besuch  a high degree of code compatibility that one could then develop an application for both platforms from a common code-base. Khawar describes how it can be done. &hellip;<\/p>\n","protected":false},"author":221882,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143538],"tags":[4143,4229,4178,4838],"coauthors":[],"class_list":["post-1004","post","type-post","status-publish","format-standard","hentry","category-dotnet-development","tag-net","tag-net-framework","tag-bi","tag-silverlight"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1004","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221882"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=1004"}],"version-history":[{"count":5,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1004\/revisions"}],"predecessor-version":[{"id":91119,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1004\/revisions\/91119"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=1004"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=1004"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=1004"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=1004"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}