Showing posts with label Silverlight. Show all posts
Showing posts with label Silverlight. Show all posts

Friday, 24 August 2012

Need a WrapPanel in WinRT?

I did, as the existing WrapGrid and VirtualizingWrapGrid weren’t up to the job of the panel I had used in my Windows Phone project.

I thought that because it’s a Panel implementation, it probably doesn’t have all the much code, having seen the one in Adam Nathan’s WPF 4 book.

So, I started by getting the implementation from the silverlight toolkit.

I only needed the following files:

NumericExtensions.cs, OrientedSize.cs and WrapPanel.cs.

While compiling a few namespaces were required to be changed and a couple of attributes removed, but after that, it’s now fully functional.

Thursday, 26 July 2012

Data-Binding Pitfalls on WPF, WP7, Silverlight and WinRT Part 1

I've been doing a lot of work on all four platforms (WPF, WP7, Silverlight and WinRT), and am puzzled by how data-binding is supposed to be implemented.

For example, in David Anson's Data Visualization toolkit, you can be penalized with an extraordinarily long delay if property changes happen in the wrong order.
http://forums.silverlight.net/t/101287.aspx/1

The problem in that specific instance is that the control sets the default range to 1 year, but the order of changing properties can cause the problem to occur at any point.  For example, if you were to change a date time axis from a range of 1 day to 1 year and back, with intervals of 1 hour and 1 month respectively, on the way to 1 year, you'd need to set the interval first, and the range second.  In the other direction, it's the opposite.

Now with Data Binding, it's not clear how you'd arrange this.  In my case in WPF everything appeared to be working just fine, until I newed up a control for printing.  Printing worked fine, but PrintPreview had a hugely long delay, before the preview window appeared.  The culprit?  The DateTimeAxis.

It turned out the problem was provoked by my code behind setting the Interval and Interval type.  When I changed it to data-binding, the problem disappeared.

Now, I suspect the reason this fixed the problem has to do with the options on Dispatcher.BeginInvoke and the Dispatcher itself.  If you look there (in WPF) the DispatcherPriorities includes Render and DataBind levels in addition to Normal.  Shawn Wildermuth wrote an article a long time ago about the dispatcher http://msdn.microsoft.com/en-us/magazine/cc163328.aspx that provides some insights.

If you examine the code in the DateTimeAxis, you’ll see that on a property change, most of what happens is a simple call to Invalidate().  That pushes the refresh down to the Render level, allowing all of the other Invalidate calls to occur before doing any work for changes resulting from property changes.  I’ll come back to that scheduling trick in a part 2 tomorrow.

Now, my code didn’t use data binding for all of it’s properties.  It all ran on the UI thread in response to the user asking to print.  As a result, (if my analysis is correct) the initial data binding has not yet run, as we haven’t ceded control to the dispatcher.

Eventually, my UI control is asked to Measure and Arrange from my code on the UI thread, and finally UpdateLayout is called by my code.  Because I had set some of the properties in code (the Interval, and Interval Types) but not the Max and Min, when the control is being laid out it does all the work to create the stupid number of ticks for each hour in a year.

Then, inside UIElement.UpdateLayout() I have this call stack:

PresentationFramework.dll!MS.Internal.Data.DataBindEngine.Task.Run(bool lastChance) + 0x31 bytes   
PresentationFramework.dll!MS.Internal.Data.DataBindEngine.Run(object arg) + 0xb6 bytes   
PresentationFramework.dll!MS.Internal.Data.DataBindEngine.OnLayoutUpdated(object sender, System.EventArgs e) + 0x1e bytes   
PresentationCore.dll!System.Windows.ContextLayoutManager.fireLayoutUpdateEvent() + 0x154 bytes   
PresentationCore.dll!System.Windows.ContextLayoutManager.UpdateLayout() + 0x926 bytes   
PresentationCore.dll!System.Windows.UIElement.UpdateLayout() + 0x16 bytes   

So, it finally data-binds the rest of my values, and lays out the axis correctly with the intended values for Max and Min.

By switching everything to use data-binding instead mixing it with code-behind, the default values in the DateTimeControl work correctly (though the work is still wasted), and then the data-binding sets them to the new values.

It’s this wasted effort that concerns me, so future instalments will examine what can be done about it.

Sunday, 20 May 2012

More bugs in the Toolkit ListPicker

We recently updated our Chromatic Tuner app, Tune Up, and after the update using the latest fixes for the Silverlight Toolkit was disappointed to find some new stack traces on the control panel.

