Lessons learned from Windows 8.x and Windows Phone 8.x app developers at Futurice. Avoid reinventing the wheel by following these guidelines. If you are interested in iOS or Android development, be sure to check our iOS and Android documents as well.
Feedback is welcomed, but check the guidelines first.
Visual Studio is the de facto IDE for developing Windows apps. The free express versions are good for getting started, but lack some important features, such as support for extensions. Pro version adds support for all the different project types in a single installation, additional productivity features, support for extensions, and some team collaboration features. Premium mainly adds built in testing support beyond simple unit testing, and Ultimate adds enhanced debugging, architecture, and code analysis tools.
Use Productivity Power Tools (2013)
A free visual studio productivity extension from Microsoft. It lacks some features of the commercial counterparts like JustCode or ReSharper, but doesn't seem to slow the IDE down at all either.
Use NuGet
Nuget is Microsoft's take on a package manager. There's a Visual Studio extension called NuGet Package Manager preinstalled in newer Visual Studios. Bottom line: Use it for external references when you don't need to include the source code in your Solution.
Use Package Restore
According to NuGet docs:
Beginning with NuGet 2.7, the NuGet Visual Studio extension integrates into Visual Studio's build events and restores missing packages when a build begins.
This approach to package restore offers several advantages:
- No need to enable it for your project or solution. Visual Studio will automatically download missing packages before your projects are built and team members don't need to understand NuGet Package Restore.
- No additional directories and files are required within your project or solution.
- Packages are restored before MSBuild is invoked by Visual Studio. This allows packages that extend MSBuild though targets/props file imports to be restored before MSBuild starts, ensuring a successful build.
- Compatibility with ASP.NET Web Site projects created in Visual Studio.
You are using the old package restore if you have clicked the "Enable NuGet Package Restore" -button in Visual Studio. If so, you should migrate: NuGet doc or with pictures.
Code is often split into small methods for reusability. However, there are reasons to split your methods even if you don't plan to reuse them. Method name documents the intent of the code it encloses. This gives you more informative callstack view while debugging and better stacktraces from your exceptions. The stacktraces part applies especially to release builds, where source code line information is lost.
Use caller information attributes when tracing
When you add CallerMemberName, CallerFilePath, or CallerLineNumber attributes for optional parameters, the parameters get set with the file path, line number, and member name of the caller. The values are set into the method call at compile time, don't have a performance penalty, and are not affected by obfuscation.
// using System.Runtime.CompilerServices
// using System.Diagnostics;
public void DoProcessing()
{
TraceMessage("Something happened.");
}
public void TraceMessage(string message,
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
{
Trace.WriteLine("message: " + message);
Trace.WriteLine("member name: " + memberName);
Trace.WriteLine("source file path: " + sourceFilePath);
Trace.WriteLine("source line number: " + sourceLineNumber);
}
// Sample Output:
// message: Something happened.
// member name: DoProcessing
// source file path: c:\Users\username\Documents\Visual Studio 2012\Projects\CallerInfoCS\CallerInfoCS\Form1.cs
// source line number: 31
Use HttpClient for your HTTP needs
Out of the different HTTP APIs available, HttpClient is the new one that supports async/await and automatic request decompression. Using it the async/await -way keeps your code short and readable.
There are different timers for different purposes. For example DispatcherTimer for WinRT, DispatcherTimer for WP Silverlight and ThreadPoolTimer. Additionally there are Observable.Timer, Task.Delay, and last (and least) Thread.Sleep.
Use yield when returning an IEnumerable
Rather than writing something like:
public System.Collections.Generic.IEnumerable<Galaxy> Galaxies {
get {
return new List<Galaxy>() {
new Galaxy { Name = "Tadpole", MegaLightYears = 400 },
new Galaxy { Name = "Pinwheel", MegaLightYears = 25 },
new Galaxy { Name = "Milky Way", MegaLightYears = 0 },
new Galaxy { Name = "Andromeda", MegaLightYears = 3 },
};
}
}
Write this instead:
public System.Collections.Generic.IEnumerable<Galaxy> Galaxies {
get {
yield return new Galaxy { Name = "Tadpole", MegaLightYears = 400 };
yield return new Galaxy { Name = "Pinwheel", MegaLightYears = 25 };
yield return new Galaxy { Name = "Milky Way", MegaLightYears = 0 };
yield return new Galaxy { Name = "Andromeda", MegaLightYears = 3 };
}
}
It will automatically return empty IEnumreable if no "yield return" is called. This will avoid null reference exceptions when you're expecting to get an IEnumerable. The yield approach also only runs as far as is required by the possible iterator. For example, the following only creates one Galaxy instance, avoiding unnecessary processing.
var firstGalaxy = Galaxies.First();
Probably the #1 thing to know about LINQ is that it creates a query that is executed whenever its items are accessed. Sometimes this is what you actually want. However, often you just want to run the query once but access the resulting items multiple times. To avoid unnecessary re-evaluation and bugs resulting from the query result changing, use ToArray, ToList, etc. extension methods to run the query and store the results into a collection.
So rather than:
var sItems = MyItems.Where(i => i.Name.Contains("s"));
var firstSItem = sItems.First(); // Query executed
var lastSItem = sItems.Last(); // Query executed
MyItems.Add(new MyItem("spoon"));
Handle(sItems.Last()); // Query executed, returns the spoon item
Do this instead:
var sItems = MyItems.Where(i => i.Name.Contains("s")).ToList(); // Query executed
var firstSItem = sItems.First();
var lastSItem = sItems.Last();
MyItems.Add(new MyItem("spoon"));
Handle(sItems.Last()); // returns the lastSItem
Don't be fooled by the IObservable Timeout<TSource, TTimeout>(this IObservable source, IObservable firstTimeout, Func<TSource, IObservable> timeoutDurationSelector)
Now, this is an interface, so different implementations could behave differently. The following applies at least to the implementation in System.Reactive.Linq.Observable.
It's easy to think that you should just:
.Timeout(Observable.Return(TimeSpan.FromSeconds(10)), vm => Observable.Return(TimeSpan.FromSeconds(1)))
However, that will simply timeout immediately. The correct way to use it is:
// Notice the .Timer
.Timeout(Observable.Timer(TimeSpan.FromSeconds(10)), i => Observable.Timer(TimeSpan.FromSeconds(1)))
So, in practice the timeout occurs when the passed IObservable completes, not after the duration of the passed TimeSpan.
When writing custom or user controls, do not set the control's Name property with a fixed value. In XAML this would mean setting the x:Name attribute for the root element.
Each dependency object in a PresentationFrameworkCollection has to have an unique Name, and if you end up adding two controls with the same name into the same PresentationFrameworkCollection, you'll end up with:
{System.ArgumentException: Value does not fall within the expected range.
at MS.Internal.XcpImports.CheckHResult(UInt32 hr)
at MS.Internal.XcpImports.Collection_AddValue[T](PresentationFrameworkCollection`1 collection, CValue value)
at MS.Internal.XcpImports.Collection_AddDependencyObject[T](PresentationFrameworkCollection`1 collection, DependencyObject value)
at System.Windows.PresentationFrameworkCollection`1.AddDependencyObject(DependencyObject value)
When you don't set the Name yourself, the framework will generate a unique name for each instance.
There are two possible suprises:
For example, the following xaml looks for the AdVisiblity in MyAdViewModel, not in the MyPageViewModel. Changing the order of the bindings doesn't make a difference. (However, does it first look in MyPageViewModel and then in MyAdViewModel).
<Grid>
<Grid.DataContext>
<MyPageViewModel AdVisiblity="Collapsed">
<MyPageViewModel.AdContext>
<MyAdViewModel Url="www.bystuff.com" Text="Buy Stuff!"/>
</MyPageViewModel.AdContext>
</MyPageViewModel>
</Grid.DataContext>
<AdControl Visibility="{Binding AdVisibility}" DataContext="{Binding AdContext}"/>
</Grid>
This happens because "{Binding PropertyName}" is short for:
"{Binding Path=DataContext.PropertyName, Source={RelativeSource Self}"
It actually binds to the property PropertyName in the object in the DataContext property of its self. When DataContext is not set, it's automatically inherited from the Parent.
Use CallerMemberName attribute or a LINQ expression to help with notifying property changes.
Many MVVM frameworks already help you with notifying property changes from your viewmodels. However, if you don't use any of those, create a base viewmodel class for yourself. Be aware of the performance overhead in creating a LINQ expressions though.
For example:
//using System;
//using System.ComponentModel;
//using System.Linq.Expressions;
//using System.Runtime.CompilerServices;
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Use this to notify a property change from outside of the property's setter.
/// For example: NotifyPropertyChanged(() => MyPropertyWhoseGetterShouldNowReturnNewValue);
/// </summary>
protected void NotifyPropertyChanged<T>(Expression<Func<T>> memberExpression)
{
var lambda = (memberExpression as LambdaExpression);
if (lambda == null) return;
var expr = lambda.Body as MemberExpression;
if (expr == null) return;
NotifyPropertyChanged(expr.Member.Name);
}
/// <summary>
/// Use this from within a property's setter
/// For example: if (SetProperty(ref _propertysBackingField, value)){ OptionallyDoThisIfValueWasNotEqual(); }
/// </summary>
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName]String propertyName = "")
{
if (object.Equals(storage, value)) {
return false;
}
storage = value;
NotifyPropertyChanged(propertyName);
return true;
}
/// <summary>
/// You can use this from within a property's setter when you don't want to set a backing field.
/// For example: NotifyPropertyChanged();
/// </summary>
protected void NotifyPropertyChanged([CallerMemberName]string propertyName = "")
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) {
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
If you aren't already using a library that offers you an easy way to bind into your reactive code from XAML, search for a ReactiveProperty and ReactiveCommand helper classes. Or just pick up the ones in this little reactive utilities library by Futurice's Tomasz Polanski.
Futurice Oy Creative Commons Attribution 4.0 International (CC BY 4.0)