As I work with the two technologies I would like to minimize any code differences I have. Looking at Microsoft, other companies like Telerik (more on them in another post), and CodePlex projects like Caliburn.Micro it seems the evolving best practice is in the title of this post.
References
I searched some, and could not find as much as I would expect on this topic. However, I did find some good posts that mean I don’t have to write as much here
The best post I found for some of the pitfalls is “Silverlight and WPF code reuse pitfalls” by Morten.
Another post that talks more about the strategies for working with both is “Writing WPF/Silverlight compatible code. Table of Contents” by Alan Mendelevich. Note this was based on WPF 3.5 and Silverlight 3 but is still quite valid.
I’m going to blatantly copy Alan’s pattern of having a Table of Contents blog post that organizes all the posts related to my efforts to write WPF and Silverlight compatible code.
My Project
Here are some of the key top level practices I currently have to promote code reuse between Silverlight and WPF.
Solution Folders
I used Solution Folders to keep track of the different presentation tier approaches as shown here.
Same Namespace, Different Project Name
I use the plain namespace for the name of my .NET 4.0 project names and I append .Silverlight on the projects that use Silverlight. However, I use the same namespace for both – which is not the default behavior.
For example, when I created my Zachrys.Heritage.Controls.Silverlight project as a new Silverlight Class Library:
The default namespace on the Properties for the project had Zachrys.Heritage.Controls.Silverlight. I removed the .Silverlight from both the Assembly name and the Default namespace so that the Silverlight tab on the properties for the project looked like this:
This reduces the differences between your .NET and Silverlight codebases.
Add As Link
I had lots of code in some libraries that were already in use for an MVC (Model-View-Controller) web application I’d been working on. As a result of that and my testing strategy (see Testing Strategy below) I put the actual files in the .NET libraries and then add a link to them in my Silverlight libraries. I’ll use the Person.cs file as an example. I have a library called Zachrys.Heritage.Models with a Person class.
In my Silverlight project I right click to add an existing item
Then I navigate to my .NET project and select the Person.cs file. Rather than click “Add” I select the arrow next to Add
and choose Add as Link
In the .NET project the file for my Person.cs file looks like this:
While in my Silverlight project it looks like this:
Note the little black arrow that points up toward the upper right. That indicates it is a link to a file in another folder.
Partial Classes
I started to use some #if statements in my code, for example to keep track of different references which are needed on occasion. However, I Iike Alan Mendelevich’s recommendation of using partial classes instead. For example, instead of this:
- #if !SILVERLIGHT
- [Serializable]
- #endif
- public class Person : PropertyChangedBase, INotifyPropertyChanged, IDataErrorInfo
And with this unit test in place:
- [TestCategory("Build"), TestMethod]
- public void Wpf_Person_Is_Serializable()
- {
- // Arrange
- var person = new Person();
- // Act
- var memberInfo = typeof(Person).GetCustomAttributes(typeof(SerializableAttribute), false);
- // Assert
- var serializeableAttribute = memberInfo[0] as SerializableAttribute;
- Assert.IsNotNull(serializeableAttribute);
- }
I added the Person.Wpf.cs file:
…with this:
- [Serializable]
- public partial class Person
And I get this:
And yes, if I remove the [Serializable] attribute, this unit test will fail. I tried it…
While there are times where the Preprocessor (compiler) directives (the #if statements) make sense, I try to leverage the partial classes first. The primary objective for making that determination is my code coverage.
Testing Strategy
For now, my testing strategy is to unit test my non-Silverlight code. Since my objective is to have virtually all the code identical, then I will still have great code coverage. The primary reason for this approach is that I have not found a way to run my Silverlight tests on my build server. But I can run my non-Silverlight tests.
Summary
I think this covers most of the high level project setup items I needed to do. I have other posts on things like making sure you have x86 set in your build definition for TFS, but this post should cover most of the Visual Studio 2010 setup I did.
Leave a Reply