As usual it’s a navigation bug, this time caused by a storyboard completing after something else has happened, in this case, someone pressed the start button after the navigation began.

As a result, the code in PickerPage.xaml.cs calls NavigationService.GoBack(); in the OnNavigatedTo handler.

Then the storyboard completes, and NavigationService.GoBack(); is called again while navigating.  We all know this is going straight to the exception handler.

The fix and issue are at http://silverlight.codeplex.com/workitem/10769 but I’ll duplicate it here.

private void OnClosedStoryboardCompleted(object sender, EventArgs e)
{
// Close the picker page
if (NavigationService.CanGoBack)
{
// Only do this if we can go back, or we crash
// navigate to start menu before this happens provokes.
NavigationService.GoBack();
}
}



But wait, there’s more!


While trying to diagnose this problem, I was playing around with the ListPicker trying to figure out exactly what might be going on, and I found another problem.


Immediately after you make your selection, the transition begins, and effectively you’ve made your selection.


But it’s actually possible to click on another item, and select that during the transition!  I consider this undesirable behaviour too.  You made your choice, and the transition began, yet you can change it at the last minute?  BZZZZ.  Wrong.


Here’s the fix for that one, again in ListPickerPage.xaml.cs:


private void ClosePickerPage()
{
IsOpen = false;
// AAW: disable picker on exit.
Picker.IsEnabled = false;
}

Saturday, 19 May 2012

Don’t use NavigationOutTransition from the Toolkit

I’ve recently updated a bunch of our software at www.wieser-software.com/m and have been noticing while demonstrating it occasionally without a data connection, that it’s possible to end up with either a blank screen or two pages shown on top of each other as a result of navigation.

I think I’ve tracked it down to a bug in the Toolkit, though I can’t work out how to fix it.

The problem arises when you are transitioning away from a page with a NavigateOutTransition, and then end up navigating back into another page (maybe the same one) before that transition has been completed.

When this happens, your program will be unhappy.

The only way I’ve found for now to fix it is remove the NavigationOutTransition elements completely from my pages.

You can follow the issue here on the Silverlight Toolkit pages:

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

Sunday, 13 May 2012

Formatting a Data Bound TimeSpan on WP7

Today, I was attempting to format a data bound TimeSpan for our upcoming application using the Custom TimeSpan Format Strings provided on MSDN

Much to my surprise, no matter what I tried, it didn’t appear to format the text, and I’m not the only one to find this.

TimeSpan ts = TimeSpan.FromSeconds(1.24);
string st = string.Format(@"{0:hh\:mm\:ss}", dt);
// st = "00:00:01.2400000"


Clearly the seconds formatting is not working correctly.  And worse, the documentation states that the time separators are not placeholders.


In my case, I know my TimeSpan is always less than 24 hours, so I thought the best solution was to convert it to a DateTime using a converter.


public class TimespanToDateTimeConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
return new DateTime(((TimeSpan) value).Ticks);
}

public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}


Now in my xaml, I do this to bind to an object named Elapsed:

 


<Grid>
<Grid.Resources>
<fwk:TimespanToDateTimeConverter x:Key="asDate" />
</Grid.Resources> ...
<TextBlock Text="{Binding Elapsed,
Converter={StaticResource asDate},
StringFormat='{0:HH\:mm\:ss\}'}"
/>

</Grid>

This neatly solves the problem, and in the process, delivers locale specific separators as well.

Friday, 4 May 2012

One of our ListItems is missing! ListPicker Bug Alert!

I used the November ‘11 Silverlight Toolkit ListPicker control in one of my upcoming WP7 apps, and was surprised when impatiently, I started scrolling down while my full screen picker page was opening.

Unfortunately, when I got to the bottom of the page, some of the items were not visible, though vertical space was reserved for them.

Off to the source I went, and discovered that the ListPicker control initially sets every item on the page to be have a PlaneProjection with a RotationX of –90.  That would at least explain why my items weren’t visible.  They were rotated away from the field of view so they couldn’t be seen (Just like Calvin and Hobbes in 2D form)

So how did it happen?

Deep inside the ListPickerPage.xaml.cs file, in the UpdateVisualState function, there’s an IList<WeakReference> itemsInView that holds the list of items currently in view, then a few lines later, a Dispatcher.BeginInvoke on UpdateOutOfViewItems.

UpdateOutOfViewItems then collects the list of visible items again.  Only they might not be the same items.  In fact, any items that are new to the set will not be drawn correctly.

The Solution

The solution of course is to change the call to pass in the list of in-view items to the UpdateOutOfViewItems, changing the call to

