注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

姑射道人的博客

博客新地址:nixuchen.com

 
 
 

日志

 
 

Reusing Your Existing Silverlight Components With Windows Phone 7  

2013-07-09 10:06:45|  分类: windows phone |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
Using .NET is all about leveraging your code across platforms. That was true with previous versions of Windows Mobile OS and it's true in today's XAML-centric environment. But with Silverlight, a .NET developer must pay special attention to the separation of core logic and UI in order to reuse the most code. By organizing your app into the MVVM, or Model-View-Presenter (aka View-Model) pattern, you'll be able to reuse a surprising amount of code between your Web-based Silverlight apps and your Windows Phone 7 apps. This walkthrough will take a basic Silverlight app and demonstrate how to do just that. 

This tutorial is structured of the article as follows: 


MVVM and Reusing of Code

MVVM Overview

MVVM is an architecture pattern that aims to organize code in three layers: the Model, the View and the ViewModel. There are numerous advantages of doing so, the most important ones being:
  • Separation of GUI logic and application logic. The pattern completely separates the View and the Model, so when changes are made in either, they can be done leaving the other unaffected.
  • Support for unit tests. The application's functionality can fully tested by writing unit tests, minimizing (or removing) the need of UI-based tests.
  • Tool support. The View populated by mock data can be edited in Blend and Visual Studio by designers without modifying other parts of the project.
Another advantage of MVVM - that is often overlooked - is that it enables efficient reusing of the code when porting between Silverlight, Windows Phone 7 (and to some extent, WPF as well). 


Reusing The Code With MVVM

MVVM makes code reuse particularly powerful between Silverlight and WP7 applications thanks to the structuring of its layers. The Model contains the business logic without framework specific details, thus all of it can be shared between the Silverlight and WP7 implementations. If the application's UI logic is identical or similar for both applications, most of (if not all) of the ViewModel layer code can be shared as well. The View, however in most cases is significantly different for the Silverlight and WP7 applications. Even though it is possible to share parts of the View between the two projects, since a web UI is usually very different from a phone UI, doing so usually doesn’t make sense. 

By using MVVM it is thus possible to reuse all of the code of the existing Silverlight application apart from the View. Considering Silverlight web applications and Windows Phone 7 ones call for different user interfaces most of the time, this means that with MVVM one only has to rewrite the UI specific part of the application. 


Reusing Silverlight Components With WP7: An Example

To understand how code can efficiently be reused from an existing Silverlight application when porting to Windows Phone 7, let's walk through a simple example - a savings calculator. 


The Silverlight Application

The Silverlight application in this example is a simple savings calculator which looks like this when running: 

Reusing Your Existing Silverlight Components With Windows Phone 7 - 姑射道人 - 姑射道人的博客

In the application the user has to enter the initial deposited amount, monthly deposit, annual interest rate and number of years to save for. The application then calculates the total deposited amount as well as the final savings with the annually compounded interest added. 

In the application the three layers of the project are structured in three separate projects. The model is a Silverlight 3 class library named SavingsCalculatorModel, the ViewModel is also a SL 3 class library named SavingsCalculatorViewModel and the View (the application to be run) is a SL 4 application named SavindsCalculatorSilverlight. Dependencies are the same one way as in the MVVM pattern: the ViewModel project references the Model and the View project references the ViewModel. 

Having outlined the UI and architecture of the example application, let's take a look at how it's implemented using Silverlight. 


The Model

The model layer is responsible for implementing the business logic. In the case of this savings calculator application this means the responsibility of calculating the savings without and with interest. The code of the model is quite simple, consisting of several properties and the CalculateSavingsmethod which calculates the total deposit and the final savings. The code for this is as follows:

01.public class SavingsCalculatorModel
02.{
03.public int NumberOfYears { getset; }
04. 
05.public double AnnualInterest { getset; }
06. 
07.public double InitialAmount { getset; }
08. 
09.public double MonthlyDeposit { getset; }
10. 
11.public double FinalSavingsWithInterest { getprivate set; }
12. 
13.public double FinalSavingsWithoutInterest { getprivate set; }
14. 
15./// Calculates FinalSavingsWithInterest and FinalSavingsWithoutInterest based on
16./// InitialAmount, NumberOfYears, AnnualInterest and MonthlyDeposit
17.public void CalculateSavings()
18.{
19.// See source for details
20.}
21.}

The View

In the View we display input fields for all of the required details, a button to initiate calculation and the outcomes of this calculation. To do so we'll need to create TextBlock elements for the texts,TextBoxes for the input and a Button for the calculation button. 

