In this blog post series, we’re going to cover the migration of the code for the Silverlight Toolkit TreeView control TreeView control to UWP and the Uno Platform, a control widely used in many lines of business applications still in use today.
This includes parts of the features that may or may not work initially, as well as modifications that will have to be made in the Uno Platform to conform to UWP if required. While the Uno Platform includes all the APIs of the Spring Creators Update (17134), many of these APIs are not implemented yet and there may be some that are used by the Silverlight
Also, the point of this exercise is to walk through a migration process from a Silverlight code base, as there is already an existing
TreeView control API in UWP. As of the writing of this article, the UWP
TreeView is not implemented in the Uno Platform and migrating this Silverlight control is not an option, as the APIs are significantly different and not directly compatible.
Importing the Silverlight TreeView control source
To migrate a control from Silverlight, there are a few things to do:
- Create a cross-targeted project using the Cross-Platform library template from the Uno Platform VS Addin
- Replace Silverlight namespaces with UWP namespaces and selectively import the
TreeViewsource files and dependencies
- Adjust the code for slightly changed APIs
- Temporarily comment out code for APIs that have significantly changed.
- Adjust the XAML
Cross targeted project creation
To be able to build the control is a reuseable way, in a NuGet package, we need to create a Cross-platform library using the Uno Platform VS Addin, which does all the configuration to target Windows (uap10.0), iOS, Android and WebAssembly.
This project will contain all the XAML files and C# source files required for the
TreeView to function properly. It uses the excellent MSBuild.Sdk.Extrasmsbuild extensions to cross targeted library with minimal efforts, using the new and improved sdk-style project format, and simplifies the creation of NuGet packages.
It will then possible to create an installable NuGet package using the context menu Pack option on the project.
Importing the source
The process of importing the source is somewhat straightforward. Microsoft, in all its XAML variants, kept many of the APIs signature-compatible. This means that in a large majority of cases, simply changing the namespaces from
Windows.UI is making the code compatible with UWP.
Here are some examples:
One tip here to simplify the migration is to temporarily remove all non-windows targets in the cross-targeted projects to keep only
uap10.0. This helps in keeping the compilation errors limited to the UWP APIs, and avoid some of the API differences that may happen including iOS/Android/Wasm targets. Once the Windows target builds, adding back the other targets will allow for special adjustments, if any.
Most of the exercise of the code import is about making an heavy use of the Intellisense by importing files one by one, starting by
TreeView.cs and removing all the red squiggles. The
TreeView controls uses
TreeViewItem, which in turn uses
After the first pass of changing namespaces, and importing dependent files, we end up with a self-contained set of C# source files, but not yet compiling.
Adjusting for slightly changed APIs
When trying to resolve the API differences when moving from UWP, after adjusting the namespaces, the first low hangings are the ones that are slightly different. For instance, it can be member visibility differences, or just name updates.
FrameworkElement.OnApplyTemplatehas been moved from
PropertyMetadatadoes not have constructor that only contains a
Bindingdoes not contain a constructor taking a string path as a parameter
Control.Focusnow requires a
Those a pretty easy to adjust, and the UWP runtime behavior has a great change of being identical to the one Silverlight had.
The case of ItemsControl.OnItemsChanged
There’s one significant change with
ItemsControl.OnItemsChanged where the method is not present anymore. This is a pretty important part of behavior of the control, used to create manipulate
TreeViewItem instances and link them to the
TreeView instance. Removing the code of this method would make the control unusable.
This method can be replaced by the
ItemsControl.Items.VectorChanged event, but not completely.
ItemsControl in Silverlight was based on
ObservableCollection which provided the
NotifyCollectionChangedActionproperty, whereas the
ItemsCollection in UWP is based on
ObservableVector. This new implementation notably does not provide the
Replace action and it’s raising
In this case, we must remove the part that dealt with
NotifyCollectionChangedAction.Replace, keeping only
Insert. The new API also does not provide the items being notified for, which means we have to use the
Items property directly instead.
Temporarily commenting out incompatible features
In other cases, the APIs are significantly different and we’ll for now comment those out for the sake of chewing a comfortable piece of code. Parts of this include keyboard support, parts of the mouse support, localization and Peer Automation related support.
UWP provides support for those features, not as virtual methods but rather as events that are not directly compatible with the Silverlight implementation. We will take a look at those features in a later part of the series.
Adjusting the XAML
Another part of the migration to UWP is the adjustment of the XAML. The syntax is the same, but parts differ :
- The custom namespace syntax is now using
clr-namespace:, and in many cases simply replacing one by the other is enough
VisualStateManagerrelated classes are now in the default xml namespace, meaning that the
vsm:namespace is not required anymore.
systemnamespace is now part of the
We’ll also comment out the support for
Cursor adjustments, as the property is not directly mapped to UWP.
Creating the sample app
To be able to test the imported code, we can create a sample application using the Uno Platform VS Addin, reference our imported project and add a simple sample like this one:
<controls:TreeView Margin="5"> <controls:TreeViewItem Header="Controls"> <controls:TreeViewItem Header="AutoCompleteBox"> <controls:TreeViewItem Header="Properties" /> </controls:TreeViewItem> <controls:TreeViewItem Header="Expander" /> <controls:TreeViewItem Header="NumericUpDown" /> </controls:TreeViewItem> <controls:TreeViewItem Header="Layout"> <controls:TreeViewItem Header="DockPanel" /> <controls:TreeViewItem Header="WrapPanel" /> <controls:TreeViewItem Header="Viewbox" /> </controls:TreeViewItem> <controls:TreeViewItem Header="Charting"> <controls:TreeViewItem Header="ColumnSeries" /> <controls:TreeViewItem Header="LineSeries" /> <controls:TreeViewItem Header="PieSeries" /> </controls:TreeViewItem> </controls:TreeView>
and test it first on Windows, then iOS, Android and WebAssembly.
When running the sample, a few things stand out:
TreeViewis displaying content properly
- The nodes expand and collapse properly
- The glyph next to the nodes changes state once, but does not animate back
- There are some exceptions regarding the
ItemContainerGeneratorwhich has been deprecated in UWP.
We’ll take a look at those the next parts of this series.