Visually Located

XAML and GIS

Setting the device wallpaper in Windows Universal Apps

Windows 10 launched today and with it comes a new SDK for building “Universal Apps”. This new SDK comes with a lot of new functionality. One of those pieces is a new way to set the wallpaper of a device. This new API is available on the new UserProfilePersonalizationSettings class. This class is used for setting the lockscreen, and the device wallpaper. The new UserProfilePersonalizationSettings class has a TrySetWallpaperImageAsync method that accepts any local StorageFile (I have not been able to set the wallpaper using the FileOpenPicker). This means you can save an image to the local or roaming folders, or use an existing image packaged with your app.

var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/AwesomeWallpaper.jpg"));
await Windows.System.UserProfile.UserProfilePersonalizationSettings.Current.TrySetWallpaperImageAsync(file);

This example uses a file packaged with the app in the Assets folder.

image

You should check if the device has the ability to change the wallpaper. I’m guessing this is in place for future Windows settings.

if (Windows.System.UserProfile.UserProfilePersonalizationSettings.IsSupported())
{
    var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/AwesomeWallpaper.jpg"));
    await UserProfilePersonalizationSettings.Current.TrySetWallpaperImageAsync(file);
}

Now go and create some amazing wallpaper apps for Windows 10

Setting the lockscreen in Windows Universal Apps

Windows 10 launched today and with it comes a new SDK for building “Universal Apps”. This new SDK comes with a lot of new functionality. One of those pieces is a new way to set the lockscreen of a device. This new API is available on the new UserProfilePersonalizationSettings class. Previously you only had the ability to set the lockscreen within phone apps using the SetImageUri method on the static LockScreen class. The method accepted a Uri that had to be local to the app.

Windows.Phone.System.UserProfile.LockScreen.SetImageUri(new Uri(localFileName));

The new UserProfilePersonalizationSettings class has a TrySetLockScreenImageAsync method that accepts any local StorageFile (I have not been able to set the lockscreen using the FileOpenPicker). This means you can save an image to the local or roaming folders, or use an existing image packaged with your app.

var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/AwesomeLockscreen.jpg"));
await Windows.System.UserProfile.UserProfilePersonalizationSettings.Current.TrySetLockScreenImageAsync(file);

This example uses a file packaged with the app in the Assets folder.

image

You should check if the device has the ability to change the lockscreen. I’m guessing this is in place for future Windows settings.

if (Windows.System.UserProfile.UserProfilePersonalizationSettings.IsSupported())
{
    var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/AwesomeLockscreen.jpg"));
    await UserProfilePersonalizationSettings.Current.TrySetLockScreenImageAsync(file);
}

Now go and create some amazing lockscreen apps for Windows 10

Persist ListView scroll position without setting NavigationCacheMode

In a previous post I wrote about why your ListView resets to the top of the list when navigating backwards. In that post I looked at using the NavigationCacheMode of the page to persist the scroll position of your ListView. I also briefly mentioned using the ScrollIntoView method of the ListView. In this post we’ll look at a little known helper class that allows you to keep your scroll position without using all the memory that NavigationCacheMode can use.

ListViewPersistenceHelper

The ListViewPersistenceHelper class allows you to easily restore the scroll position with only two methods, GetRelativeScrollPosition and SetRelativeScrollPositionAsync. These methods use the item that is at the top of the list as indicators for where the scroll position should be.

The GetRelativeScrollPosition should be called when navigating away from the page. A good place is the OnNavigatedFrom method.

protected override void OnNavigatedFrom(NavigationEventArgs e)
{
    _positionKey = ListViewPersistenceHelper.GetRelativeScrollPosition(myListView, ItemToKeyHandler);
    base.OnNavigatedFrom(e);
}
 
private string ItemToKeyHandler(object item)
{
    MyDataItem dataItem = item as MyDataItem;
    if (dataItem == null) return null;
 
    return dataItem.Id;
}

The SetRelativeScrollPositionAsync method tells the ListView where to scroll to. A good place to call this method is in the OnNavigatedTo method.

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    base.OnNavigatedTo(e);
    if (_positionKey == null) return;
 
    ListViewPersistenceHelper.SetRelativeScrollPositionAsync(myListView, _positionKey, KeyToItemHandler);
}
 