Dispatcher.BeginInvoke(new Action(() => UpdateOutOfViewItems(itemsInView)));

and the signature to:

private void UpdateOutOfViewItems(IList<WeakReference> itemsInView)

and finally we don’t call GetItemsInViewPort in the UpdateOutOfViewItems.

I’ve added this fix as a hotfix to the SilverlightToolkit project here:

ListPickerPage.xaml.cs

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);
}


 


 

Saturday, 24 March 2012

Live Tiles revisited

Back in December, I wrote about dynamically generating live tiles on the phone from a xaml template.  I released first live tiles application Terminator which shows sunrise and sunset around the world using NASA blue marble imagery.  Some of our customers asked for sunrise and sunset times, and where better than on a live tile.

However, occasionally the tile would not update correctly using code based on that I showed back in December. 

The symptoms were odd.  The layout was all over the place, and as I started changing things, I found that things were about to get even more peculiar.

Originally, the tile was defined as a user control with a defined height and width of 173 pixels, containing a grid with some auto resize columns.  So, I simplified my control to use a canvas as follows:

<Canvas Background="Red" >
<Image Canvas.Left="0" Canvas.Top="27"
Width="173" Height="89" x:Name="imgSunrise"
Source="/images/lowsunrise.png"/>

<TextBlock Canvas.Left="12" TextAlignment="Right"
Width="149" Text="{Binding SunriseTime}"/>
<TextBlock Canvas.Left="12">Sunrise</TextBlock>
<TextBlock Canvas.Left="12" Canvas.Top="27" TextAlignment="Right"
Width="149" Text="{Binding SunsetTime}"/>
<TextBlock Canvas.Left="12" Canvas.Top="27" >Sunset</TextBlock>
<TextBlock Canvas.Left="12" Canvas.Top="112"
Width="149" TextWrapping="Wrap" Text="{Binding Location}" />
</Canvas>

Previously, my control was rendering on a transparent background so that it would match the theme the user had selected, but I thought I’d try it with a fixed background so I could see what was happening.


What I found was that occasionally, my color was not being applied to my canvas, and it was still showing through with the theme color.


That discovery led me to believe that the layout had not yet completed.


Now, as was described back in December, the behavior of the notifications changes based on where they are run.  In the user agent, the load happens immediately, when the tile is used on a panel, it gets run multiple times.


My original strategy was to handle the change when the first LayoutUpdated event was fired, however, to my surprise, calling _fe.Arrange(layoutRect); where _fe is the framework element we’re trying to lay out, only generates a single call to LayoutUpdated in some circumstances, partcularly after the app has been Tombstoned.


In addition, it transpired that the values of ActualHeight and ActualWidth in this case were both 0.  I guess it’s no surprise that it rendered incorrectly in that case!  What appeared to have happened was that the image was way to big, and grainy.  Eventually I downloaded from Isolated storage, and found this is what was actually produced:


sunrise


One of the interesting things to note about this image is that it is not square, certainly not 173x173 like a tile should be, despite that being the size requested.


In fact it’s 173x135.  So, when rendering a tile, it turns out that metro will stretch the smallest dimension to 173, which explained the odd look described earlier.


So, what did I do to fix it? 


I tried subscribing to the SizeChanged event.  That didn’t work:  In fact it never fired. 


I tried setting up a DispatcherTimer, and handling it in 500msec, but that didn’t make any difference either.


Eventually I found a horrible hack that worked, though I don’t know why:


I did this in a loop (don’t try this at home, kids):



for (int i = 0; i < 3; i++)
{

_fe.Measure(new Size(173, 173));
_fe.Arrange(layoutRect);
_fe.UpdateLayout();

if (!bSynchronous || _fe.ActualHeight == 173) break;
// we do this in a loop because sometimes it doesn't work!
}




This code, surprisingly did work, though all Measure/Arrange/UpdateLayout were all required.  Initiallly I started with just Arrange.


But, in playing with this code to write the blog, I found an even simpler solution.  Set the size on the Canvas in the first place, and the problem seems to disappear (that is to say, the way that I used to be able to break it doesn’t break it any more).


This all begs the question:  microsoft, Why is this so hard?


That’s about 12 hours more of my life wasted.  The whole implementation of Silverlight/.NET is in a black box, where we can’t see the code, particularly on the phone where we can’t easily disassemble the source.  Even then it quickly drops down into native code, becoming inaccessible again.


Back in the old days of C++/MFC, it was at least possible to see what the source code was doing, and figure it out.  Now we just have to guess.  It’s turned programming into a giant game, where you need to figure out that right move to proceed, and that’s incredibly frustrating.


It all comes down to a lack of documentation about what actually is going on.  The trouble with blogs like these and all the other search engine led development, is we’re documenting workarounds for current implementations.  There’s no contract that says this behaviour will stay the same, so the next update may break your programs.


If you found this useful, and it saves you any time please consider purchasing one of our apps.  I have to admit, at the moment, sales are terrible for windows phone apps, and if things don’t improve soon, I won’t be wasting any more time developing new phone apps.  I make more money off my 2kW solar panels in a day than I do from phone apps in a month.  And, WM6.5 apps are still bringing in as much money per month as WP7 ones do.

Friday, 9 March 2012

Getting an integer identity for an object on WP7

Today’s quirk was discovered while trying to get an object’s identity.

Jeffrey Richter in CLR via C# (version 2)mentions that you can call RuntimeHelpers static GetHashCode method in a box at the bottom of page 148 to get a unique ID for an object.

The documentation for the .NET framework 4 and earlier all say this about GetHashCode:

The RuntimeHelpers.GetHashCode method always calls the Object.GetHashCode method non-virtually, even if the object's type has overridden the Object.GetHashCode method. Therefore, using RuntimeHelpers.GetHashCode differs from calling GetHashCode directly on the object with the Object.GetHashCode method.

But, if you change to the Silverlight version of the documentation of GetHashCode that statement is missing, and if you actually build the code you’ll find that it just calls GetHashCode on the object itself, with whatever override is provided on that type (as these people found out)

Further investigation into GetHashCode all the way back to V2 of the framework looks unpromising as well:

The default implementation of the GetHashCode method does not guarantee unique return values for different objects. Furthermore, the .NET Framework does not guarantee the default implementation of the GetHashCode method, and the value it returns will be the same between different versions of the .NET Framework. Consequently, the default implementation of this method must not be used as a unique object identifier for hashing purposes.

There is some information here on other possible strategies on stackoverflow for getting an identity.

My intended use was for serialization, and the above thread points out the ObjectIDGenerator class which looks like exactly the functionality I’m looking for, but it doesn’t work on Silverlight!

GCHandle also doesn’t look like it will do the job, as most members are security critical, and the only value it gives out is a pinned address anyway, though there is a promising Narrowing operator, so casting to an IntPtr looks like it might work.

However, when I try to run it I get an exception:

Attempt to access the method failed: System.Runtime.InteropServices.GCHandle.set_Target(System.Object)

which I guess is expected as they’re marked with [SecurityCritical] attributes.

Despite all that, it does appear that object.ReferenceEquals will tell me if two objects are the same, and a promising approach appears to be

Dictionary<object, int> dict = new Dictionary<object, int>(10);

I initially created two objects and added them, and when querying dict.Count I got two items.

 

So, on my objects I created, I added an override of object.Equals to always return true.

Disappointingly, I now only have one object in my dictionary, as it obviously uses equality rather than identity.

 

However, hidden among all of the dictionary constructors is a constructor that takes an IEqualityComparer<T>, if only I could figure out how to create one.

 

Luckily, there’s an implementation here, the only change i made was to remove the call to RuntimeHelpers.GetHashCode() and use obj.GetHashCode() instead, as they do the same thing anyway on the phone.

 

After that, even with my operator= and GetHashCode overridden in my class to always return true and 0 respectively, my code as follows successfully labels two unique objects  in its Dictionary.

var datesTmp = new EphemeralState();
Dictionary<object, int> dict =
new Dictionary<object, int>
(10, ObjectReferenceEqualityComparerer<object>.Default);

dict[datesTmp] = 1;

var datesTmp2 = new EphemeralState();
dict[datesTmp2] = 2;

Debug.WriteLine(dict.Count);


 

So now we know how to build something equivalent to the ObjectIDGenerator class.  Find the value of an object key in the dictionary above, and if it doesn’t exist, generate a new id, and add it to the dictionary.

 

Back to work now.


 

Thursday, 8 March 2012

How to monitor garbage collections in a WP7 app

I’m currently working on an app that has the potential to use lots of memory, and I’d like to cache the results as much as I can to speed things up for the user.

I’d also like to get my app certified and available for sale, so must be careful not to eat up all the memory.  One way to do that is with a WeakReference object, but I found that my objects were being garbage collected at the first opportunity, which didn’t really help.

I thought about doing an ephemeral garbage collection by calling GC.Collect(0) on the phone, but that isn’t allowed, and throws an exception.

What I really needed to do was keep my objects alive for a little while after they were used, but I really want to define a little while in terms of the number of garbage collections, rather than running a timer to continually dispose objects.

Unfortunately, I discovered there wasn’t any obvious event raised when a garbage collection is fired, but a little lateral thinking let me realize that there is an event that is called, thought it’s not marked as an event.

It’s actually every object’s finalizer!

So my strategy is to create an object, to which I hold only a weak reference, and when it’s garbage collected I update my statistics, and perform whatever other GC related actions I need to on the UI thread.

To save anyone else the pain, I include the code below.  To fire it up, just reference GCWatcher.GCINFO somewhere in your application, and the notifications begin.

public class GCWatcher
{
/// <summary>
/// static constructor collects the total memory on the device
/// </summary>
static GCWatcher()
{
TotalMemory = (long)DeviceExtendedProperties.GetValue("DeviceTotalMemory");
}

/// <summary>
/// Store a weak reference to our current sacrificial garbage collector object
/// </summary>
static WeakReference _activeGC;

/// <summary>
/// keep a count of the total number of garbage collections seen
/// </summary>
static int gcCount = 0;

/// <summary>
/// store the total memory found on the device
/// </summary>
public static readonly long TotalMemory;

/// <summary>
/// This placeholder should be modified to raise whatever notifications you need in your application
/// It will always be called on the main thread.
/// </summary>
static void Notify()
{
// placeholder for our notification call
}

/// <summary>
/// Property to get the current Garbage Collection info object. If one does not exist it will be created.
/// </summary>
static public GCWatcher GCINFO
{
get
{
WeakReference currentwr = Interlocked.CompareExchange(ref _activeGC, null, null);
GCWatcher current = currentwr == null ? null : currentwr.Target as GCWatcher;
if (current == null)
{
current = new GCWatcher();
Interlocked.Exchange(ref _activeGC, new WeakReference(current));
}
return current;
}
}

/// <summary>
/// Instance property to return the memory usage at the most recent garbage collection
/// </summary>
public long ApplicationCurrentMemoryUsage
{
get;
set;
}

/// <summary>
/// Instance property to return the peak memory usage at the most recent garbage collection
/// </summary>
public long ApplicationPeakMemoryUsage
{
get;
set;
}

/// <summary>
/// protected constructor, to create a new GCWatcher object, and initialize the properties.
/// This is always called on the UI thread.
/// </summary>
internal GCWatcher()
{
// when we create a GC Watcher, we collect the statistics
ApplicationCurrentMemoryUsage = (long) DeviceExtendedProperties.GetValue("ApplicationCurrentMemoryUsage");
ApplicationPeakMemoryUsage = (long) DeviceExtendedProperties.GetValue("ApplicationPeakMemoryUsage");

}

/// <summary>
/// implement a finalizer, that keeps track of our garbage collections via the weak referened object
/// </summary>

~GCWatcher()
{
Interlocked.Exchange(ref _activeGC, null); // zap the value, as we're destroyed
Interlocked.Increment(ref gcCount);

Deployment.Current.Dispatcher.BeginInvoke(
// create a new GCWatcher on the main thread.
() =>
{
WeakReference tmp = new WeakReference(new GCWatcher());
Interlocked.Exchange(ref _activeGC, tmp);
GCWatcher.Notify();
});
}

/// <summary>
/// Thread safe property to return the total counts of garbage collections
/// </summary>
int Count
{
get
{
return Interlocked.CompareExchange(ref gcCount, 0, 0);
}
}

Wednesday, 7 March 2012

Thread Safety on WPF, Silverlight and WP7

About a week ago I posted about IsolatedStorage and Thread Safety and what exactly the statement Any instance members are not guaranteed to be thread safe means in the documentation of the class libraries.

A lot of discussion making superstitious claims about serializing access to instance members ensued, however all of those led to illogical conclusions, implying that it was never possible to write a program that used multiple threads.

Eventually, I contacted members of the Base Class Library team who responded with the following definitive statements:

In general, the overall Framework guidance should apply to IsolatedStorage as well.

- Static members should be thread safe.

- Instance members cannot be expected to be thread safe unless otherwise specified.

- Instance members on different instances should be safe to use concurrently.

In addition, specifically related to IsolatedStorage, I got this definitive statement:

If you work on distinct instances of IsolatedStorage / ..File / ..Stream on different threads you will not run into any concurrency issues.

Different instances of those types have private copies of all internal data; and in cases where we need to update global state (e.g. isolated storage quota) we do all the necessary locking for you.

Note, however, that if you open two distinct Stream instances on the same file – whether through the iso storage or directly thought FileStream, we do not make any guarantees about the order in which these instances will access the underlying physical file. When using two distinct stream instances on the same file concurrently from different threads, you may end up with interleaved, mixed or invalid data in the file. However, the stream objects themselves will remain consistent and valid.

This is different from using one single Stream object from different threads: That is not supported and can break the stream object itself, not only resulting in data corruption, but also in weird runtime behaviour.

So there you have it.  Put your mutexes and locks down and step away from the code face and think!

If you are seeing what looks like a threading problem, and you found a mutex or lock solved it, it probably has, but not for the reason you thought.  There is probably some other multithreading logic error you had not foreseen, and your lock will either kill performance, or just make the bug even harder to find.

Thursday, 1 March 2012

WP7 Bing Maps Crash while being led down the garden path!

There I was, innocently trying to data bind to my collection of objects, and use an item template to render them on my maps control for an upcoming application.

So, I added a layer to my map like this:

<my:MapItemsControl x:Name="tracksLayer"
ItemsSource="{Binding Tracks }"
ItemTemplate="{StaticResource TrackTemplate}" />



and implemented my data template like this in the page resources:


<SolidColorBrush x:Key="FadedBrush" Color="Blue" Opacity=".5" />

<DataTemplate x:Name="TrackTemplate">
<MapPolyline Locations="{Binding Locations}"
Stroke="{StaticResource FadedBrush}"
StrokeThickness="5" />
</DataTemplate>



That all worked fine, and I got my brush displayed.


So, I thought great, now lets ask the track what color it should be, and changed the stroke definition to look like this:


<DataTemplate x:Name="TrackTemplate">
<my:MapPolyline Locations="{Binding Locations}"
Stroke="{Binding TrackBrush}"
StrokeThickness="5" />
</DataTemplate>



To my surprise, this threw an exception (or two) and terminated the program.


After a couple hours of debugging to figure out what had happened and being led down the garden path by the StaticResource, I eventually came across the fact that Stroke and StrokeThickness are not dependency properties in MapShapeBase.


Luckily, someone else had solved the problem here.  But be careful, the declarations there aren’t marked public and the dependency properties are implemented differently in WPF, so it won’t work out of the box.


I’ve attached my class here updated for WP7:


public class MapPolylineBindable : MapPolyline
{
public static readonly DependencyProperty StrokeProperty;
public static readonly DependencyProperty StrokeThicknessProperty;

static MapPolylineBindable()
{
MapPolylineBindable.StrokeProperty = DependencyProperty.Register("Stroke", typeof(Brush), typeof(MapPolylineBindable),
new PropertyMetadata(null, OnStrokeExChanged));

MapPolylineBindable.StrokeThicknessProperty = DependencyProperty.Register("StrokeThickness", typeof(double), typeof(MapPolylineBindable),
new PropertyMetadata(1.0, OnStrokeThicknessExChanged));
}

public new Brush Stroke
{
get { return (Brush)GetValue(MapPolylineBindable.StrokeProperty); }
set { SetValue(MapPolylineBindable.StrokeProperty, value); }
}

private static void OnStrokeExChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
(o as MapPolyline).Stroke = (Brush)e.NewValue;
}

public new double StrokeThickness
{
get { return (double)GetValue(MapPolylineBindable.StrokeThicknessProperty); }
set { SetValue(MapPolylineBindable.StrokeThicknessProperty, value); }
}

private static void OnStrokeThicknessExChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
(o as MapPolyline).StrokeThickness = (double)e.NewValue;
}
}

