There’s a number of ways we could implement platform specific code in Windows Universal Apps which I’ll cover in future articles.
In this article we’ll look at an often underused feature of C#: partial classes and methods.
Quick Overview
Partial classes allow us to split the definition of a class over multiple .cs files. The files all contain the same namespace and class names, but the class name is preceded by the partial keyword modifier.
Partial methods allow a method to be defined but that doesn’t contain an implementation, the implementation can then be provided in another partial class file.
(Check out my C# Tips eBook for more info on partial types.)
Using Simple Conditional Compilation Directives
If you want to get an overview of Universal Apps, check out this previous article.
For the sake of this demo, say we have a class “Identity” that displays a message box stating whether we’re in a Windows Store or Phone app.
We could do this using conditional directives:
using System;
using System.Threading.Tasks;
using Windows.UI.Popups;
namespace UsingPartials
{
public class Identity
{
public async Task WhoAmI()
{
string message = CalcMessage();
#if WINDOWS_APP
message = "I'm a Windows Store App!";
#elif WINDOWS_PHONE_APP
message = "I'm a Windows Phone App!";
#endif
var dialog = new MessageDialog(message);
await dialog.ShowAsync();
}
}
}
And from a button click event handler in both the apps:
private async void WhoAmI_Click(object sender, RoutedEventArgs e)
{
var id = new Identity();
await id.WhoAmI();
}
Clicking the button in the apps results in the following message boxes being displayed:
Refactoring to Partial
So this is a simple example, but if there were lots of these conditional directives, we can tidy things up a little.
The idea is that the shared class “Identity” is made partial:
public partial class Identity
This class still contains the method that’s called from each of the apps, but this time the creation of the content of the message is delegated to a method called “CalcMessage”. This method sets the private field to be used in the dialog.
In the “Identity” class, the “CalcMessage” is declared as a partial method. This means that it doesn’t contain an implementation, but the “WhoAmI” method can still call it.
The actual implementation of the code that decides on the message is unique to the two apps.
So now the “Identity” class now looks like this:
using System;
using System.Threading.Tasks;
using Windows.UI.Popups;
namespace UsingPartials
{
public partial class Identity
{
string _message;
public async Task WhoAmI()
{
CalcMessage();
var dialog = new MessageDialog(_message);
await dialog.ShowAsync();
}
partial void CalcMessage();
}
}
We now create a new class file in the Windows Store app:
namespace UsingPartials
{
public partial class Identity
{
partial void CalcMessage()
{
_message = "I'm a Windows Store App!";
}
}
}
And another one in the Phone app:
namespace UsingPartials
{
public partial class Identity
{
partial void CalcMessage()
{
_message = "I'm a Windows Phone App!";
}
}
}
Now the implementation of CalcMessage can be different for both platforms, but other code can still be shared in the shared project version of Identity.cs.
We also now don’t have any conditional directives in use.
If we only have one or two of these conditional directives, then it’s probably easier to just keep them as is, but if there are lots of them and it’s making readability harder then partials may be a useful alternative.
If you want to fill in the gaps in your C# knowledge be sure to check out my C# Tips and Traps training course from Pluralsight – get started with a free trial.
SHARE: