共用方式為


Porting Windows Phone Silverlight XAML and UI to Windows Runtime 8

[This article is for Windows 8.x and Windows Phone 8.x developers writing Windows Runtime apps. If you’re developing for Windows 10, see the latest documentation]

Note  For info about porting to a Universal Windows Platform (UWP) app for Windows 10, see Porting XAML and UI.

 

The previous topic was Troubleshooting.

The practice of defining UI in the form of declarative XAML markup translates extremely well from Windows Phone Silverlight to Windows Runtime apps. You'll find that large sections of your markup are compatible once you've updated system Resource key references, changed some element type names, and changed "clr-namespace" to "using". Much of the imperative code in your presentation layer—view models, and code that manipulates UI elements—will also be straightforward to port.

A first look at the XAML markup

The previous topic showed you how to copy your XAML and code-behind files into your new Windows Runtime Visual Studio project. One of the first issues you might notice highlighted in the Visual Studio XAML designer is that the PhoneApplicationPage element at the root of your XAML file is not valid for a Windows Runtime project. In the previous topic you saved a copy of the XAML files that Visual Studio generated when it created the Windows Runtime project. If you open that version of MainPage.xaml you'll see that at the root is the type Page, which is in the Windows.UI.Xaml.Controls namespace. So, you can change all <phone:PhoneApplicationPage> elements to <Page> (don't forget property element syntax) and you can delete the xmlns:phone declaration.

For a more general approach to finding the Windows Runtime type that corresponds to a Windows Phone Silverlight type, you can refer to the Windows Phone Silverlight to Windows Runtime namespace and class mappings topic.

XAML namespace prefix declarations

If you use instances of custom types in your views—perhaps a view model instance or a value converter—then you will have XAML namespace prefix declarations in your XAML markup. The syntax of these differs between Windows Phone Silverlight and Windows Runtime. Here are some examples:

    xmlns:ContosoTradingCore="clr-namespace:ContosoTradingCore;assembly=ContosoTradingCore"
    xmlns:ContosoTradingLocal="clr-namespace:ContosoTradingLocal"

Change "clr-namespace" to "using" and delete any assembly token and semi-colon (the assembly will be inferred). The result looks like this:

    xmlns:ContosoTradingCore="using:ContosoTradingCore"
    xmlns:ContosoTradingLocal="using:ContosoTradingLocal"

You may have a resource whose type is defined by the system:

    xmlns:System="clr-namespace:System;assembly=mscorlib"
    /* ... */
    <System:Double x:Key="FontSizeLarge">40</System:Double>

In the Windows Runtime, omit the "System" prefix declaration and use the (already declared) "x" prefix instead:

    <x:Double x:Key="FontSizeLarge">40</x:Double>

Imperative code

Your view models are one place where there's imperative code that references UI types. Another place is any code-behind files that directly manipulate UI elements. For example, you might find that a line of code like this one doesn't compile yet:

    return new BitmapImage(new Uri(this.CoverImagePath, UriKind.Relative));

BitmapImage is in the System.Windows.Media.Imaging namespace in Windows Phone Silverlight, and a using directive in the same file allows BitmapImage to be used without namespace qualification as in the snippet above. In a case like this you can right-click the type name (BitmapImage) in Visual Studio and use the Resolve command on the context menu to add a new namespace directive to the file. In this case, the Windows.UI.Xaml.Media.Imaging namespace is added, which is where the type lives in the Windows Runtime. You can remove the System.Windows.Media.Imaging using directive, and that will be all it takes to port code like that in the snippet above. When you're done you'll have removed all Windows Phone Silverlight namespaces.

In simple cases like this, where you're mapping the types in an old namespace to the same types in a new one, you can use Visual Studio's Find and Replace command to make bulk changes to your source code. The Resolve command is a great way of discovering a type's new namespace. As another example, you can replace all "System.Windows" with "Windows.UI.Xaml". That will essentially port all using directives and all fully-qualified type names that refer to that namespace.

Once all the old using directives are removed and the new ones added, you can use Visual Studio's Organize Usings command to sort your directives and remove unused ones.

Sometimes, fixing imperative code will be as minor as changing a parameter's type. Other times you will need to use Windows Runtime APIs instead of .NET APIs for Windows Store apps. To identify which APIs are supported, use the rest of this porting guide in combination with .NET for Windows Store apps overview and the Windows Runtime reference.

And, if you just want to get to the stage where your project builds, you can comment or stub out any non-essential code. Then iterate, one issue at a time, and refer to the following topics in this section (and the previous topic: Troubleshooting), until any build and runtime issues are ironed-out and your port is complete.

