30 April 2014

A screen-size independent scroll-into-view pane for Windows Phone and Windows Store apps

In this article I introduced MoveObjectBehavior and a way to use it to make Facebook-app like scroll-into-view panes. All very nice, but with a minor drawback – it basically needs a fixed screen size. That’s OK under Windows Phone 8 (albeit it does not look so good on a Lumia 1520) but still – you got away with it.

That is no longer the case in Windows Phone 8.1, and it never was the case in Windows 8. You have to take multiple screen sizes into account now, and in the case of Windows 8 the screen size can change while the app is running – as the user can arbitrarily change the horizontal space an app is using while it’s running.

Like this:

Scroll-into-view pane for Windows 8

Now MoveObjectBehavior has an ActivatedXValue Property and of course I could try, in stead of setting a fixed value, to bind that to the value of ActualWidth of the Page. Unfortunately that is not a Dependecy Property, so although it works initially, changes to it’s value are not populated. Yet, as you can see above, it can be done, and with a pretty animation as well.

This, of course, is were a second behavior comes in handy. Meet SizeListenerBehavior:

using Windows.UI.Xaml;

namespace WpWinNl.Behaviors
{

  /// <summary>
  /// This behavior listens to a size change of the attached object
  /// and puts the resulting size into two bindable dependecy properties
  /// </summary>
  public class SizeListenerBehavior : SafeBehavior<FrameworkElement>
  {
    protected override void OnSetup()
    {
      AssociatedObject.SizeChanged += AssociatedObjectSizeChanged;
      base.OnSetup();
      PropagateSizes();
    }

    protected override void OnCleanup()
    {
      AssociatedObject.SizeChanged -= AssociatedObjectSizeChanged;
      base.OnCleanup();
    }

    void AssociatedObjectSizeChanged(object sender, SizeChangedEventArgs e)
    {
      PropagateSizes();
    }

    private void PropagateSizes()
    {
      WatchedObjectHeight = AssociatedObject.ActualHeight;
      WatchedObjectWidth = AssociatedObject.ActualWidth;
    }
  }
}

It is very simple - it listens to the SizeChanged event that does get triggered on any size change, then populates that to two dependency properties. And those are bindable. I omitted both properties from the code above as they are fairly standard. So if you give the behavior a name you can use Element binding to bind this properties to MoveObjectBehavior.

Which is done like this:

<Page
    x:Class="SizeListener.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
    xmlns:behaviors="using:WpWinNl.Behaviors"
    mc:Ignorable="d" 
DataContext="{Binding Source={StaticResource DemoViewModelDataSource}}"> <Page.BottomAppBar > <CommandBar x:Name="BottomBar"> <AppBarButton Icon="Help" Command="{Binding MyCommand}"> </AppBarButton> </CommandBar> </Page.BottomAppBar > <interactivity:Interaction.Behaviors> <behaviors:SizeListenerBehavior x:Name="pageRootSizeListener"/> </interactivity:Interaction.Behaviors> <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" > <Grid> <interactivity:Interaction.Behaviors> <behaviors:MoveObjectBehavior Activated="{Binding ShowSettings}" Duration="1000" ActivatedXValue="{Binding WatchedObjectWidth, ElementName=pageRootSizeListener}"/> </interactivity:Interaction.Behaviors> <Grid Background="Green"> <Grid Margin="50"> <TextBlock FontSize="50">THIS IS MY MAIN PAGE</TextBlock> </Grid> </Grid> <Grid RenderTransformOrigin="0,0.5" Background="Blue"> <Grid.RenderTransform> <CompositeTransform ScaleX="-1"/> </Grid.RenderTransform> <Grid> <Grid RenderTransformOrigin="0.5,0.5" Margin="50" > <Grid.RenderTransform> <CompositeTransform ScaleX="-1"/> </Grid.RenderTransform> <TextBlock FontSize="50">THIS IS MY MESSAGE PAGE</TextBlock> </Grid> </Grid> </Grid> </Grid> </Grid> </Page>

You see the parts that are actually do the work underlined, red and bold (so I hope that this is clear for everyone, even color blind people).

The trick with the mirroring grids to put stuff to the left (and the right) of your screen is described in my article, Aligning XAML elements outside the screen using scaling (for a Facebook-like GUI), so I won’t repeat that here.

The demo solution can be found here. If you are looking for the source in the code, you can keep looking, as it’s been sitting in my WpWinNl library on CodePlex for a while – but I just did not have the time to blog about it. If you want just the behavior’s source, that’s here.

20 April 2014

Windows Phone 8.1–moving your cursor. Don’t panic!

No code today, but a simple how-to. I was caught off-guard by this, a lot of people – including people who I concern to be power users, are pretty much confused by the way you move your cursor around in Windows Phone 8.1. It used to be

  • Long press text
  • Wait for a cursor to pop up above the text
  • Then swipe a little down and move the cursor to the place where you actually want it to be.

Help! Long press does not show the floating cursor anymore. Your cheese has been moved! Now what? Here’s my advice

Keep calm and tap twice

  • Tap a word. That will select it, and show the well-known selection handles – two dots that you can grab and move to increase or decrease the selection
  • Tap the word again. This will deselect it again, place the cursor in front of it, with a single dot-handle below it.
  • Now tap on that dot and move your finger around. The cursor will follow your finger – even up and down.

See below. Left - after one tap, right – after the second tap. I added the red arrow to indicate the dot that I mean

wp_ss_20140420_0001wp_ss_20140420_0002

It’s displayed in your phone’s accent color – mine is currently set to lime green. I find that kind of fitting with spring, don’t you think? ;-). Once you are used to it, it’s really easy. Double-tap, move the cursor. No more long pressing and swiping down.

For those who rather see it explained on video: see below.

How to move your cursor.

02 April 2014

Code sharing strategies between Windows Phone 8.1 and Windows 8.1 with the new Universal Windows apps

With the announcement of the new SDK for Windows Phone Microsoft now really starts to stress the companionship of Windows and Windows Phone, and makes it a lot easier to build apps that run on both platforms. Windows Phone apps now reside under ‘Store Apps’ and although you can still write Windows Phone only apps, it’s pretty clear to me what the preferred way to go for new Windows Phone apps is

image

Two new kinds of Windows Phone apps

Let me make one thing clear: no-one is going to push you. Windows Phone 8.1, like it’s predecessor, will run 8.0 apps fine. You can go on re-using the skillset you have acquired, still using the XAML style you are used to. In fact, Microsoft stresses this point even more by including Windows Phone Silverlight 8.1 apps, which are a bit of a halfway station: your XAML largely stays the same, but it gives you access to the new APIs. Yet I feel the crown jewel of the new SDK is the new Universal Windows app and, in it’s slipstream, the enhanced PCL capabilities. But once again – no-one is forcing you this way. Microsoft are very much about going forward, but also about protecting your existing skills and assets.

One solution, two apps

One thing up front: ‘one app that runs everywhere’ is a station that we still have not reached. You are still making two apps – one for Windows Phone, one for Windows. In this sense, it’s basically the same approach as before where you used code sharing with linked files. That was quite a hassle, and now Visual Studio supports a formal way to share files between projects. This makes maintaining oversight dramatically easier, and it gets rid of the confounded “This document is opened by another project’ dialog too. Plus – and that’s a very big plus – the code you can use on both platforms has become a lot more similar.

Going universal

imageOne warning in advance – if you going for the Universal Windows app, you’re going all the way. It means that for your Windows Phone app in most cases you are basically writing a Windows 8 app - using XAML and APIs that are familiar for Windows Store apps programmers, but not necessarily for Windows Phone developers. If you already have some experience writing Windows Store this won’t be a problem. If you have never done that before, some things may look a bit different.

So, I have created a new blank Universal Windows app and it shows like displayed on the right:

Initially, it only shows the App.Xaml.cs as shared. This has one great advantage already – you can go in and disable the frame rate counter for both apps in one stroke :-):

        protected override void OnLaunched(LaunchActivatedEventArgs e)
        {
#if DEBUG
            if (System.Diagnostics.Debugger.IsAttached)
            {
                //this.DebugSettings.EnableFrameRateCounter = true;
            }
#endif

Switching contexts

If you go through the shared App.Xaml.cs you will notice a few more things: at several places in the file it says #if WINDOWS_PHONE_APP, and I also want to point out this little thing on top, the context switcher.

image

You can set the context switcher to ‘MyNewApp.Windows and you will see the Windows app code greyed out. This way, you can very quickly see which code is executed in which version and which not

image

Sharing code – sharing XAML

So I went to the Windows Store app, opened Blend, added some text and two tool bar buttons:

<Page
    x:Class="MyNewApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MyNewApp"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
  <Page.BottomAppBar>
    <CommandBar>
      <AppBarButton Icon="Accept" Label="AppBarButton" Click="AppBarButton_Click"/>
      <AppBarButton Icon="Cancel" Label="AppBarButton"/>
    </CommandBar>
  </Page.BottomAppBar>

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
      <TextBlock HorizontalAlignment="Left" 
                 Height="37" Margin="90,53,0,0" TextWrapping="Wrap" 
                 Text="Hello World" 
                 VerticalAlignment="Top" Width="383" FontSize="29.333"/>

    </Grid>
</Page>

And added some code behind.

private async void AppBarButton_Click(object sender, RoutedEventArgs e)
{
  var m = new MessageDialog("Hello world");
  await m.ShowAsync();
}

Now this won’t make for a spectacular app. If you run it, it will basically show:

imageimage

It amaaaaazing, right ;-)? But then I went a bit overboard – I imagemoved MainPage.xaml and imageMainPage.xaml.cs to the Shared project, and removed it from the Windows Phone 8.1 project. Run the Windows Store App again – still works. Run the Windows Phone 8.1 app, and sure enough…