private IAsyncOperation<object> KeyToItemHandler(string key)
{
    Func<System.Threading.CancellationToken, System.Threading.Tasks.Task<object>> taskProvider = token =>
    {
        var viewModel = DataContext as MyViewModel;
        if (viewModel == null) return null;
        foreach (var item in viewModel.Items)
        {
            if (item.Id == key) return Task.FromResult(item as object);
        }
        return Task.FromResult((object)null);
    };
 
    return AsyncInfo.Run(taskProvider);
}

In this simple example I’m storing the _positionKey key in a static field. This is ok for a simple case, but you may want to store this somewhere else.

Precautions:

I did notice that if you are animating the items of your ListView and using the ListViewPersistenceHelper, that there are some unintended side effects. The first few items of your ListView will still show the animation when navigating backward while the other items remain still. You can see this in the image below.

Animating side-effect

A simple work around for this is to reset the ItemContainerTransitions of the ListView in the OnNavigatedTo method if the _positionKey is not null.

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    base.OnNavigatedTo(e);
    if (_positionKey == null) return;  
 
    myListView.ItemContainerTransitions = new TransitionCollection();
    ListViewPersistenceHelper.SetRelativeScrollPositionAsync(itemListView, _positionKey, KeyToItemHandler);
}

Hopefully this will help your apps use less memory while still maintaining a great experience for your users!

Easily create Microsoft Band Web Tiles with the Web Tiles Authoring website

The Microsoft Band team released “Web Tiles” today. Web Tiles are a simple way to show tiles on your Microsoft Band without needing to write an app. The tiles update from a web url. As far as I can tell, the web url must return json data. This data can be whatever but it needs to be open to everyone meaning no authentication. All of the articles today talk about the structure of a web tile and what each piece means. All this information is great, but if you only need a simple tile you can do without it.

Along with the release of Web Tiles, Microsoft also released a Web Tiles Authoring website. This website walks you through creating a new tile step by step. Let’s take a look at how this works

Step 1: Choose a layout

Here you pick which of the six layouts you’d like to use for the tile. You can choose from displaying a single page tile or multiple page tile. Multiple page tiles must link to an RSS or ATOM feed. This is not a requirement of web tiles; it is only a requirement for the authoring tool. Web tiles can have multiple pages without needing an ATOM or RSS feed.

Choose a layout

Step 2: Assign the url

Here you enter the url that will contain the data for your tile. If you picked a multiple page layout from Step 1, you must enter a URL for RSS or an ATOM feed. Again, this is not a requirement for web tiles, only for the authoring tool.

Assign the url

Step 3: Selecting information to display

Here you select what information from your json feed you would like to display. You simply drag the data from the right and drop it onto the place you’d like to display it.

Select information-a     Select information-b

Here we see that I selected to display the weather with the state being the header, the second line being the temp and the third line being some description.

Step 4: Make it yours

Here you’ll set the information to make the tile yours.

 Make it yours

Step 5: Download!

Download this awesome web tile to send to your favorite people

download

Hopefully the tool will be improved to allow for multiple pages when your resource is not an ATOM or RSS feed.

A simpler FilePicker for Windows Phone and Windows apps

If you’ve built a Windows Phone app that uses the FileOpenPicker you know that it can be a pain while the Windows variation is pretty simple to use. In Windows you use the PickSingleFileAsync method and continue code as you think you would.

StorageFile storageFile = await openPicker.PickSingleFileAsync();
// Do something with the file

However in Windows Phone this becomes a little more complex. It’s especially complex when you look at the sample on MSDN. First you call the PickSingleFileAndContinue method, then in App.xaml.cs wait for the app to be activated, then somehow get back to where you were before. It’s a mess. I wanted to make this easier in a recent app I was working on and I wanted it to work the same for Windows and Windows Phone.

To get started you’ll need to know that the CoreApplicationView can give us access to when the app is activated. With this, we can bypass all the weirdness of using the App class.

CoreApplication.GetCurrentView().Activated += OnViewActivated
...
...
private async void OnViewActivated(CoreApplicationView sender, IActivatedEventArgs args)
{
    sender.Activated -= OnViewActivated;
    // do some stuff
}

Let’s create a new Picker that will get any image files. We’ll create a new ImagePicker class. This class will be a shared class between Windows and Windows Phone apps. Let’s stub that out now.

public class ImagePicker
{
    public Task<IRandomAccessStream> PickAsync()
    {
        // TODO: this
    }
}

