Tuesday 24 April 2012

Silverlight Toolkit ListPicker changes

After my post about a week ago, about the Silverlight Toolkit November 2011 installer installing the wrong version I took some advice and started using NuGet.

So, as I’ve been updating my apps, I’ve begun adding the references to the latest toolkit.  Today, I came across a breaking change (I’ve switched from Version 1.0 to Version 7.0 of the toolkit in one jump) in the ListPicker.

My first clue should have been that ItemCountThreshold="3" raised an error, so I removed it, as the new threshold is consistent with my application.

Then I noticed that my picker page seemed to have a different font from the version of our Chromatic Tuner for Windows Phone: Tune Up that’s released on Marketplace.

It turns out, the ListPicker now navigates to a new page, which raised another bug in our software, because previously OnNavigatedTo was not called after the Picker was dismissed. 

As the program was so simple, we set the selected Item in the ListPicker irrespective of whether we were a new page, and therefore lost the new selection.

Wednesday 18 April 2012

Silverlight Toolkit Nov 2011 installer borked

If like me, you’re using the Silverlight Toolkit, and installed the November 2011 installer and are shipping, there’s a problem you probably want to know about.  You may have suspected something was wrong, in that it actually installed into an October or August folder originally.  Read on…

My stack trace matched the one reported here: http://silverlight.codeplex.com/workitem/10220

I was getting crashes in Context menu, and decompiled the Toolkit.dll I was shipping, and was surprised to find that some null checks were missing in the decompile compared to the source code that was shipped in the same install.


As a result, I downloaded the 71382 source, and rebuilt, and found the decompile now matches.


My conclusion: The dll's installed with that build are faulty. I’ve uploaded my build here

http://silverlight.codeplex.com/workitem/9982

Don’t think removing and adding a reference is all you need to do either

I tried that, and the old Microsoft.Phone.Controls.Toolkit.dll was still the one built into my xap file, and it kept pointing to the old one in the original folder, despite adding a reference to the new file.

In the end, I needed to manually delete the dll from the bin/Release and bin/Debug folders.

Addendum 19/April/2012

@windcape (Claus Jørgensen) suggested I learn to use NuGet, and he’s right.  Nuget does deliver a more up to date package.  Get the toolkit here:

http://nuget.org/packages/SilverlightToolkitWP

The Resource ‘X’ Could not be resolved : WP7

A while back, I took one of my WP7 programs, and saved it as a Template, so it was easy to create a new WP7 app with all my framework code already built into the app.

What I didn’t notice at the time though, was that my Merged resource dictionary was not being used to render in the VS2010 xaml designer, though they were working correctly in the actual program, and in Blend.

After spending a few hours searching on the web, and trying “voodoo” solutions, I found the answer (or thought I did, until I began writing this up, which wasted another hour or two)

My original solution was built with this ResourceDictionary located in my Framework folder:

<!--Application Resources-->
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Resources/AppDetails.xaml" />
<ResourceDictionary Source="/Framework/Resources/FrameworkResources.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>


Both xaml files above were included in the build as Content


This is the code I needed instead:


<!--Application Resources-->
pplication.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/MyApp;component/Framework/Resources/FrameworkResources.xaml" />
<ResourceDictionary Source="/MyApp;component/Resources/AppDetails.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>


And to get this to work, the xaml files needed to be changed to Page


You must also make sure your App.xaml file is marked with a build action of ApplicationDefinition and your App.xaml appears to have to be in the root of your project.


I had some cases where it appeared to work with various combinitions of all of the above, but after a restart of visual studio, occasionally it would again lose the resources in the designer, so the only apparent way to make this work is to follow the exact steps above.

Monday 16 April 2012

WP7 Layout Jitters and the SystemTray

Ever since I started on writing WP7 apps, Microsoft has been drilling into developers how important it is to have the UX be fantastic.  Yet, if you create a phone application from the wizard, add another page to the app from the wizard, and hook up an appbar button to navigate to the second page, you end up with a visual mess during navigation.

You’ll find, as I did, that in some cases, your page will appear, and then magically jump down the page by 32 pixels:  The size of the SystemTray.