The values of the input TextBoxes are data binded to members of the ViewModel. This is done via a two way binding so that changes made by the user are applied on the ViewModel. For example the input field for the annual interest is set up the following way: 
1.<TextBox Text="{Binding InitialAmount, Mode=TwoWay}"/>
We also need to bind the result of the calculations to the view. The results are not to be changed by the user, thus we can use a one way binding (and since this is the default, there's no need to specify the binding mode). 
1.<TextBlock Text="{Binding FinalSavingsWithInterest}" FontWeight="Bold"/>
The final part of setting up the View is forwarding the Click event of the Button to the ViewModel. This is done by commanding - that is relaying commands to the ViewModel. To do so, we need to bind theCommand property of the Button to an ICommand to be exposed on the ViewModel: 
1.<Button Command="{Binding CalculateCommand}"/>
The code for the View can be found in the attached source code in the MainPage.xaml file. 

01.public class SavingsCalculatorViewModel: INotifyPropertyChanged
02.{
03.private SavingsCalculatorModel _model;
04. 
05.public int NumberOfYears
06.{
07.get
08.{
09.return _model.NumberOfYears;
10.}
11.set
12.{
13._model.NumberOfYears = value;
14.}
15.}
16.// Similarly wrapping of  AnnualInterest, InitialAmount, MonthlyDeposit, FinalSavingsWithInterest and FinalSavingsWithoutInterest
17.(...)
18. 
19.public ICommand CalculateCommand
20.{
21.get
22.{
23.return new RelayCommand(CalculateSavings) { IsEnabled = true };
24.}
25.}
26. 
27.private void CalculateSavings()
28.{
29._model.CalculateSavings();
30.RaisePropertyChanged("FinalSavingsWithoutInterest");
31.RaisePropertyChanged("FinalSavingsWithInterest");
32.}
33. 
34.// Constructor initializing the default values and INotifyProperyChanged implementations
35.(...)

The ViewModel

The ViewModel is responsible for gluing the Model and View together. It will have to expose all the properties that the View will bind to and wrap these around the Model. In this example the ViewModel is pretty simple: it acts as wrapper around the model, sets default values on it when initializing and exposes the CalculateCommand command to be triggered when the calculate button is pressed. In the example a simple ICommand implementation is used - Josh Smith's RelayCommand version. The important parts of the ViewModel code are the following: 

01.public class SavingsCalculatorViewModel: INotifyPropertyChanged
02.{
03.private SavingsCalculatorModel _model;
04. 
05.public int NumberOfYears
06.{
07.get
08.{
09.return _model.NumberOfYears;
10.}
11.set
12.{
13._model.NumberOfYears = value;
14.}
15.}
16.// Similarly wrapping of  AnnualInterest, InitialAmount, MonthlyDeposit, FinalSavingsWithInterest and FinalSavingsWithoutInterest
17.(...)
18. 
19.public ICommand CalculateCommand
20.{
21.get
22.{
23.return new RelayCommand(CalculateSavings) { IsEnabled = true };
24.}
25.}
26. 
27.private void CalculateSavings()
28.{
29._model.CalculateSavings();
30.RaisePropertyChanged("FinalSavingsWithoutInterest");
31.RaisePropertyChanged("FinalSavingsWithInterest");
32.}
33. 
34.// Constructor initializing the default values and INotifyProperyChanged implementations
35.(...)

Porting the Silverlight Application to Windows Phone

Now that we've seen how the Silverlight application is constructed, let's look into porting it to Windows Phone 7. We want to maintain the same application logic, but optimize the UI a bit better for the phone to give it a native feel. The ported Windows Phone 7 application will look as follows after we've finished:

Reusing Your Existing Silverlight Components With Windows Phone 7 - 姑射道人 - 姑射道人的博客 


Porting of the Model and ViewModel

Since the business logic hasn't changed, all the code of the model is reused in the WP7 application. In this example, the Model was a Silverlight class library, thus the Windows Phone project simply needs a reference pointing to the model project. 

Our UI requirements are functionally the same as for the Silverlight application, meaning that all of the ViewModel code can also be reused as well - no coding needed so far! 


Porting the View

When porting the view of the application there's not much point in reusing the View of the Silverlight application. On the interface of the phone we'd want a UI that blends in to the WP7 world. We'll need to modify the original View to achieve this. Some of the changes that we're making in the view are as follow: 

  • We want the form to fill most of the phone screen and offer input boxes large enough to be easy to tap. To do so, instead of using the default text style we'll use larger fonts by using the built-inWindows Phone theme resources
    1.<TextBlock Text="Monthly Deposit:" Style="{StaticResource PhoneTextTitle2Style}" />
  • By default when tapping a text input field the user is presented with a keyboard with alphabetical letters on it, forcing the user to switch to numerical ones to enter numbers. To avoid this, let's set the InputScope property on the TextBoxes to Number: 
    1.<TextBox Text="{Binding InitialAmount, Mode=TwoWay}"InputScope="Number"/>
  • Bold text doesn't stand out as much on the phone than it does on the web. To have the final savings value stand out more, let's set its color to be the phone's accent color: 
    1.<TextBlock Text="Final Savings:" Foreground="{StaticResource PhoneAccentBrush}" Style="{StaticResource PhoneTextTitle2Style}"FontWeight="Bold" />
  • Windows Phone doesn't have support for ICommands on input elements, thus we'll have to tap into event triggers and have these triggers forwarded to commands. We'll be using the EventToCommand helper class from MVVM Light to do so. See the Implementing Commanding in a Consistent Way section for more details on this.



Porting Overview

Porting this Silverlight application to Windows Phone proved to be surprisingly easy: we were able to reuse the Model and ViewModel layers of the original application without modification and only had to rewrite the View. However, since a Silverlight application to be run in a browser and that on a phone require different user interfaces, we would have had to make changes to the phone UI in all cases. 

Overall it's safe to say that by having developed the Silverlight example following the MVVM pattern, we were able to port it to Windows Phone 7 by reusing most of its code and only rewriting the Windows Phone user interface specific part - the View.



Download the Code

The solution containing the Model, ViewModel, the Silverlight View and the Windows Phone 7 View can be downloaded from here. To run the Silverlight application, build and run the SavingsCalculatorSilverlight project, for the Windows Phone application build and run the SavingsCalculatorWP7 project. 


Further Thoughts on Code Reuse between Silverlight and Windows Phone

Reusing Parts of the View With UserControls

In the example we didn't reuse any part of the View. The main reason for this was that the XAML of a Silverlight page and that of a Windows Phone page is different, making the sharing of the same XAML not possible. 

However, it is possible to reuse UserControls between Silverlight and Windows Phone applications. This can be done both at assembly level or by referencing the XAML of the UserControl. 


Possible Problems When Reusing Silverlight Components with Windows Phone

Structuring the Silverlight project following the MVVM pattern does not always guarantee that the code will be 100% reusable. If the Silverlight application uses APIs that are not implemented on the Windows Phone 7 Silverlight runtime, the project will not compile for Windows Phone. As Windows Phone 7 runs an extended Silverlight 3 runtime, at the moment this issue is mostly localized to the few new APIs introduced by Silverlight 4. However, when Silverlight 5 for the web is released, this issue will probably be a more important one. 

There are a few workarounds to resolve this, the two most common ones being: 

  • Wrap the Silverlight 4 (or later on, Silverlight 5) specific calls between #if !WINDOWS_PHONE (...) #endif macro definitions. This way they will only be compiled in the Silverlight project as the default Windows Phone project has the WINDOWS_PHONE constant defined.
  • Use partial classes and move the framework version-specific logic into a partial class file only referenced by the Silverlight solution.



Implementing Commanding in a Consistent Way

In the example we've implemented commanding (binding the command of the button to an action in the ViewModel) different for the Silverlight application than for the Windows Phone port. The reason for this was that Windows Phone input controls only have notions of triggers, not commands. We've solved the situation by using the MVVM Light framework's EventToCommand helper class to forward the events invoked by triggers to the commands on the ViewModel. This means that while inside the Silverlight project we've used the following syntax to bind to a command: 
1.<Button Content="Calculate" Command="{Binding CalculateCommand}" />
In Windows Phone on the other hand, we used this syntax:
1.<Button Content="Calculate" xmlns:mvvmlight="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WP7"xmlns:interactivity="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity">
2.<interactivity:Interaction.Triggers>
3.<interactivity:EventTrigger EventName="Click">
4.<mvvmlight:EventToCommand Command="{Binding CalculateCommand}"/>
5.</interactivity:EventTrigger>
6.</interactivity:Interaction.Triggers>
7.</Button>
This situation could have been avoided by using the same MVVM framework for both the Silverlight and WP7 project. In the example simplicity was the key, thus no MVVM framework was used in the Silverlight example. However in a real-world project it's definitely worth using the same framework across the Silverlight and Windows Phone 7 projects to maximize the code reuse. MVVM frameworks supporting both Silverlight and WP7 environments include MVVM LightCaliburn Micro and - to certain extent - Prism (Silverlight and WP7 build). 


Summary

The article has briefly highlighted some key advantages of using MVVM in Silverlight projects and has outlined how structuring a project following the MVVM pattern helps code reuse when porting to Windows Phone. It then gave a walkthrough creating a simple example - a savings calculator - giving a quick overview of how the project is structured. It then explained how to port it to Windows Phone, reusing all of the code except for the UI specific View layer. Finally, it explored some other topics that might be important when reusing Silverlight code on WP7, such as reusing parts of the view, commanding and possible problems. 

Summing it up, the article has shown yet another advantage of structuring Silverlight projects following the MVVM pattern. By doing so it's possible to later port it to Windows Phone 7 only having to rewrite the user interface specific parts of the application.
AttachmentSize
MVVMExample.zip343.66 KB
Published at DZone with permission of its author, Gergely Orosz.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

  评论这张
 
阅读(532)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017