Pretty simple class, right? Let’s fill in the pieces. We’ll still use the FileOpenPicker within the PickAsync method. This is an ImagePicker so we want to state that it needs to look for images

public Task<IRandomAccessStream> PickAsync()
{
    FileOpenPicker openPicker = new FileOpenPicker();
    openPicker.ViewMode = PickerViewMode.Thumbnail;
    openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
    openPicker.FileTypeFilter.Add(".jpg");
    openPicker.FileTypeFilter.Add(".jpeg");
    openPicker.FileTypeFilter.Add(".png");
 
    // TODO: the rest
}

At this point we need to break up into Windows Phone code and Windows code

private TaskCompletionSource<IRandomAccessStream> _imageCompletionSource;
 
#if WINDOWS_PHONE_APP
public Task<IRandomAccessStream> PickAsync()
#else
public async Task<IRandomAccessStream> PickAsync()
#endif
{
    FileOpenPicker openPicker = new FileOpenPicker();
    openPicker.ViewMode = PickerViewMode.Thumbnail;
    openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
    openPicker.FileTypeFilter.Add(".jpg");
    openPicker.FileTypeFilter.Add(".jpeg");
    openPicker.FileTypeFilter.Add(".png");
 
#if WINDOWS_PHONE_APP
    _imageCompletionSource = new TaskCompletionSource<IRandomAccessStream>();
    CoreApplication.GetCurrentView().Activated += OnViewActivated;
    openPicker.PickSingleFileAndContinue();
    return _imageCompletionSource.Task;
#else
    StorageFile storageFile = await openPicker.PickSingleFileAsync();
    return await storageFile.OpenAsync(FileAccessMode.Read);
#endif
}

Notice for Windows Phone we will use a TaskCompletionSource to return the value. The result for the TaskCompletionSource will be set in the OnViewActivated method.

private async void OnViewActivated(CoreApplicationView sender, IActivatedEventArgs args)
{
    sender.Activated -= OnViewActivated;
    FileOpenPickerContinuationEventArgs pickerArgs = args as FileOpenPickerContinuationEventArgs;
 
    IRandomAccessStream stream = null;
    if (pickerArgs != null)
    {
        if (pickerArgs.Files.Count > 0)
        {
            StorageFile storageFile = pickerArgs.Files[0];
            stream = await storageFile.OpenAsync(FileAccessMode.Read);
        }
    }
    _imageCompletionSource.SetResult(stream);
}

Now with this simple class you can pick an image file like such

var picker = new ImagePicker();
var accessStream = await picker.PickAsync();

And that works the same for both Windows and Windows Phone. I did test this on a low memory device and it did work there as well!

You can find a “generic” version of this class here.

Creating a behavior or action to close a Flyout from a control within the Flyout

I recently started work on a new project and I’m trying hard to use “no code-behind”. This has been challenging for me as I tend to always put very view specific logic within the view itself. Things like navigation, starting storyboards or showing popups/flyouts. One thing I was trying to do recently was close a Flyout from a button within the flyout. My first approach was to try an EventTriggerBehavior for the Click event of the button along with the CallMethodAction. I tried two ways to call the Hide method on the flyout.

   1: <Button x:Name="AddButton" Content="Add Item" >
   2:     <Button.Flyout>
   3:         <Flyout x:Name="AddItemFlyout"
   4:                 Placement="Full">
   5:             <StackPanel>
   6:                 <TextBox x:Name="PlaceName" Header="Name"/>
   7:                 <Grid>
   8:                     <Grid.ColumnDefinitions>
   9:                         <ColumnDefinition/>
  10:                         <ColumnDefinition/>
  11:                     </Grid.ColumnDefinitions>
  12:                     <Button Content="Cancel" Margin="0,0,9.5,0" >
  13:                         <interactivity:Interaction.Behaviors>
  14:                             <core:EventTriggerBehavior EventName="Click">
  15:                                 <core:CallMethodAction TargetObject="{Binding ElementName=AddItemFlyout}"
  16:                                                        MethodName="Hide" />
  17:                             </core:EventTriggerBehavior>
  18:                         </interactivity:Interaction.Behaviors>
  19:                     </Button>
  20:                     <Button Content="Create" Grid.Column="1" Margin="9.5,0,0,0" 
  21:                             Command="{Binding CreateItemCommand}" 
  22:                             CommandParameter="{Binding Text, ElementName=PlaceName}">
  23:                         <interactivity:Interaction.Behaviors>
  24:                             <core:EventTriggerBehavior  EventName="Click">
  25:                                 <core:CallMethodAction TargetObject="{Binding Flyout, ElementName=AddButton}"
  26:                                                        MethodName="Hide" />
  27:                             </core:EventTriggerBehavior>
  28:                         </interactivity:Interaction.Behaviors>
  29:                     </Button>
  30:                 </Grid>
  31:             </StackPanel>
  32:         </Flyout>
  33:     </Button.Flyout>
  34: </Button>

Notice in the cancel button I tried hooking into the flyout by name and the create button I tried accessing the Flyout property of the button. Neither one of these would close the flyout. I searched online and found that this is not a new problem. Someone asked a question on StackOverflow a year ago.

My next step was to create a behavior and define a Flyout dependency property on it. When the button was clicked it would hide the flyout. This did not work because the Flyout property was always null. I tried setting it two different ways just as I had before.

With these not working I decided to walk the tree until I hit the Flyout and close it.

var flyout = AssociatedObject.GetVisualParent<Flyout>();
if(flyout != null)
{
    flyout.Hide();
}

NOTE: This uses an extension method for walking up the visual tree using the VisualTreeHelper.

This didn’t work because the Flyout is not an visual control. A Flyout is rendered with the FlyoutPresenter control. That’s all fine and dandy, but the FlyoutPresenter does not offer a way to close itself. So what to do? I went to XamlSpy to have a look at what is rendering the Flyout.

xamlspy

XamlSpy shows us that a popup is rendering the FlyoutPresenter. Perfect, we’ll walk the tree until we get to the popup, and then set IsOpen to false;

var popup = AssociatedObject.GetVisualParent<Popup>();
if(popup != null)
{
    popup.IsOpen = false;
}

Sweet! Let’s run this and watch the Flyout close! Click button… Wait… why isn’t it closing… Popup is null? Huh? It turns out that the VisualTreeHelper reports that the FlyoutPresenter does not have a parent. The VisualTreeHelper may report there isn’t a parent, but luckily the Parent property on the FlyoutPresenter does give us the Popup!

var flyout = AssociatedObject.GetVisualParent<FlyoutPresenter>();
if (flyout != null)
{
    var popup = flyout.Parent as Popup;
    if (popup != null)
    {
        popup.IsOpen = false;
    }
}

This allows the Flyout to close and even fires off the Closed event.

Here is some code to make this into a behavior that only works on buttons.

public class CloseFlyoutBehavior : Behavior<Button>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.Click += AssociatedObjectOnClick;
    }
    private void AssociatedObjectOnClick(object sender, RoutedEventArgs routedEventArgs)
    {
        var flyout = AssociatedObject.GetVisualParent<FlyoutPresenter>();
        if (flyout != null)
        {
            var popup = flyout.Parent as Popup;
            if (popup != null)
            {
                popup.IsOpen = false;
            }
        }
    }
}

Note that this uses the Behavior base class I previously wrote about.

And if you’d like to make this into an action that can work for anything.

public class CloseFlyoutAction : IAction
{
    public object Execute(object sender, object parameter)
    {
        var element = sender as FrameworkElement;
        if (element == null) return null;
 
        var flyout = element.GetVisualParent<FlyoutPresenter>();
        if (flyout != null)
        {
            var popup = flyout.Parent as Popup;
            if (popup != null)
            {
                popup.IsOpen = false;
            }
        }
        return null;
    }
}

Animating list items within Windows apps

In a previous post I’ve talked about some page transitions and animations within Windows apps. There are many other locations where adding animations is very easy. One of these is animating items within any ItemsControl class. This includes controls like the ListView/GridView controls. The ItemsControl exposes the ItemContainerTransitions property. This property exposes a TransitionCollection, the same collection I talked about in the previous post. One of the key transitions you’ll want to look at is the EntranceThemeTransition.

The EntranceThemeTransition defines how items will enter the region when they are rendered. It contains three properties. FromVerticalOffset and FromHorizontalOffset define the where the item should start rendering, with respect to where the final location will be. So if you have a FromVerticalOffset of 100, the item will begin an entrance animation 100 pixels below where it will end. The last property IsStaggeringEnabled, defines if all items should animate at once, or if the animation should be staggered. I really like setting this to true for some great animations.

 

Here are some examples of using the EntranceThemeTransition to animate items.

Animate a list of items from the right

Set FromVerticalOffset to 0, and FromHorizontalOffset to your desired value.

<ListView.ItemContainerTransitions>
    <TransitionCollection>
        <EntranceThemeTransition IsStaggeringEnabled="True" 
                                 FromVerticalOffset="0" 
                                 FromHorizontalOffset="200"/>
        <AddDeleteThemeTransition/>
        <NavigationThemeTransition/>
        <ContentThemeTransition/>
    </TransitionCollection>
</ListView.ItemContainerTransitions>
Animate a list of items from the bottom

Set FromHorizontalOffset to 0, and FromVerticalOffset to your desired value.

<ListView.ItemContainerTransitions>
    <TransitionCollection>
        <EntranceThemeTransition IsStaggeringEnabled="True" 
                                 FromVerticalOffset="200" 
                                 FromHorizontalOffset="0"/>
        <AddDeleteThemeTransition/>
        <NavigationThemeTransition/>
        <ContentThemeTransition/>
    </TransitionCollection>
</ListView.ItemContainerTransitions>
Animate a list of items diagonally

Set both FromVerticalOffset  and FromHorizontalOffset to your desired value.

<ListView.ItemContainerTransitions>
    <TransitionCollection>
        <EntranceThemeTransition IsStaggeringEnabled="True" 
                                 FromVerticalOffset="200" 
                                 FromHorizontalOffset="200"/>
        <AddDeleteThemeTransition/>
        <NavigationThemeTransition/>
        <ContentThemeTransition/>
    </TransitionCollection>
</ListView.ItemContainerTransitions>
Animate a grid of items from the left

Set FromVerticalOffset  to 0, and  FromHorizontalOffset to a negative value.

<GridView.ItemContainerTransitions>
    <TransitionCollection>
        <EntranceThemeTransition IsStaggeringEnabled="True" 
                                 FromVerticalOffset="0" 
                                 FromHorizontalOffset="-200"/>
        <AddDeleteThemeTransition/>
        <NavigationThemeTransition/>
        <ContentThemeTransition/>
    </TransitionCollection>
</GridView.ItemContainerTransitions>

Play with the EntranceThemeTransition and come up with some great animations!

In depth look at the Windows RelativePanel

Windows 10 released a lot of new functionality and controls. One of the new controls is the RelativePanel. This panel takes the great Grid panel and cranks it up to 11.

The Grid panel gives a lot of control with how you layout controls. You specify rows and columns of various heights and widths and then place controls within the grid and define the row and/or column through attached properties. Instead of rows/columns, the RelativePanel places controls relative to itself or other controls within it. Just like the Grid, the RelativePanel uses 16 different attached properties to define where elements should be placed. In fact, the RelativePanel has no additional properties or methods from a regular Panel. It only contains attached properties.

Aligning relative to the RelativePanel

The relative panel does not respect controls with traditional alignment via HorizontalAlignment and VerticalAlignment. Instead there are six new properties to define how an element should align relative to the RelativePanel. These properties are boolean values that specify if it should align.

The following table shows the new attached properties.

Attached Property Default value Horizontal/VerticalAlignment equivalent
RelativePanel.AlignBottomWithPanel false VerticalAlignment=”Bottom”
RelativePanel.AlignHorizontalCenterWithPanel false HorizontalAlignment=”Center”
RelativePanel.AlignLeftWithPanel true HorizontalAlignment=”Left”
RelativePanel.AlignRightWithPanel false HorizontalAlignment=”Right”
RelativePanel.AlignTopWithPanel true VerticalAlignment=”Top”
RelativePanel.AlignVerticalCenterWithPanel false VerticalAlignment=”Center”

 

You can combine these values just as you could with HorizontalAlignment and VerticalAlignment. If you would like to center a control in the panel:

<RelativePanel>
    <Border Width="100" Height="100" Background="Blue" 
            RelativePanel.AlignHorizontalCenterWithPanel="True"
            RelativePanel.AlignVerticalCenterWithPanel="True"/>
</RelativePanel>

Center

By themselves, these six new properties are not very exciting. They are equivalent to the HorizontalAlignment and VerticalAlignment properties. The awesomeness comes from aligning with other elements.

NOTE: If you are following along with the blog, you will notice the designer, in both Visual Studio and Blend, will only render elements with the above properties correctly. It will not render elements with the properties below correctly. You will need to run the application to see the layout.

Align relative to other elements

This is where the RelativePanel shines. With the Grid control you had to create many different rows and columns. You had to know the row and/or column of a particular control. Then you assign the row and/or column of a control you wanted next to the first. Here is an example displaying name of someone

<TextBlock Text="Name" Grid.Row="1" Grid.Column="1"/>
<TextBlock Text="Shawn Kendrot" Grid.Row="1" Grid.Column="2" Margin="12,0,0,0"/>

Here is how you would accomplish that with the RelativePanel

<TextBlock x:Name="NameText" Text="Name"/>
<TextBlock Text="Shawn Kendrot" RelativePanel.RightOf="NameText" Margin="12,0,0,0"/>

When you want to align one control to the right of another another, simple say so!

Let’s take a look at the 10 new attached properties that allow for relative placement of one control with another.

Above

Aligns an element vertically above another element. This alone will not place an element directly above an element.

<RelativePanel>
    <Border x:Name="ElementOne" Width="200" Height="200" Background="Red" 
            RelativePanel.AlignHorizontalCenterWithPanel="True"
            RelativePanel.AlignVerticalCenterWithPanel="True"/>
    <Border x:Name="ElementTwo" Width="100" Height="100" Background="Blue" 
            RelativePanel.Above="ElementOne"/>
</RelativePanel>
Above-Windows

AlignBottomWith

Vertically aligns the bottom of a control with the bottom of another control. This property will not affect the horizontal alignment of the control.

<RelativePanel>
    <Border x:Name="ElementOne" Width="200" Height="200" Background="Red" 
            RelativePanel.AlignHorizontalCenterWithPanel="True"
            RelativePanel.AlignVerticalCenterWithPanel="True"/>
    <Border x:Name="ElementTwo" Width="100" Height="100" Background="Blue" 
            RelativePanel.AlignBottomWith="ElementOne"/>
</RelativePanel>

BottomWith

AlignHorizontalCenterWith

Horizontally aligns the center of one control with the center of another control. This property will not affect vertical alignment of the control.

<RelativePanel>
    <Border x:Name="ElementOne" Width="200" Height="200" Background="Red" 
            RelativePanel.AlignHorizontalCenterWithPanel="True"
            RelativePanel.AlignVerticalCenterWithPanel="True"/>
    <Border x:Name="ElementTwo" Width="100" Height="100" Background="Blue" 
            RelativePanel.AlignHorizontalCenterWith="ElementOne"/>
</RelativePanel>

HorizontalCenterWith

AlignLeftWith

Horizontally aligns the left edge of the control with the left edge of another control. This will not affect vertical alignment.

<RelativePanel>
    <Border x:Name="ElementOne" Width="200" Height="200" Background="Red" 
            RelativePanel.AlignHorizontalCenterWithPanel="True"
            RelativePanel.AlignVerticalCenterWithPanel="True"/>
    <Border x:Name="ElementTwo" Width="100" Height="100" Background="Blue" 
            RelativePanel.AlignLeftWith="ElementOne"/>
</RelativePanel>

LeftWith

AlignRightWith

Horizontally aligns the right edge of the control with the right edge of another control. This will not affect vertical alignment.

<RelativePanel>
    <Border x:Name="ElementOne" Width="200" Height="200" Background="Red" 
            RelativePanel.AlignHorizontalCenterWithPanel="True"
            RelativePanel.AlignVerticalCenterWithPanel="True"/>
    <Border x:Name="ElementTwo" Width="100" Height="100" Background="Blue" 
            RelativePanel.AlignRightWith="ElementOne"/>
</RelativePanel>

RightWith

AlignTopWith

Vertically aligns the top edge of the control with the top edge of another control. This will not affect horizontal alignment.

<RelativePanel>
    <Border x:Name="ElementOne" Width="200" Height="200" Background="Red" 
            RelativePanel.AlignHorizontalCenterWithPanel="True"
            RelativePanel.AlignVerticalCenterWithPanel="True"/>
    <Border x:Name="ElementTwo" Width="100" Height="100" Background="Blue" 
            RelativePanel.AlignTopWith="ElementOne"/>
</RelativePanel>

TopWith

AlignVerticalCenterWith

Vertically aligns the center of one control with the center of another control. This will not affect horizontal alignment.

<RelativePanel>
    <Border x:Name="ElementOne" Width="200" Height="200" Background="Red" 
            RelativePanel.AlignHorizontalCenterWithPanel="True"
            RelativePanel.AlignVerticalCenterWithPanel="True"/>
    <Border x:Name="ElementTwo" Width="100" Height="100" Background="Blue" 
            RelativePanel.AlignVerticalCenterWith="ElementOne"/>
</RelativePanel>

VerticalCenterWith

Below

Vertically aligns an element below another element. This alone will not place an element directly below an element. This will align the top edge of one control with the bottom edge of another control.

<RelativePanel>
    <Border x:Name="ElementOne" Width="200" Height="200" Background="Red" 
            RelativePanel.AlignHorizontalCenterWithPanel="True"
            RelativePanel.AlignVerticalCenterWithPanel="True"/>
    <Border x:Name="ElementTwo" Width="100" Height="100" Background="Blue" 
            RelativePanel.Below="ElementOne"/>
</RelativePanel>

Below

LeftOf

Horizontally aligns the right edge of one control with the left edge of another control.

<RelativePanel>
    <Border x:Name="ElementOne" Width="200" Height="200" Background="Red" 
            RelativePanel.AlignHorizontalCenterWithPanel="True"
            RelativePanel.AlignVerticalCenterWithPanel="True"/>
    <Border x:Name="ElementTwo" Width="100" Height="100" Background="Blue" 
            RelativePanel.LeftOf="ElementOne"/>
</RelativePanel>

LeftOf

RightOf

Horizontally aligns the left edge of one control with the right edge of another control.

<RelativePanel>
    <Border x:Name="ElementOne" Width="200" Height="200" Background="Red" 
            RelativePanel.AlignHorizontalCenterWithPanel="True"
            RelativePanel.AlignVerticalCenterWithPanel="True"/>
    <Border x:Name="ElementTwo" Width="100" Height="100" Background="Blue" 
            RelativePanel.RightOf="ElementOne"/>
</RelativePanel>

RightOf

Combining properties

Combine the alignment properties for the true power of the RelativePanel. Align the side and top/bottom edges of a control with another for exact layout.

<RelativePanel>
    <Border x:Name="ElementOne" Width="200" Height="200" Background="Red" 
            RelativePanel.AlignHorizontalCenterWithPanel="True"
            RelativePanel.AlignVerticalCenterWithPanel="True"/>
    <TextBlock Text="Hello" Margin="12,0,0,0" 
               RelativePanel.RightOf="ElementOne" 
               RelativePanel.AlignTopWith="ElementOne"/>
    <TextBlock Text="World" Margin="12,0,0,0"
               RelativePanel.RightOf="ElementOne" 
               RelativePanel.AlignBottomWith="ElementOne"/>
</RelativePanel>

Combine

You can try combining multiple horizontal or vertical alignments. As you can imagine, trying to horizontally align with two or more properties will probably not work. It’s hard to align to the left of object one while also aligning right of another.

Precautions

It is possible for items to be rendered outside of the given area. Take the following example of an item aligned to the panels right, and another object aligned to the right of the first.

<RelativePanel>
    <Border x:Name="ElementOne" Width="200" Height="200" Background="Red" 
            RelativePanel.AlignRightWithPanel="True"/>
    <Border x:Name="ElementTwo" Width="100" Height="100" Background="Blue" 
            RelativePanel.RightOf="ElementOne"/>
</RelativePanel>

When this is rendered, the blue area will not be visible.

OffScreen

This is still the case if you limit the size of the RelativePanel. If an item is out of the panel, it will not render.

Layout cascades from one item to another. So if object one aligns with object two, and object three aligns with object two, if object one moves, then object two and three move along with it.

This new controls offers great possibilities. What will you create with it?

Creating different page views for Windows Apps based on the device

Windows 10 has released the new Universal App Platform that brings new “Windows Apps”. These apps offer the ability to use one Visual Studio project to create apps for any platform/device. This offers the ability to have one XAML file for all of your views. This works much like the web does with responsive design. If you want your page to look different on a smaller device you can change the layout based on the width of the device. You can do this with StateTriggers.