and to bind, you need to do this:

 


<DataTemplate x:Name="TrackTemplate">
<hack:MapPolylineBindable Locations="{Binding Locations}"
Stroke="{Binding TrackBrush}"
StrokeThickness="5" />
</DataTemplate>


Friday, 24 February 2012

Asynchronous actions with RX

I was trying to come up with a syntactically tidy way to run some code in the ThreadPool.

Assume I have a function as follows that performs the work:

void PopulateIsolatedStorageList()
{
using (iso = IsolatedStorageFile.GetUserStoreForApplication())
{
string[] found = iso.ISO.GetDirectoryNames("Logs/*.*");
foreach (string s in found)
{
// do some time consuming processing here
}
}
}


First I attempted to create an Action delegate for the above, and then tried to do this:


Action b = this.PopulateIsolatedStorageList;
Observable.FromAsyncPattern(b.BeginInvoke, b.EndInvoke )().
ObserveOn(Scheduler.ThreadPool).Subscribe();



This did not work.  First, PopulateIsolatedStorageList ended up with a null this pointer.


Secondly, it seemed to run on the main thread in any case.





A bit of lateral thinking required


What are my goals?



  1. I want to run my action on a worker thread.

  2. I want to perform some completed action on the UI thread (namely OnPropertyChanged).

Why not create an enumeration of things I want to get done on the worker thread then?


Action[] a = { PopulateIsolatedStorageList};
a.ToObservable(Scheduler.ThreadPool).Subscribe
( action => action(),
      () => Deployment.Current.Dispatcher.BeginInvoke(() => UINotify() ));


Where UINotify() is the expression to perform on the main thread.

 

And surprisingly, it all works.

Update – It helps if you find the right method


Having searched some more I found another mechanism, which removes the need to create the array, and is probably the proper way to do it.


Observable.ToAsync(PopulateIsolatedStorageList)()
.Subscribe(
     _ => { },
() => Deployment.Current.Dispatcher.BeginInvoke(() => UINotify() ));


IsolatedStorage performance tests on WP7

The documentation on IsolatedStorage seems to be incomplete on the subject of when you should open and close the ApplicationStore, particularly since the only the public static members are thread safe.

It would appear that the best performance might be to open the IsolatedStorage using IsolatedStorageFile.GetUserStoreForApplication() once for the application, and share the instance, but what operations are allowed across multiple threads if you do?  Well, that isn’t clear.

So, the safest thing to do is to open one every time you need it, and dispose of it when finished.

I’ve already verified that each time you call GetUserStoreForApplication, a different object is returned, and built a harness that does this:

isf = IsolatedStorageFile.GetUserStoreForApplication();

int v = System.Environment.TickCount;

for (int i = 0;i<1000;i++)
{

CheckFolderBare("Shared");
}

int v2 = System.Environment.TickCount - v;
v = System.Environment.TickCount;

for (int i= 0;i<1000;i++)
{
CheckFolderSlow("Shared");
}
int v3 = System.Environment.TickCount - v;

MessageBox.Show(string.Format("Fast: {0}ms\nSlow {1}ms", v2, v3));


My Implementations of CheckFolderBare and CheckFolderSlow are this:


private bool CheckFolderBare(string s)
{
return isf.DirectoryExists(s);
}

private bool CheckFolderSlow(string s)
{
using (var isf2 = IsolatedStorageFile.GetUserStoreForApplication())
{
return isf2.DirectoryExists(s);
}
}

 

Not surprisingly, my initial suspicions were correct.  It isn’t particularly cheap to create and dispose of the file (taking about 1.3ms).  Timings were:

Fast: 2787ms

Slow: 4086ms

 

How about enumerating the folders?  To do this, I create a folder in IsolatedStorage named Logs, and created in that folder 7 additional folders, and then ran these functions 1000 times:

private string[] FoldersSlow()
{
using (var isf2 = IsolatedStorageFile.GetUserStoreForApplication())
{
return isf2.GetDirectoryNames("Logs/*.*");
}
}

private string[] FoldersFast()
{
return isf.GetDirectoryNames("Logs/*.*");
}



Results differed by about 2.5ms:


Fast: 7619ms
Slow: 9100ms


So, to make things more interesting, I decided to create and delete a folder on each operation, so on odd calls, I remove the folder Logs/Bogus and on even calls I created it.


Surprisingly, I ended up with times differing by 1.3ms, and in some cases, not showing any difference at all.


Fast: 16406ms
Slow: 17542ms


Verdict?


On balance, I’d say there is no real performance penalty by opening and closing the IsolatedStorage in a realistic usage scenario.

Friday, 30 December 2011

Tombstoning and Mango: Something’s Awry!

I’ve wasted another day.

I’ve been trying without success to understand what’s happening with Tombstoning, and why my properties which are data bound are not being updated.

To cut a long story short, you can reproduce this using Matt Lacey’s Tombstone Helper Toolkit as follows:

First, download the latest source from CodePlex.

Build for OS 7.1, which requires you to modify the Demo Projects WMAPPManifest.xml file to have the correct AppPlatformVersion 7.1, or you get an error from Microsoft.Phone.PreImport.targets ValidateWMAppManifest rule.

Go to the Debug tab of the demo, and switch on Tombstoning.

Build and run the file, and go to the TextBox demo, and verify that if you change field 1, and navigate away and back, that its value returns.

Now make the following changes:

On line 30 of TextBoxes.xaml, change the line to this, so it’s DataBound as follows:

<TextBox Name="first" Text="{Binding Path=UserName, Mode=TwoWay}"/>


Now, add this to the top of TextBoxes.xaml.cs, inside the namespace declaration.  It’s based on Jesse Liberty's ViewModel here:


public class MainPageViewModel : INotifyPropertyChanged {
private string _userName;
public string UserName
{
get { return _userName; }
set { _userName = value; NotifyPropertyChanged("UserName"); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propName)
{
if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propName)); }
}

public MainPageViewModel()
{
UserName = "I AM SAM";
}
}


Finally, modify Matt’s TextBoxes constructor to set my ViewModel as the DataContext:


public TextBoxes()
{
DataContext = new MainPageViewModel();
InitializeComponent();
}

If you now run the code, and change “I AM SAM” to “SAM I AM”, navigate away, and then back, you’ll see that the name is not replaced.

 

I’ve found a bodge, based on what I read here on the WP7 forums:  Change OnNavigatedTo like this:

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
// Uncomment the next line for changes to be reloaded
// Loaded += (s, ea) =>
{
this.RestoreState();
};
}

 



If you uncomment the Loaded+= line, the code will now work as expected.


Clearly there’s something odd going on with Mango here, as I’ve seen this in my own simplistic implementation where I set the Text property of a TextBox directly without all the framework like this:


Long.Text = (string)State["Longitude"];


and it too does not get updated correctly.

Friday, 23 December 2011

US Culture is more pervasive than you might expect

While getting an application ready to ship, I switched the locale of my WP7 device to Danish.  Fingers crossed, my app will magically display Pi as 3,14159

Alas, that’s not what happens.  When I put up a text box, and enter 3,14159, my software actually gets a value of 314159 instead.

Posting a query on Culture to the WP7 Forums got no result, so I dug into Laurent Bugnion’s excellent Silverlight 4 Unleashed book, and found that he suggests in Listing 6.10 that you set the Language on the Page.  I didn’t really want to build a page for every language, as I’ll never hit them all, so instead modified the constructor of my FrameworkElement classes as follows:

InitializeComponent();
this.Language = System.Windows.Markup.XmlLanguage.GetLanguage(Thread.CurrentThread.CurrentUICulture.Name);


Eventually I tracked down several sources for why this is the case:


http://www.pedrolamas.com/2011/07/28/cuidado-com-o-frameworkelement-language/
http://connect.microsoft.com/VisualStudio/feedback/details/442569/wpf-binding-uses-the-wrong-currentculture-by-default


 


imageimageI also attempted to make it easier for the user to enter numbers into my window, using the InputScope attribute of my TextBoxes, I assumed that InputScope=”Number” would be what I wanted. How Naive.  The image on the left shows how unsuitable this is.


In the Danish Locale, we really want a comma on the keyboard, not a decimal point.  In addition, there is no negative sign.


The best compromise I could find (after randomly trying many of the InputScope values that looked appropriate was Time, which gives the keyboard on the right.


Now I just need to come up with a strategy for translating the Validation Exceptions that I’m currently displaying in the UI.

Wednesday, 21 December 2011

Fast and Loose with WP7 Mutex

While trying to figure out how to synchronize access between my ScheduledAgent and my main program, I started to investigate how Mutex objects behave.

Normally on Windows, when a Mutex is abandoned, an exception is raised when the Mutex is next acquired.  After searching online, I failed to find a description of what happens, particularly if you are holding a Mutex when WP7 decides to kill your process.

Here’s my sample I dropped onto a phone page:

private void OnLoaded(object sender, RoutedEventArgs e)
{
m = new Mutex(false, "KeepOff");
bgw = new Thread(new ThreadStart(bgw_DoWork));
bgw.Start();
try
{
Thread.Sleep(500);
m.WaitOne();
Thread.Sleep(500);
}
catch (Exception ex)
{
}
m.ReleaseMutex();
}

void bgw_DoWork()
{
m.WaitOne();
Thread.Sleep(5000);
Thread.Sleep(0);

}


Surprisingly, when the thread exits, the Mutex is acquired by the code in the try block, and no exception is raised.  I also tested the behavior in my ScheduledAgent, and in that circumstance, the Mutex is also released when the thread is terminated.


Eventually, I did find a reference to the behavior on the phone, but rather than being on WaitOne where I thought it belonged, it’s here: ReleaseMutex Method


Now , I wouldn’t recommend being this sloppy with your Mutex objects, but it looks like for now at least we can assume WP7 will clean up after us.


Peter Torr points out WaitOne might be dangerous, particularly in light of FAS (Fast Application Switching) if it doesn’t include a timeout.  I’ll look into that more in another post.