Sergii Baidachnyi

Blog about technologies

Archive for July 2015

UWP: New Controls (part 5 – Media)

leave a comment »

Of course, the existing Media controls are not new but I cannot overlook them due to number of new features there. I have developed lots of applications which work with video and I know about disadvantages of Media controls in Windows 8.x like:

· Problem with adaptive streaming – in order to start working with adaptive streaming you needed to use external libraries like Player Framework and Smooth Streaming SDK because Windows 8.x SDK doesn’t support embedded features for adaptive streaming. Even if you use these libraries you will get support for Smooth Streaming only;

· No support of existing formats for closed captions – Windows 8.x SDK doesn’t support closed captions at all. SMPTE-TT and TTML were introduced in Player Framework SDK only;

· No way to change template for existing media player control – Windows 8.x supports SystemMediaTransportControls but there were not many ways to change something. So, you had to design your own player from scratch or use existing player from Player Framework with less ability to change anything there;

Let’s see how Microsoft fixed all these disadvantages in Universal Windows Platform.

Adaptive Streaming

HTTP Live Streaming (HLS), Dynamic Adaptive Streaming over HTTP (DASH) and Microsoft Smooth Streaming are the most popular technologies for adaptive streaming. New MediaElement control supports all of them.

If you want to test how it works it’s better to use Azure account (you can use trial) and create Media Service instance there. Media Service supports dynamic packaging, so you can upload your video there and encode it using one of profiles which are ready for adaptive streaming.

clip_image001

Pay special attention that you need to create at least one streaming unit. Once video is encoded, thanks to dynamic packaging, you can stream it using any format that I mentioned previously (HLS, Dash, Smooth).

Let’s test, how to work DASH. In order to do it you need just add MediaElement to XAML page:

<MediaElement Name="media" AreTransportControlsEnabled="True" />

In order to create adaptive media source you can use AdaptiveMediaSource class like this:

AdaptiveMediaSourceCreationResult result = await AdaptiveMediaSource.CreateFromUriAsync(new Uri("http://testadaptive.streaming.mediaservices.windows.net/e1f03724-c228-4f86-9570-7321f1767fc5/Module%202.1_H264_4500kbps_AAC_und_ch2_128kbps.ism/Manifest(format=mpd-time-csf)", UriKind.Absolute)); if (result.Status == AdaptiveMediaSourceCreationStatus.Success) { var astream = result.MediaSource; media.SetMediaStreamSource(astream); }

My video works fine and thanks to MediaTransportControls I have great interface for my media player:

clip_image003

Captions

If you want to add closed captions it’s easy to do with new controls as well. Just use the following code to associate TTM file with existing adaptive stream:

AdaptiveMediaSourceCreationResult result = await AdaptiveMediaSource.CreateFromUriAsync(new Uri("http://testadaptive.streaming.mediaservices.windows.net/e1f03724-c228-4f86-9570-7321f1767fc5/Module%202.1_H264_4500kbps_AAC_und_ch2_128kbps.ism/Manifest(format=mpd-time-csf)", UriKind.Absolute)); if (result.Status == AdaptiveMediaSourceCreationStatus.Success) { var astream = result.MediaSource; var ttmSource = TimedTextSource.CreateFromUri(new Uri("ms-appx:///assets/captions.ttm")); var mediaSource=MediaSource.CreateFromAdaptiveMediaSource(astream); mediaSource.ExternalTimedTextSources.Add(ttmSource); var mediaElement = new MediaPlaybackItem(mediaSource); media.SetPlaybackSource(mediaElement); }

You can see that we use TimedTextSource class to create source based on file with captions. In order to associate the captions with media source we used MediaSource class and MediaPlaybackItem class to prepare source for MediaElement.

Template for Media

Starting with Windows 10 the MediaTransportControls class has its own states and a template according to modern design. It allows to change anything there by modifying the existing XAML template. So you should not create buttons from scratch, implement logic etc. There are three ways to get existing template for MediaTransportControl: visit MSDN, find generic.xaml file on your computer or use Blend.

Because I have written this post before release of Windows 10 SDK there was no information on MSDN but I hope that you can find it right after release.

Generic.xaml file you can find using the following path C:\Program Files (x86)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\10.0.10069.0\Generic. Just open generic.xaml and find template for MediaTransportControls there.

Finally, you can extract template using Blend tool. I would like recommend this way because it’s easy not just to create copy of template but to modify it as well. In order to extract template for MediaTransportControls you need to create a new project (or open existing) in Blend and add MediaTransportControls to a page. Using context menu select Edit Template -> Edit a Copy menu item.

clip_image004

Blend will propose to select location and name for new style. So, select it and click OK.

clip_image006

Right after it you can open XAML and modify new template there or use powerful editor in Blend to see and modify everything there

clip_image007

Written by Sergiy Baydachnyy

07/31/2015 at 8:28 PM

UWP: Extensions and ApiInformation

leave a comment »

Universal Windows Platform allows to build universal applications for all devices which run Windows 10. I have already published several posts about new controls which allow to create universal interfaces for different screen sizes and resolutions. But what about device-specific features? For example: Raspberry Pi has set of pins which are not available for phone and tablets; you can use desktops and laptops in order to print something directly from your application but this functionality is not available for phones; lots of phones support vibration what is very uncommon for laptops etc. That’s why all contracts with device-specific functionality were moved to special libraries called extensions.

You can include existing extensions to your project using Add Reference dialog and open Extensions tabs. Today you can find three most important extensions there like Mobile Extension, Desktop Extension and IoT Extension.

clip_image002

Of course you might see more extensions soon. For example, Microsoft might publish some extensions for Xbox and Hololens but you will be able to create your own for own Windows 10 devices.

If you want to see all contracts which were included to the extension, you can open the manifest file for the selected extension and check all contracts there. For example, you can find the IoT manifest using the following folder C:\Program Files (x86)\Windows Kits\10\Extension SDKs\WindowsIoT\10.0.10069.0 and manifest looks like

<?xml version="1.0" encoding="utf-8"?> <FileList TargetPlatform="UAP" TargetPlatformMinVersion="10.0.0.1" TargetPlatformVersion="10.0.10069.0" SDKType="Platform" DisplayName="Windows IoT Extension SDK" AppliesTo="WindowsAppContainer" MinVSVersion="14.0" ProductFamilyName="Windows.IoT" SupportsMultipleVersion="Error" TargetFramework=".NETCore, version=v4.5.3;" SupportPrefer32Bit="True" MoreInfo="http://www.microsoft.com/en-us/server-cloud/internet-of-things.aspx"> <ContainedApiContracts> <ApiContract name="Windows.Devices.DevicesLowLevelContract" version="1.0.0.0"/> <ApiContract name="Windows.System.SystemManagementContract" version="1.0.0.0"/> </ContainedApiContracts> </FileList>

So, right now there are two contracts only and you can find all classes there using Object Browser in the Visual Studio.

I already published how to use IoT extensions for Raspberry Pi 2. So, in this article I want to talk more about how to implement universal approach even if you add an extension.

The main idea of Universal Windows Platform is to give a way to create just one application and one binary for all devices. But what happens when we add an extension? Should we recompile our application for different platforms with this extension and without the extension? The answer is No.

Extensions are designed in the way when you can continue to run your code on a platform which doesn’t support extensions which you have included to your project. But if you try to call methods and create objects based on classes from the extensions, these calls will generate runtime exception.

That’s why you need to check in runtime if selected extension is available on the platform. Of course, you should not do it in exception handler. It’s better to adopt the interface of your application for the specific device rather than notify users about some unsupported feature when the application is running. So, developers need to have better tool to check availability of contract and Microsoft implemented all needed features in ApiInformation class.

ApiInformation is located in Windows.Foundation.Metadata namespace and contains several static methods like IsApiContractPresent, IsEventPresent, IsMethodPresent etc.

So, if you want to check, if GPIO is available, you can use the following code:

if (ApiInformation.IsApiContractPresent("Windows.Devices.DevicesLowLevelContract", 1)) { //doing something with GPIO }

Pay special attention that IsApiContractPresent requires two parameters. The second one is major version (you can use minor version as well – third parameter). This parameter is needed because Microsoft can update some of contracts and you can target specific version(s).

The code above doesn’t mean that you need to create hundreds of if blocks if you include one or several contracts. It’s better to create a custom trigger based on this information and implement several visual states.

Written by Sergiy Baydachnyy

07/27/2015 at 6:50 PM

UWP: New Controls (part 4 – Inking)

with one comment

One more powerful control in Universal Windows Platform is InkCanvas. Thanks to this control you can enable inking anywhere in your application and you can use not just stylus but fingers and mouse as well. So, thanks to this feature you can bring inking functionality to any device based on Windows 10.

To enable inking you need to start with InkCanvas element and place it inside any container like StackPanel, Grid, etc. Like other UI controls based on FrameworkElement, InkCanvas contains a bunch of properties but in the simplest case you do not have to declare anything:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <InkCanvas Name="ink"></InkCanvas> </Grid>

In this case InkCanvas will fill all space inside the container and you can start make your notes or paint something. Pay special attention that by default InkCanvas accepts input from stylus (pen) only. So, if you want to use fingers or mouse you need to implement the following code:

ink.InkPresenter.InputDeviceTypes = CoreInputDeviceTypes.Mouse|CoreInputDeviceTypes.Touch;

In this code we are using the second important object – InkPresenter. InkCanvas is just a control which contains just one inking property – reference to InkPresenter but InkPresenter contains all information about input methods and lots of different settings there including collection of strokes. You cannot create InkPresenter directly but you can get reference to the object of this class using InkPresenter property of InkCanvas. Frankly speaking InkCanvas doesn’t contain any other properties or methods related to inking. But we still have something to discuss about InkCanvas and the most important question there is how to enable inking anywhere because usually you need to enable inking for images, videos, text rather than using inking inside a blank container. Let’s add several controls to the container and see what happens there.

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <InkCanvas Name="ink"></InkCanvas> <StackPanel> <TextBlock Text="Hello. Here is some text." Margin="20"></TextBlock> <Button Content="Click me" Margin="20"></Button> </StackPanel> </Grid>

If you run this code you will see that all controls work fine and you can make any notes there.

clip_image002

In our example we placed InkCanvas behind other controls but if you swap StackPanel and InkCanvas you can see that InkCanvas is placed above StackPanel and controls like Button don’t work at all. You can resolve it thanks to Canvas.ZIndex property.

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <StackPanel Canvas.ZIndex="1"> <TextBlock Text="Hello. Here is some text." Margin="20"></TextBlock> <Button Content="Click me" Margin="20"></Button> </StackPanel> <InkCanvas Name="ink" ></InkCanvas> </Grid>

Let’s talk about settings of InkPresenter and how to make different effects there. It’s all around InkDrawingAttributes class. You simply need to create an object of this class and set different properties like Color, PenTip, Size etc.

InkDrawingAttributes attr = new InkDrawingAttributes(); attr.Color = Colors.Red; attr.IgnorePressure = true; attr.PenTip = PenTipShape.Circle; attr.Size = new Size(4, 10); attr.PenTipTransform = Matrix3x2.CreateRotation((float)(70 * Math.PI / 180)); ink.InkPresenter.UpdateDefaultDrawingAttributes(attr);

Code below shows how to use InkDrawingAttributes. In order to update attributes you need to call UpdateDefaultDrawingAttributes and pass InkDrawingAttributes object there. In code below I used PenTipTransform property as well. This is a very interesting property which allows to apply transformation to pin shape and get more natural look for strokes thanks to different height of strokes based on direction of pen (moving direction/angle).

clip_image003

You can check the image below where I tried to paint symbol “f” and you can see that the image contains strokes with different height. In fact I used the same settings but this effect was applied thanks to PenTipTransform.

Finally, you can paint anything but how can you erase some strokes if you make anything wrong? In order to do it you need to change mode of InkPresenter:

ink.InkPresenter.InputProcessingConfiguration.Mode = InkInputProcessingMode.Erasing;

The next important class which is related to inking is InkStroke. Anything what you paint on InkCanvas consists of InkStroke. In order to get access to functionality around InkStroke objects you can use StrokeContainer property of InkPresenter. Thanks to this property you can save existing strokes to file, add new strokes, get access to selected strokes etc. So, if you want to implement any functionality around strokes then StrokeContainer is your friend. Of course the most popular methods there are LoadAsync and SaveAsync.

Lots of applications require recognition functionality as well. In order to recognize text based on hand writing you can use InkRecognizerContainer class. In the simplest way you can use this class like this:

InkRecognizerContainer container = new InkRecognizerContainer(); var result=await container.RecognizeAsync(ink.InkPresenter.StrokeContainer, InkRecognitionTarget.All); string s=result[0].GetTextCandidates()[0];

This code will use default recognizer and convert the first text candidate from the list to text. Of course it’s not enough for more complex scenarios. For example, I spend 10 years at school to train my handwriting for Russian and Ukrainian but not for English. So, when I am trying to write something in English usually I can find the right result on the second or third place in the list of text candidates. Additionally, I can have several recognizers on my computer.

So, it’s better to allow to select the right recognizer. You can simply use SetDefaultRecognizer and GetRecognizers of InkRecognizerContainer object to do it. In case of non-native English writers I am not sure that you need to present full list of possible results. It’s better to ask users to setup recognizer using system settings. For example, I can setup the default recognizer to adopt to my writing style if I select “write each character separately” and make some “teach” settings:

clip_image005

At the end of the post I want to draw your attention to Ink Toolbar control. It’s not a default UWP control and you need to install this control separately. Once you install the control it will be available in Extension tab of Add Reference dialog (close and open Visual Studio after installation) and it’s ready to use. You just need to add reference to the library:

xmlns:ink="using:Microsoft.Labs.InkToolbarControl"

Find a place for the control and make reference to the existing InkCanvas:

<InkCanvas Name="ink" ></InkCanvas> <ink:InkToolbar TargetInkCanvas="{x:Bind ink}" VerticalAlignment="Top" HorizontalAlignment="Right"></ink:InkToolbar>

Below you can see the control itself which generates our code:

clip_image006

Written by Sergiy Baydachnyy

07/27/2015 at 6:45 PM

UWP: New Controls (part 3 – Maps)

leave a comment »

In this post I am going to talk about maps in Universal Windows Platform applications. And it’s better to start with the answer to the question that developers asked me many times: when will offline maps be available for Windows applications?

Starting with Windows 10 offline maps are available not just for phones but for desktops, laptops, tablets etc. User can visit Settings window and download all needed maps there. Once maps are downloaded the existing map control will use them by default.

clip_image002

It’s really cool because I can use my Windows 10 devices anywhere in order find addresses, the right direction etc. and you can access? all these things directly from your application.

But offline maps are not the single feature of new Windows 10 maps. Let’s look at other features there:

· Unified platform – since Windows 10 you should not use several services like Here or Bing Maps for different tasks (or different services on different devices). All services are available under the same umbrella and can be used for any UWP applications;

· Adaptive interface – existing Maps application works fine on all devices. You can use touch, pen or mouse as well as use different screen sizes. The same we can say about MapControl which is available for developers;

· 2D view with business and traffic information – existing maps support all common features for 2D maps like different views, traffic information (you can on or off it), provide information about business locations and transit;

· Location – existing Maps application allows to find and display user location. Using Windows.Devices.Geolocation API you can find user location in your application in order to provide better user experience and implement lots of different tasks;

· External elements – developers can place own icons, rectangles, polygons and even XAML controls on maps. It allows to customize existing maps and extend the number of possible scenarios;

· Geofence – Geofencing API allows to notify application if user arrives to the defined area;

· Routing – developers can use Maps services that can calculate route to selected destination using different methods there (driving, walking);

· StreetSide – new functionality which allows to get images of the selected area to display it inside the interface. It’s very useful if user wants to understand what the selected area looks like;

· 3D views – one more new functionality which is available for developers starting with Windows 10: right now you can show maps not just in 2D but in 3D view modes. If 3D view is available for the selected area you can implement the same set of features like in standard Maps application;

It’s time to talk how to use maps in your applications. You have two ways there: you can redirect some user requests to the existing Maps application or you can integrate maps directly to your application.

If you are going to utilize existing Maps application you can redirect user to it using Launcher class. This class contains LaunchUriAsync static method which allows to open an external application using information from Uri. For example, if you use “http://….” in your uri then Launcher will open web browser but in case of Maps you need to start your uri with bingmaps:. Of course, it’s not enough and you need to pass some parameters using your uri. The full list of possible parameters you can find using the following link. For example, this code will open Maps application in move center to North Vancouver and zoom the map to level 14:

await Launcher.LaunchUriAsync(new Uri("bingmaps:?lvl=14&rpt=adr.North%20Vancouver%20BC"));

In order to start working with maps in your application you need to get “access key” visiting Maps Dev Center. You can select Trial key or Basic key based on your needs. Right after Windows 10 is released you will be able to find Universal Application in the list of possible applications but right now there is still no information about Windows 10. In any case you cannot publish Windows 10 applications right now (several days left), so you can use maps without key. It works fine but you will see the message that MapServiceToken is not specified and you cannot publish your application without MapServiceToken.

Once Windows 10 is available you can create Basic key for your universal application using the portal:

clip_image003

In order to start working with maps in your application you need to use three namespaces – Windows.UI.Xaml.Controls.Maps, Windows.Devices.Geolocation and Windows.Services.Maps and one control – MapControl. The first namespace contains MapControl itself and several classes which allows to place something on maps, setup camera and styles, prepare street view. The second namespace allows to get user location and contains Geofencing API as well. And the last one supports several utility classes which allows to find location by address, calculate route etc.

Because MapControl is not in default XAML namespaces you need to add a new namespace to XAML file:

xmlns:maps="using:Windows.UI.Xaml.Controls.Maps"

And you are ready to use MapControl:

<maps:MapControl MapServiceToken="..."/>

Right now we know how to add maps to your application and it’s time to see some tasks there.

Let’s start with basic functionality like how to center map, zoom map etc. Let’s have a look at the following code:

maps.ZoomLevel = 14; maps.Center = (await MapLocationFinder.FindLocationsAsync("North Vancouver, BC", null)).Locations[0].Point;

In this code we use reference to MapControl in order to assign two properties ZoomLevel and Center. Of course, in case of ZoomLevel you should not do anything special but if you want to center your map based on address you need to use map services – MapLocationFinder in this case. In my example I used FindLocationsAsync method and assigned the first location from the list to the Center property.

In order to apply 3D view to the maps you simply need to use Style attribute. It’s somewhat confusing because Style attributes exists for all UI controls and that can have different meaning.

<maps:MapControl Name="maps" Style="Aerial3D"/>

Of course, in case of the 3D View, it’s better to change default angle for map camera. You can do it usingthe static method of MapScene class called CreateFromLocationAndRadius. Thanks to this method you can create a scene using radius (meters), zoom level and radius (degrees). Once you have MapScene object you need to use TrySetSceneAsync method to apply the scene:

await maps.TrySetSceneAsync(MapScene.CreateFromLocationAndRadius((await MapLocationFinder.FindLocationsAsync("Vancouver Downtown, BC", null)).Locations[0].Point,500,90,60));

If you run my code you will see center of Vancouver in 3D:

clip_image005

So, applying 3D view is easy. The same works for the StreetView functionality. If you want to use the street view you need just two lines of code:

StreetsidePanorama panorama=await StreetsidePanorama.FindNearbyAsync((await MapLocationFinder.FindLocationsAsync("Vancouver Downtown, BC", null)).Locations[0].Point); maps.CustomExperience = new StreetsideExperience(panorama);

If you run this code you can see something like this:

clip_image007

Of course, existing maps show lots of different information but if you integrate maps to your application, probably, you want to add your own objects to maps.

The simplest objects which you can add to the maps are MapIcon, MapPolygon and MapPolyline. For example, if you want to add an icon to the maps you can run the following code:

MapIcon mapIcon = new MapIcon(); mapIcon.Location = maps.Center; mapIcon.NormalizedAnchorPoint = new Point(0.5, 1.0); mapIcon.Image = RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///Assets/weather.png")); mapIcon.ZIndex = 0; maps.MapElements.Add(mapIcon);

You can use this code to place weather icons in the area, points of interest etc.

Additionally you can add XAML controls to the maps. In this case you need to use Children collection instead of MapElements as before. But it’s not enough to add XAML UI control, you need to place the control to the right position on the maps. In order to do it you can use the SetLocation method of the MapControl class. This method has two parameters: reference to added UI control and location.

Therefore you can see that the current version of MapControl is very powerful and supports lots of features. It’s even possible to write a separate book just about this control. If you want to know more, the best starting point for you is Bing portal for developers. The portal contains lots of examples and information how to use Bing maps from JavaScript or in applications for alternative platforms.

Written by Sergiy Baydachnyy

07/20/2015 at 7:21 PM

UWP: 3D Transformation

with one comment

If you develop applications for Windows Phone 8.1 or Windows 8.1 you can use PlaneProjection class which allows applying 3D transformations to any UI elements. But PlaneProjection is very limited and provides only a way to make rotation. If you want to apply more complex 3D transformations you need to use MatrixTransform and implement your own math algorithms.

But starting with Windows 10 you have a way to make more complex 3D transforms using new classes like PerspectiveTransform3D and CompositeTransform3D. Let’s look at the following code:

<RelativePanel HorizontalAlignment="Center"> <RelativePanel.Transform3D> <PerspectiveTransform3D></PerspectiveTransform3D> </RelativePanel.Transform3D> <Image Source="Assets\drone.jpg" Width="400" Name="image"> <Image.Transform3D> <CompositeTransform3D CenterX="200" CenterY="100" RotationX="{x:Bind sliderX.Value,Mode=OneWay}" RotationY="{x:Bind sliderY.Value,Mode=OneWay}" RotationZ="{x:Bind sliderZ.Value,Mode=OneWay}"> </CompositeTransform3D> </Image.Transform3D> </Image> <Slider Maximum="360" RelativePanel.Below="image" Name="sliderX" Width="400" Margin="0,10,0,10"></Slider> <Slider Maximum="360" RelativePanel.Below="sliderX" Name="sliderY" Width="400" Margin="0,10,0,10"></Slider> <Slider Maximum="360" RelativePanel.Below="sliderY" Name="sliderZ" Width="400" Margin="0,10,0,10"></Slider> </RelativePanel>

If you execute the code you will see the screen below where you can rotate an image using three sliders:

clip_image002

Frankly speaking you would be able to make something like it using PlaneProjection as well but with this example we can understand syntax for new elements.

First of all you need to use PerspectiveTransform3D element and assign it to Transform3D property which is available for all UI elements. PerspectiveTransform3D allows to declare a common view port for all child elements. So you should think about it as about a perspective camera. You can move the camera using OffsetX and OffsetY properties but this movement will not affect position of your control inside the container – it just affects transformations because you have the same view port and any camera movement will add an angle which will affect projection only. PerspectiveTransform3D has Depth property as well which declares distance between camera and Z=0 plane. By default Depth is 1000 but you can change it and it affects transformations only as well. Frankly speaking I found that if you change Depth you will see unpredictable effects.

Once you apply PerspectiveTransform3D to any container you can use CompositeTransform3D to apply any transformations to elements inside view port. You can scale, translate and rotate UI elements.

At the same time I discovered two disadvantages there.

First of all CompositeTransform3D allows to set the center of the transformation but it requires to use pixels. So, if I want to make transformation around the center of a control I need to calculate actual size. It’s strange because even PlaneProjection allows to set center in relative coordinates ((0.5, 0.5) – center).

The second disadvantage is a problem with correct placement of controls in the space – elements are rendered in XAML order, one by one. So, elements that are closer to each other can be placed behind elements that are not so close. MSDN recommends to use workaround (Canvas.ZIndex) but it requires to implement complex code which should change ZIndex dynamically. Additionally, there are lots of tasks when ZIndex doesn’t help. So, in the current version you cannot use these classes for more complex scenarios.

If you need to build complex 3D models I would recommend to use WebView and implement your model there using CSS 3D. Since Windows 10, WebView is based on Microsoft Edge and support preserve-3d value for 3d transformation.

clip_image004

Written by Sergiy Baydachnyy

07/17/2015 at 6:44 PM

Tailored views or one more way to create Universal interfaces

with one comment

If you visit what’s new for developers in Windows 10 page you can see the following sentence there:

“XAML provides new support for defining tailored views (.xaml files) that share the same code file.”

Of course this feature can be very useful because in some cases it’s not easy to create really universal pages. For example, you can adopt all controls but you need to remember that phone users usually use just one hand to work with applications. So, you need to adopt not just layout but user experience as well.

That’s why I tried to investigate what this sentence means. Looks like this feature is still in development and you will not find any docs about it but you already can test existing implementation.

In current version of UWP you already can create separate XAML for desktop and mobile pages. In order to do it you need to add a new XAML View to your project.

clip_image002

You can see that XAML Veiw template will create XAML page only without code behind file. Of course, it’s not enough and in order to associate a new view with page by default you need to select one of the two approaches:

· You can place the view to the same folder with the initial page and you need to call the view using the name of the initial page and add a prefix. I discovered two prefixes right now – DeviceFamily-Mobile and DeviceFamily-Desktop. I didn’t have a chance to test Xbox and I found that DeviceFamaly-IoT doesn’t work;

· You can use the same name for the view which has the page by default but you need to place the view to the special folder – DeviceFamily-Mobile or DeviceFamily-Desktop;

clip_image003

That’s all. If you run our application on the phone and you will have a view under DeviceFamily-Mobile rule then the view will be applied but if you didn’t implement a new view around DeviceFamily-Mobile then XAML by default will be applied. The same things work for desktop.

Pay special attention that it’s in preview now and even no docs have been published.

Written by Sergiy Baydachnyy

07/14/2015 at 4:35 AM

UWP: New Controls (part 2 – SplitView)

with 2 comments

Another control which allows to create adaptive interfaces is SplitView. Usually you will use this control to create menus but in fact SplitView allows to declare two panels, Pane and Content, with any content inside. Particularly the Pane panel allows to add some adaptive capabilities by supporting different display modes. The main syntax of SplitView is

<SplitView IsPaneOpen="False" DisplayMode="CompactInline" PaneBackground="Beige" OpenPaneLength="200" CompactPaneLength="30"> <SplitView.Pane> </SplitView.Pane> <SplitView.Content> </SplitView.Content> </SplitView>

Where the DisplayMode property can be set in one of the following values:

· CompactInline – Pane panel supports compact mode. When it is expanded all content will be moved in order to provide enough space for expanded panel;

· CompactOverlay – the same as the previous mode but when panel is expanded it doesn’t affect all other content because the panel will be placed above the content;

· Inline – supported in expanded mode only. If it is displayed then all other content will be moved to have enough space for the panel;

· Overlay – supported in expanded mode only. It doesn’t affect all other content because the panel will be placed above the content;

With the help of the IsPaneOpen you can define if the panel is displayed in standard mode or if the panel is expanded (or compact) in compact mode. So, if you set IsPaneOpen to false and display mode is compact then the panel will be displayed in compact mode. If you change IsPaneOpen to true then the panel will be displayed in expanded mode.

So, you can see that SplitView doesn’t have anything related to menus but you can easily place something like ListView inside and declare menu items there. Design the menu items in the way that users can see only icons in the compact mode and all of the content in expanded mode, and implement VisualStateManager which changes DisplayMode and IsPaneOpen properties in runtime.

I would would advise to follow these recommendations in order to design your own menu:

· Implement three states for your menu: Expanded, Compact and UltraCompact for different screen sizes. If you have enough space you can show the Pane in expanded mode without any problems but if you have less space you can show just icons in compact mode. Finally if you don’t have room at all (phone in portrait orientation) you should activate UltraCompact state and hide your Pane completely;

· In Compact and UltraCompact states add a bullet button above the menu which opens the Pane using Overlay modes. So, you will be able to open the menu even in UltraCompact mode when menu is hidden;

clip_image002

· Use ListView control for menu;

So your VisualStateManager can look like this (CompactInline as default and IsPaneOpen is True):

<VisualState x:Name="Expanded"> <VisualState.StateTriggers> <AdaptiveTrigger MinWindowWidth="900"></AdaptiveTrigger> </VisualState.StateTriggers> </VisualState> <VisualState x:Name="Compact"> <VisualState.Setters> <Setter Value="False" Target="splitView.IsPaneOpen"></Setter> <Setter Value="CompactOverlay" Target="splitView.DisplayMode"></Setter> </VisualState.Setters> <VisualState.StateTriggers> <AdaptiveTrigger MinWindowWidth="500"></AdaptiveTrigger> </VisualState.StateTriggers> </VisualState> <VisualState x:Name="UltraCompact"> <VisualState.Setters> <Setter Value="False" Target="splitView.IsPaneOpen"></Setter> <Setter Value="Overlay" Target="splitView.DisplayMode"></Setter> </VisualState.Setters> <VisualState.StateTriggers> <AdaptiveTrigger MinWindowWidth="0"></AdaptiveTrigger> </VisualState.StateTriggers> </VisualState>

If you implement a bullet button you need to add logic which allows to expand menu as well. You can implement all logic inside code behind or you can try to create two more states and your own triggers there.

Written by Sergiy Baydachnyy

07/14/2015 at 4:33 AM

UWP: New Controls (part 1 – RelativePanel)

with one comment

In the next posts I am going to discuss new controls which are available for Windows 10 developers. And today I am going to start with a new layout control RelativePanel. For better understanding of the control I will start my post with a short example:

<Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition Height="*"></RowDefinition> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"></ColumnDefinition> <ColumnDefinition Width="*"></ColumnDefinition> </Grid.ColumnDefinitions> <TextBlock Text="This is a header" Grid.ColumnSpan="2" Style="{ThemeResource HeaderTextBlockStyle}"></TextBlock> <Image MaxWidth="800" Grid.Row="1" Source="Assets\drone.jpg" VerticalAlignment="Top"></Image> <TextBlock Text="This is a text about drones." Margin="10,0,10,0" TextWrapping="Wrap" Grid.Column="1" Grid.Row="1"></TextBlock> </Grid>

In this example I implemented a simple layout which uses Grid element to place two text blocks and an image. So, if you run this code you can see something like this:

clip_image002

But there is a problem, Windows 10 allows to change size of windows and additionally I can run this application on phones. So it’s easy to see that I don’t have enough space to show image and text if I have a smaller window. Because I want to create a universal interface I should change my layout dynamically if I don’t have enough space. Probably I simply need to place the text below the image and VisualStateManager is the best way to do this. But I used Grid container which has two columns and two rows and for smaller display I need a grid with one column and three rows which is virtually impossible to manage in VisualStateManager even for my example (but the real interfaces are much more complex). That’s why when developers build universal applications for Windows 8.1 they duplicate some parts of the interface and simply work with Visibility property inside VisualStateManager.

Starting with Windows 10, developers have a chance to use the new container which allows to avoid problems with Grid – it’s RelativePanel. Let’s see the same example but inside RelativePanel control.

<RelativePanel > <TextBlock Text="This is a header" Name="header" Style="{ThemeResource HeaderTextBlockStyle}"></TextBlock> <Image Name="image" MaxWidth="800" RelativePanel.Below="header" Source="Assets\drone.jpg"></Image> <TextBlock Text="This is a text about drones." Margin="10,0,10,0" TextWrapping="Wrap" RelativePanel.AlignTopWith="image" RelativePanel.RightOf="image" Name="text"></TextBlock> </RelativePanel>

You can see that in case of RalativePanel you can declare position of embedded controls using dependency properties. Because it’s just properties, it’s easy to reformat layout using them in VisualStateManager. For example, you can use the following code to show the same interface in one row:

<VisualStateManager.VisualStateGroups> <VisualStateGroup> <VisualState x:Name="Normal"> <VisualState.StateTriggers> <AdaptiveTrigger MinWindowWidth="900"></AdaptiveTrigger> </VisualState.StateTriggers> </VisualState> <VisualState x:Name="Mobile"> <VisualState.Setters> <Setter Value="" Target="text.(RelativePanel.AlignTopWith)"></Setter> <Setter Value="image" Target="text.(RelativePanel.Below)"></Setter> <Setter Value="" Target="text.(RelativePanel.RightOf)"></Setter> <Setter Value="0,10,0,10" Target="text.Margin"></Setter> </VisualState.Setters> <VisualState.StateTriggers> <AdaptiveTrigger MinWindowWidth="0"></AdaptiveTrigger> </VisualState.StateTriggers> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups>

Once the window is less than 900 pixels, the text is moved below the image. Pay special attention how to declare dependency properties in the Target attribute.

So, let’s use this powerful control, and according to my experience, Relative panel is the most popular control for creating universal interface now.

Written by Sergiy Baydachnyy

07/06/2015 at 6:59 PM

UWP: How to handle changes of DependencyProperty

with 2 comments

Last time we discussed how to create our own state trigger. In order to do it we made some extensions of “view model” class in order to get information about changes in state of the model. We declared a delegate and an event there and additionally we injected code which initiated external event handlers. But in many cases you cannot modify a class which you are going to use in your trigger and the class doesn’t have needed events as well. In this case you can check dependency properties there.

Starting with Windows 10 you can handle changes in dependency properties even if the class doesn’t have any special events for it. It’s possible thanks to RegisterPropertyChangedCallback (and UnregisterPropertyChangedCallback) method which was included to DependencyObject class. Thanks to this method you can provide an event handler which fires when selected DependencyProperty is changed. This method is very useful for UWP controls when you need to track changes in existing controls but we can utilize this method in our classes as well.

Let’s try to modify classes from the previous post.

public enum StateEnum { Loading, Loaded, Error } public class PageViewModel: DependencyObject { public static readonly DependencyProperty StateProperty= DependencyProperty.Register("State",typeof(StateEnum), typeof(PageViewModel),new PropertyMetadata(null)); public StateEnum State { get { return (StateEnum)GetValue(StateProperty); } set { SetValue(StateProperty, value); } } public void InitModel() { State = StateEnum.Loading; //load data State = StateEnum.Loaded; } }

You can see that I removed the delegate and the event and added a StateProperty dependency property. Right now code looks better and usually if you implement your own “view model” class you already have some dependency properties there and probably you should not change anything.

Of course, in order to work with dependency properties we use the SetValue and GetValue methods. We used standard approach there – created a wrapper property. It’s clear that all changes around DependencyProperty in UWP were implemented inside the SetValue method. It just executed all methods which were registered thanks to RegisterPropertyChangedCallback.

My state trigger will look different as well:

public class DataTrigger: StateTriggerBase { private PageViewModel model; public PageViewModel Model { get { return model; } set { model = value; model.RegisterPropertyChangedCallback(PageViewModel.StateProperty, new DependencyPropertyChangedCallback(ChangeState)); } } private void ChangeState(DependencyObject obj, DependencyProperty pr) { SetActive(model.GetValue(PageViewModel.StateProperty). ToString().Equals(StateOfModel)); } public string StateOfModel { get; set; } }

You can see that code looks better right now. Pay special attention that we use PageViewModel object to call RegisterPropertyChangedCallback method.

So, if you don’t have all needed events, check existing dependency properties and in many cases you find all that you need.

Written by Sergiy Baydachnyy

07/05/2015 at 1:50 AM