<VisualStateManager.VisualStateGroups>
    <VisualStateGroup>
        <VisualState x:Name="wideState">
            <VisualState.StateTriggers>
                <AdaptiveTrigger MinWindowWidth="600"/>
            </VisualState.StateTriggers>
            <VisualState.Setters>
                <Setter Target="MyTextBlock.Text" Value="BIGGER!" />
            </VisualState.Setters>
        </VisualState>
        <VisualState x:Name="narrowState">
            <VisualState.StateTriggers>
                <AdaptiveTrigger MinWindowWidth="0"/>
            </VisualState.StateTriggers>
            <VisualState.Setters>
                <Setter Target="MyTextBlock.Text" Value="little" />
            </VisualState.Setters>
        </VisualState>
    </VisualStateGroup>
</VisualStateManager.VisualStateGroups>

The example above changes the text of a TextBlock based on the width of the app. You can find more StateTriggers from Morten Nielsen and others on his github page.

But what if you do not want one xaml file? What if you want a completely different view for a phone and don’t want to base it on the width of the device? In Windows and Windows Phone 8.1 you had separate projects that could hold different views based on the device. This is still possible! And it’s quite easy to accomplish. There are two main steps

First, create a new folder in your Windows 10 app and call it “DeviceFamily-Mobile”.

Folder_thumb

Then right click the folder and select Add –> New Item and select the top item “Xaml View”. Name the file MainPage.xaml.

mainpage_thumb

This creates just the xaml page of the page, not the code behind. It doesn’t need a code behind file because you’ve already declared a MainPage file!

That’s all you have to do! Now you have a page that is specific for mobile devices and a page that will be used for all other platforms/devices. Let’s test this out.

Open the mobile page and add a TextBlock stating we are on a phone.

<TextBlock Text="Hello from Windows Phone!"/>

Now open the other MainPage file and add the following:

<TextBlock Text="Hello from Windows!"/>

Run the app on a phone emulator or a device and you will see the first message!

phone[3]_thumb

Now run the app on your machine or the simulator and you will be greeted with the second message!

windows_thumb

Let’s take this one step further and add a device folder for desktop. This time name it “DeviceFamily-Desktop”. Add a new Xaml View and add the following to the Grid.

<TextBlock Text="Hello from Windows Desktop!"/>

Run the app on your machine and you will see the new text. The original MainPage.xaml will only display on a device that is not phone (mobile) and not desktop.

I mentioned already that the code file is shared. Anything you put in the file can be used for all of the pages. Let’s say you have a button on each view and need a click handler. One click handler in the code file will work for all views!

I’m sure there are more device family folders that would work like XBox or HoloLens but we’ll have to wait to test those.

Registering to any DependencyProperty changing in Windows 10 Apps

Many have argued that there are pieces still missing from Windows Runtime XAML that were in WPF. One item that was in WPF was the ability to be notified when a DependencyProperty changed. This functionality is now available in Windows Apps thanks to the new RegisterProperrtyChangedCallback method on DependencyObject. This opens up a world of opportunities for us. This functionality is extremely useful when creating custom controls or wrapping existing controls.

Rather than getting into anything complex, I’ll show a quick sample. A TextBlock control has Text, but no way to be notified when the text changes. We do have the ability to bind to the Text, but we’ll ignore that for now.

We’ll create two TextBlocks and one Button.

<StackPanel>
    <TextBlock x:Name="CounterText"/>
    <Button Content="Click me" Click="OnButtonClicked"/>
    <TextBlock x:Name="DuplicateTextBlock"/>
</StackPanel>

When the button is clicked we’ll set the text for the first TextBlock.

private int _counter;
 
private void OnButtonClicked(object sender, RoutedEventArgs e)
{
    CounterText.Text = string.Format("Clicked {0} times", ++_counter);
}

We’ll also register a callback for when the Text property changes for the CounterText TextBlock. Within the callback we’ll set the text of the other TextBlock.

public MainPage()
{
    this.InitializeComponent();
 
    CounterText.RegisterPropertyChangedCallback(TextBlock.TextProperty, OnTextChanged);
}
 
private void OnTextChanged(DependencyObject sender, DependencyProperty dp)
{
    var t = (TextBlock)sender;
 
    DuplicateTextBlock.Text = t.Text;
}

Now every time you click the button, it will set the text of the first TextBlock and the callback will fire setting the text of the second TextBlock!

capture-2