Alarms and Reminders

Code using the Alarm or Reminder classes should be ported to use the BackgroundTaskBuilder class to create and register a background task, and display a toast at the relevant time. See Background processing and Toasts.

Animation

As a preferred alternative to keyframe animations and from/to animations, the Windows Runtime animation library is now available to Windows Runtime apps. These animations have been designed and tuned to run smoothly, to look great, and to make your app appear as integrated with Windows as the built-in apps do. See Quickstart: Animating your UI using library animations.

If you do use keyframe animations or from/to animations in your Windows Runtime app then you may want to understand the distinction between independent and dependent animations that the new platform has introduced. See Make animations smooth. Animations that run on the UI thread (ones that animate layout properties, for example) are known as dependent animations, and when run on the new platform they will have no effect unless you do one of two things. You can either re-target them to animate different properties, such as RenderTransform, thereby making them independent. Or you can set EnableDependentAnimation="True" on the animation element in order to confirm your intention to run an animation that cannot be guaranteed to run smoothly. If you use Blend for Visual Studio to author new animations then that property will be set for you where necessary.

Binding

The topic of binding includes:

  • Binding a UI element to "data" (that is, to the properties and commands of a view model)
  • Binding a UI element to another UI element
  • Writing a view model that is observable (that is, it raises notifications when a property value changes and when the availability of a command changes)

All of these aspects are largely unchanged, but there are namespace differences. For example, System.Windows.Data.Binding maps to Windows.UI.Xaml.Data.Binding, System.ComponentModel.INotifyPropertyChanged maps to Windows.UI.Xaml.Data.INotifyPropertyChanged, and System.Collections.Specialized.INotifyPropertyChanged maps to Windows.UI.Xaml.Interop.INotifyCollectionChanged.

Windows Phone Silverlight app bars and app bar buttons can't be bound like they can in a Windows Runtime app. You may have imperative code that constructs your app bar and its buttons, binds them to properties and localized strings, and handles their events. If so, you now have the option to port that imperative code by replacing it with declarative markup bound to properties and commands, and with static resource references, thus making your app incrementally safer and more maintainable. You can use Visual Studio or Blend for Visual Studio to bind and style Windows Runtime app bar buttons just like any other XAML element. Note that in a Windows Runtime app the type names you use are CommandBar and AppBarButton.

The binding-related features of Windows Runtime apps currently have the following limitations:

Binding an Image to a view model

You can bind the Image.Source property to any property of a view model that's of type ImageSource. Here's a typical implementation of such a property in a Windows Phone Silverlight app:

    // this.BookCoverImagePath contains a path of the form "/Assets/CoverImages/one.png".
    return new BitmapImage(new Uri(this.CoverImagePath, UriKind.Relative));

In a Windows Runtime app, you use the ms-appx URI scheme. So that you can keep the rest of your code the same, you can use a different overload of the System.Uri constructor to put the ms-appx URI scheme in a base URI and append the rest of the path onto that. Like this:

    // this.BookCoverImagePath contains a path of the form "/Assets/CoverImages/one.png".
    return new BitmapImage(new Uri(new Uri("ms-appx://"), this.CoverImagePath));

That way, the rest of the view model, the path values in the image path property, and the bindings in the XAML markup, can all stay exactly the same.

Controls