Now this may seem pretty cool – and in fact it is - but it would not be something I would recommend using just like that. Windows Phone is a different beast, the way people use a phone app differs from how they use a Store app on a tablet, and usually you have to think different about how the layout works on a tablet. Case in point – the app bar. Windows Phone has only room for four buttons. The Secondary Commands show up as menu items, not as buttons. The Top bar does not show up at all. So blindly copying a UI from Windows Phone to Windows Store and back is not a smart thing to do. But the fact that it works, is in itself pretty cool.

Sharing code – in a more practical way

In practice, I have found you almost never share whole pages between phone apps and store apps, for a number of reasons:

  • Phone design does not always translate easily to tablet design and vice versa (as pointed out above).
  • For phone, space is a premium, and you don’t want to drag along all kinds of stuff that’s only used on a tablet - think super-high-res stuff, or all kinds of elaborate XAML constructions to accommodate that
  • If you use controls on one platform that simply are not present on the other, or if you use native controls (for example, maps)

To maximize code sharing, you can for instance use partial classes. That works like this: in your code behind MainPage.Xaml.cs you declare the class “partial”.

namespace MyNewApp
{
  /// <summary>
  /// An empty page that can be used on its own or navigated to within a Frame.
  /// </summary>
  public sealed partial class MainPage : Page
  {
    public MainPage()
    {
      this.InitializeComponent();
    }
  }
}
And then in the shared project you create a new file MainPage.Xaml.cs (or MainPage.cs), with just this:
namespace MyNewApp
{
  /// <summary>
  /// An empty page that can be used on its own or navigated to within a Frame.
  /// </summary>
  public sealed partial class MainPage : Page
  {
    public MainPage()
    {
      this.InitializeComponent();
    }
  }
}

And this still gives the same result. Partial classes in shared projects can be pretty powerful. From the partial class in shared code you can call for instance back to methods in the non-shared portion, provided that those called methods are present in both the non-shared portions of the class (so both the MainPage.Xaml.cs). You can even call methods in referenced PCLs. Just keep in mind that in the background it just works like shared files and you can do a lot to minimize duplication.

More ways of sharing

Another way of sharing code is putting most of it in the shared portion – even stuff that’s not present on both platforms – but then using the #ifdef WINDOWS_PHONE_APP and #ifdef WINDOWS_APP directives. This is largely a matter of preference. For smaller classes with little differences I tend to choose this route, for larger classes or code behind files I tend to go for partial classes.When I am working on stuff that is particularly phone-related, I don’t want my code cluttered by Windows code, and vice versa.

A third way of sharing pieces of UI would be creating user controls in shared code. They can be reused within pages that are in itself not shared.

Finally – don’t forget that everything can be shared in the shared images. Apart from XAML and code this includes, for instance:

  • Images
  • Resource files (styles, templates, localization, etc)
  • Data files

And PCL?

In the past, I have never been a fan of PCL, because of their limitations. This has been greatly improved by the new model and I actually start to like it. If you make a PCL for use in Windows 8.1 and Windows Phone 8.1 you can put almost everything in it that can be stuffed in a shared project, including user controls – although of course you can’t do elaborate partial classes callback tricks into non-shared code. This is because a PCL needs to stand on itself. So only everything that is available in both platforms fits in, so for instance almost everything map-related is out (with a few notable and very important exceptions: Geolocation (GPS tracking) and Geofencing (that is now available on Windows Phone too!).

Still – PCL is only useful if you are building stuff that

  • Needs to be reusable over multiple different apps
  • Needs to be usable on both Windows Phone and Windows Store

With this respect, there is not much difference in building platform-specific libraries and distributing them vi NuGet. This is more for the advanced programmer who is starting to build his own toolkit. This means you, by the time you are working on your third app :-)

Code sharing recap

  • Code, XAML or assets that can be shared within one app for both platform can go into a shared project. For code that does not fit entirely you can use
    • Partial classes
    • #ifdef directives
  • Code, XAML or assets that can be shared over multiple apps for both platform can go into a PCL

Conclusion

Build for Both has become a lot easier. You still have to deliver two apps, but making them as one has become a lot easier. Making clever use of the of partial classes and #ifdef makes it easier too, although this requires some thinking. Still, you have to take into account how both platforms behave differently.

A new exiting story for Windows Phone and Windows developers has begun.

The ‘demo solution’, which is hardly worth it’s name in this case, can be downloaded here.