I posted a question here back at the end of March,: http://forums.create.msdn.com/forums/p/101982/610979.aspx#610979 with a follow  up on how to provoke the problem, as well as a project file that demonstrates the problem here:

http://www.wieser-software.com/m/forums/NavigateHops.zip

If you increase the length of time in the About_LayoutUpdated function’s Sleep call, you should be able to see what I mean.

Now, this has been bothering me for about a month, as I’m just about ready to release a new app, and this looks really bad.

Today, I finally decided I had to waste half a day, and find out what was really going on.

First the facts:

  • The layout jumps by 32 pixels, exactly the height of the SystemTray
  • If you set the opacity of the SystemTray, the height is not removed from the space allocated to your application.
  • If your application supports Portrait or Landscape mode, there’s more work work to do, as in LandscapeLeft orientation, the SystemTray normally reserves 72 pixels on the left, while LandscapeRight reserves 72 pixels on the right.
  • SystemTray.Opacity set in the page XAML is actually a dependency property, as is IsVisible.

 

http://msdn.microsoft.com/en-us/library/microsoft.phone.controls.pageorientation(v=vs.92).aspx has an hilarious description of how (not) to use these flags:

The ideal way to check for orientation in your application is to check the bit flag Portrait, check the bit flag Landscape, or check for both LandscapeLeft and LandscapeRight. However, you should not check for only LandscapeLeft or only LandscapeRight.

(unless of course you really want to know if it’s in LandscapeLeft or LandscapeRight orientation)

So, armed with the facts and misinformation above, lets get coding:

I decided I wanted to build this as a function that can be added to my constructors so that it can be switched off or changed at a later date.

So, first, create a static class in our Framework namespace to hold the WPHacks.  Let’s call it WPHacks.cs

using System.Windows;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;

namespace Framework
{
// This code writen by Wieser Software Ltd
// www.wieser-software.com
// Use of this code is permitted as is or in derived
// works provided the code is attributed to us.
public static class WPHacks
{
static Thickness PortraitMargin = new Thickness(0, 32, 0, 0);
static Thickness MarginLandscapeLeft = new Thickness(72, 0, 0, 0);
static Thickness MarginLandscapeRight
= new Thickness(0, 0, 72, 0);

/// <summary>
/// Wire up our fixes for SystemTray visibility
/// Make sure you call this after you've called
/// InitializeComponent.
/// </summary>
/// <param name="page">The page to fix</param>
public static void WireOrientationHack(
PhoneApplicationPage page)
{
if (!SystemTray.GetIsVisible(page)) return;

// if using the SystemTray,
// set up the initial margin based on the
// page's desired orientation
PageOrientation o = page.Orientation;
OnOrientationChanged(page,
new OrientationChangedEventArgs(o));

// you may be tempted to use the SystemTray.Opacity
// property instead, but you'd be wrong, because that
// is asking what the current SystemTray is showing
// not what this page wants it to be set to
if (SystemTray.GetOpacity(page) == 1.0)
{
SystemTray.SetOpacity(page, 0.0);
}

page.OrientationChanged += OnOrientationChanged;
}

/// <summary>
/// On an orientation change, we readjust the margins
/// on the page, to leave room for the system tray.
/// 32 Pixels on top for portrait, 72 pixels on left
/// for LandscapeLeft, 72 pixels on right for LandscapeRight
/// </summary>
/// <param name="sender">The page changing orientation</param>
/// <param name="e">Event args</param>
static void OnOrientationChanged(
object sender, OrientationChangedEventArgs e)
{
PhoneApplicationPage src = sender as PhoneApplicationPage;
if (src == null) return;

if (0 != (e.Orientation & PageOrientation.Portrait))
{
src.Margin = PortraitMargin;
}
else
{
src.Margin =
((e.Orientation & PageOrientation.LandscapeLeft)
== PageOrientation.LandscapeLeft)
? MarginLandscapeLeft : MarginLandscapeRight;
}
}
}
}


If you add this code to your project, all that’s required to fix the jitter is to make the following call in your constructor, immediately after calling InitlializeComponent(), as shown in this About constructor:

 

public About()
{
InitializeComponent();
Framework.WPHacks.WireOrientationHack(this);
}