Windows Phone Silverlight apps use controls defined in the Microsoft.Phone.Controls namespace and the System.Windows.Controls namespace. XAML Windows Runtime apps use controls defined in the Windows.UI.Xaml.Controls namespace. The architecture and design of XAML controls in the Windows Runtime is virtually the same as Windows Phone Silverlight controls. But some changes have been made to improve the set of available controls and to unify them with Windows Store apps. For example:

  • ApplicationBar. The CommandBar control in the Windows Runtime is the equivalent of the Windows Phone Silverlight ApplicationBar control, but it is significantly more flexible, supporting custom layouts, and offering more app bar button options. A CommandBar can go into the Page.BottomAppBar property. Using the Page.TopAppBar property is only valid in a Windows Store app; it's not a supported aspect of the Windows Phone Store app UX, and using it will cause your app to terminate.
  • ApplicationBarIconButton. The Windows Runtime equivalent is the AppBarButton control when used inside the CommandBar.PrimaryCommands property. The new control is more flexible, offering data binding and more options for graphical content with the BitmapIcon, FontIcon, PathIcon, and SymbolIcon elements. If you set FontIcon.FontFamily to Segoe UI Symbol then you can use any of the Segoe UI Symbol glyphs in the Glyph property. PrimaryCommands is the content property of CommandBar (the XAML parser interprets an element's inner xml as the value of its content property).
  • ApplicationBarMenuItem. The Windows Runtime equivalent is the AppBarButton control when used inside the CommandBar.SecondaryCommands property.
  • ControlTiltEffect.TiltEffect class. Animations from the Windows Runtime animation library are built into the default Styles of the common controls, see Animation above. For example, the Windows Phone Store app version of the Windows Runtime Button has a PointerDownThemeAnimation element in the Pressed state in its default style, and that's now the standard tilt effect. See Animating pointer actions.
  • LongListSelector with grouped data. The Windows Phone Silverlight LongListSelector functions in two ways, which can be used in concert. First, it is able to display data that is grouped by a key, for example a list of names grouped by initial letter. Second, it is able to "zoom" between two semantic views: the grouped list of items (for example, names), and a list of just the group keys themselves (for example, initial letters). With the Windows Runtime you can display grouped data with the ListView and GridView controls, and SemanticZoom is the control that lets you zoom between two semantic views provided by those same view controls. Note the distinction between semantic zooming (the same data viewed with different semantics) and optical zooming (the same data viewed at different optical scales). Visual Studio and Blend for Visual Studio do a great job of tooling SemanticZoom (and the necessary ListViews or GridViews). See Guidelines for semantic zoom and Guidelines for list and grid view controls.
  • LongListSelector with flat data. For performance reasons, in the case of very long lists, we recommended LongListSelector instead of a Windows Phone Silverlight list box even for flat, non-grouped data. In a Windows Runtime app, ListView or GridView are preferred for long lists of items whether or not the data are amenable to grouping.
  • Panorama. The Windows Phone Silverlight Panorama control maps to the Hub control in the Windows Runtime. A Hub is composed of heterogeneous HubSections, each of which can have a different data source. See Guidelines for hub controls in Windows Store apps and Guidelines for hub controls in Windows Phone Store apps.
  • Pivot. The Windows Runtime equivalent of the Windows Phone Silverlight Pivot control is Windows.UI.Xaml.Controls.Pivot. It is one of the few Windows Runtime controls that are phone-only (that is, for use only in a Windows Phone Store app).

For more info on Windows Runtime controls, see Controls by function, Controls list, and Guidelines for controls.

Localization and globalization

For localized strings, you can re-use the .resx file from your Windows Phone Silverlight project in your Windows Runtime project. Copy the file over, add it to the project, and rename it to Resources.resw so that the lookup mechanism will find it by default. Set Build Action to PRIResource and Copy to Output Directory to Do not copy. You can then use the strings in markup by specifying the x:Uid attribute on your XAML elements. See Quickstart: Using string resources.

Windows Phone Silverlight apps use the CultureInfo class to help globalize an app. Windows Runtime apps use MRT (Modern Resource Technology), which enables the dynamic loading of app resources (localization, scale, and theme) both at runtime and in the Visual Studio design surface. For more information, see Guidelines for files, data, and globalization.

Media and graphics

As you read about Windows Runtime media and graphics, bear in mind that the Windows design principles encourage a fierce reduction of anything superfluous including graphical complexity and clutter. Windows design is typified by clean and clear visuals, typography, and motion. If your app follows the same principles then it will seem more like the built-in apps.

Windows Phone Silverlight has a RadialGradientBrush type which is not present in the Windows Runtime, although other Brush types are. In some cases you will be able to get a similar effect with a bitmap. Note that you can create a radial gradient brush with Direct2D in a Microsoft DirectX and XAML C++ Windows Runtime app.

Windows Phone Silverlight has the System.Windows.UIElement.OpacityMask property, but that property is not a member of the Windows Runtime UIElement type. In some cases you will be able to get a similar effect with a bitmap. And you can create an opacity mask with Direct2D in a Microsoft DirectX and XAML C++ Windows Runtime app. But a common use case for OpacityMask is to use a single bitmap that adapts to both light and dark themes. For vector graphics, you can use theme-aware system brushes (such as the pie charts illustrated below). But to make a theme-aware bitmap (such as the check marks illustrated below) requires a different approach.

In a Windows Phone Silverlight app, the technique is to use an alpha mask (in the form of a bitmap) as the OpacityMask for a Rectangle filled with the foreground brush:

    <Rectangle Fill="{StaticResource PhoneForegroundBrush}" Width="26" Height="26">
        <Rectangle.OpacityMask>
            <ImageBrush ImageSource="/Assets/wpsl_check.png"/>
        </Rectangle.OpacityMask>
    </Rectangle>

The most straightforward way to port this to a Windows Runtime app is to use a BitmapIcon, like this:

    <BitmapIcon UriSource="Assets/winrt_check.png" Width="21" Height="21"/>

Here, winrt_check.png is an alpha mask in the form of a bitmap just as wpsl_check.png is, and it could very well be the same file. However, you may want to provide several different sizes of winrt_check.png to be used for different scaling factors. For more info on that, and for an explanation of the changes to the Width and Height values, see View pixels, and scaling to pixel density in this topic.

A more general approach, which is appropriate if there are differences between the light and dark theme form of a bitmap, is to use two image assets—one with a dark foreground (for light theme) and one with a light foreground (for dark theme). For further details about how to name this set of bitmap assets, see How to name resources using qualifiers. Once a set of image files are correctly named, you can refer to them in the abstract, using their root name, like this:

    <Image Source="Assets/winrt_check.png" Stretch="None"/>

In Windows Phone Silverlight, the UIElement.Clip property can be any shape that you can express with a Geometry and is typically serialized in XAML markup in the StreamGeometry mini-language. In the Windows Runtime, the type of the Clip property is RectangleGeometry, so you can only clip a rectangular region. Allowing a rectangle to be defined using mini-language would be too permissive. So, to port a clipping region in markup, replace the Clip attribute syntax and make it into property element syntax similar to the following:

    <UIElement.Clip>
        <RectangleGeometry Rect="10 10 50 50"/>
    </UIElement.Clip>

Note that you can use arbitrary geometry as a mask in a layer with Direct2D in a Microsoft DirectX and XAML C++ Windows Runtime app.

When you navigate to a page in a Windows Phone Silverlight app, you use a Uniform Resource Identifier (URI) addressing scheme:

    NavigationService.Navigate(new Uri("/AnotherPage.xaml", UriKind.Relative)/*, navigationState*/);

In a Windows Runtime app, you call the Frame.Navigate method and specify the type of the destination page (as defined by the x:Class attribute of the page's XAML markup definition):

    // In a page:
    this.Frame.Navigate(typeof(AnotherPage)/*, parameter*/);

    // In a view model, perhaps inside an ICommand implementation:
    var rootFrame = Windows.UI.Xaml.Window.Current.Content as Windows.UI.Xaml.Controls.Frame;
    rootFrame.Navigate(typeof(AnotherPage)/*, parameter*/);

You define the startup page for a Windows Phone Silverlight app in WMAppManifest.xml:

    <DefaultTask Name="_default" NavigationPage="MainPage.xaml" />

In a Windows Runtime app, you use imperative code to define the startup page. Here's some code from App.xaml.cs that illustrates how:

    if (!rootFrame.Navigate(typeof(MainPage), e.Arguments))

URI mapping and fragment navigation are URI navigation techniques, and so they are not applicable to Windows Runtime navigation, which is not based on URIs. URI mapping exists in response to the weakly-typed nature of identifying a target page with a URI string, which leads to fragility and maintainability issues should the page move to a different folder and hence to a different relative path. Windows Runtime apps use type-based navigation, which is strongly-typed and compiler-checked, and does not have the problem that URI mapping solves. The use case for fragment navigation is to pass along some context to the target page so that the page can cause a particular fragment of its content to be scrolled into view, or otherwise displayed. The same goal can be achieved by passing a navigation parameter when you call the Navigate method.

For more info, see Quickstart: Navigating between pages.

Resource key references

The XAML markup editor in Visual Studio highlights references to resource keys that can't be resolved. For example, the XAML markup editor will underline a reference to the style key PhoneTextNormalStyle with a red squiggle. If that isn't corrected then the app will immediately terminate when you try to deploy it to the emulator or device. So it's important to attend to XAML markup correctness. And you will find Visual Studio to be a great tool for catching such issues.

Also see Text, below.

Status bar (system tray)

The system tray (set in XAML markup with shell:SystemTray.IsVisible) is now called the status bar, and it is shown by default. You can control its visibility in imperative code by calling the Windows.UI.ViewManagement.StatusBar.ShowAsync and HideAsync methods.

Text

Text (or typography) is an important aspect of a Windows Runtime app. Use these illustrations to find the Windows Runtime TextBlock system styles that are available. Find the ones that correspond to the Windows Phone Silverlight styles you used. All of the Windows Store app styles (except for CaptionTextBlockStyle) are also available for Windows Phone Store apps, so there’s an advantage to using those. Alternatively, you can create your own universal styles and copy the properties from the Windows Phone Silverlight system styles into those. And there will be cases where you will choose not to use the exact same style for PC, tablet, and phone due to form factor differences.

System TextBlock styles for Windows Store apps

System TextBlock styles for Windows Phone Store apps

Tiles

Tiles for Windows Runtime apps have behaviors similar to Live Tiles for Windows Phone Silverlight apps, although there are some differences. For example, code that calls the Microsoft.Phone.Shell.ShellTile.Create method to create secondary tiles should be ported to call SecondaryTile.RequestCreateAsync. Here is a before-and-after example, first the Windows Phone Silverlight version:

    var tileData = new IconicTileData()
    {
        Title = this.selectedBookSku.Title,
        WideContent1 = this.selectedBookSku.Title,
        WideContent2 = this.selectedBookSku.Author,
        SmallIconImage = this.SmallIconImageAsUri,
        IconImage = this.IconImageAsUri
    };

    ShellTile.Create(this.selectedBookSku.NavigationUri, tileData, true);

And the Windows Runtime equivalent:

    var tile = new SecondaryTile(
        this.selectedBookSku.Title.Replace(" ", string.Empty),
        this.selectedBookSku.Title,
        this.selectedBookSku.ArgumentString,
        this.IconImageAsUri,
        TileSize.Square150x150);

    await tile.RequestCreateAsync();

Code that updates a tile with the Microsoft.Phone.Shell.ShellTile.Update method, or the Microsoft.Phone.Shell.ShellTileSchedule class, should be ported to use the TileUpdateManager, TileUpdater, TileNotification, and/or ScheduledTileNotification classes.

For more info on tiles, toasts, badges, banners, and notifications, see Creating tiles and Working with tiles, badges, and toast notifications. For specifics about sizes of visual assets used for Windows Runtime Tiles, see Tile and toast visual assets.

Toasts

Code that displays a toast with the Microsoft.Phone.Shell.ShellToast class should be ported to use the ToastNotificationManager, ToastNotifier, ToastNotification, and/or ScheduledToastNotification classes. To enable toasts in a Windows Runtime app, set Toast capable (ToastCapable in markup) to true in the app package manifest. Note that on Windows Phone the consumer-facing term for "toast" is "banner".

See Working with tiles, badges, and toast notifications.

View pixels, and scaling to pixel density

To a Windows Phone Silverlight app, all phone screens are exactly 480 view pixels wide, without exception, no matter how many physical pixels the screen has, nor what its pixel density or physical size is. This means that an Image element with Width="48" will be exactly one tenth of the width of the screen of any phone that can run the Windows Phone Silverlight app. View pixels are a way of abstracting size and layout away from the actual physical size and resolution of devices.

Incidentally, resolution is a measure of pixel density and not, as is commonly thought, pixel count. Effective resolution is the way the physical pixels that compose an image or glyph resolve to the eye given differences in viewing distance and physical pixel size (pixel density being the reciprocal of physical pixel size). Effective resolution is a good metric to build an experience around because it is user-centered. By understanding all the factors, and controlling the size of UI elements, you can make the user's experience a good one.

To a Windows Runtime app, it is not the case that all devices are some fixed number of view pixels wide. That's probably obvious, given the wide range of devices that a Windows Runtime app can run on. But not even a Windows Phone Store app sees all phones as being the same width in view pixels. Some phone models are 384 view pixels wide to a Windows Phone Store app; in fact, 384 is not only a common size, it's also the smallest view pixel width. 386 and 400 are common sizes, and the upper end of the range is currently around 600. As an app developer, you can ignore this variation. It's just another way of assigning a scale factor to a device, and scale factor is a concept common to Windows Runtime apps. If you give your UI elements a fixed size in XAML markup, then the variation in scale factor serves to keep your UI elements presenting a more-or-less constant-sized touch (and reading) target to the user across different phones. This also means that instead of your UI optically scaling on different devices, it will instead be able to fit the appropriate amount of content into the available spaces. Then, if your application is one that needs to account for changes in effective resolution due to viewing distance, then you can just turn the dial of a final scaling applied to your UI.

For a Windows Phone Store app, since 480 was formerly the fixed width in view pixels and now 384 is the minimum width in view pixels, you just need to multiply any dimension from the Windows Phone Silverlight app markup by 0.8. For more info, see Guidelines for scaling to pixel density.

The next topic is Porting for I/O, device, and app model.

Windows Phone Silverlight to Windows Runtime namespace and class mappings