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.

A new pattern for Win8 ApplicationViewState handling

While trying to port our app Bridge Stenographer I was faced with the problem of supporting the new ViewStates in Windows 8.

I didn’t really like the idea of having a bunch of duplicate controls on my UI that I hid.

I didn’t really like the idea of having a frame that I navigated to a completely separate set of controls.

And I really didn’t like the messy syntax for managing view states with the VisualStateManager, particularly in light of my previous experiences of Visual States never doing what you expect.

So here’s my idea:

First, in the Common folder, modify LayoutAwarePage.cs to make the ObservableDictionary available to the rest of the classes by making it public (or protected).

Set up bindings in your DefaultView model, labelled with keys that define the states you require.  So for instance, I need to move some items from one grid location to another based on my state changes.

DefaultViewModel["keyboardRow"] = 2;
DefaultViewModel["keyboardColumn"] = 1;
DefaultViewModel["keyboardMaxWdith"] = 465;
_fullpage = DefaultViewModel;



Where _fullpage is defined as (sorry about Wdith typo above.  How to edit in LiveWriter???)


private IObservableMap<string, object> _fullpage;
private IObservableMap<string, object> _snapped;



Then in my constructor I also add the _snapped object:


_snapped = new ObservableDictionary<string, object>;
_snapped["keyboardMaxWidth"] = 300;
// etc...


Then in my code, I simply bind to

<somecontrol MaxWidth="{Binding DefaultViewModel[keyboardMaxWidth]}" />


And swap the DefaultViewModel in response to the SizeChanged event on the page:


void BiddingPage_SizeChanged(object sender, SizeChangedEventArgs e)
{
switch (ApplicationView.Value)
{
case ApplicationViewState.Snapped:
DefaultViewModel = _snapped;
break;
default:
DefaultViewModel = _fullpage;
break;
}
InvalidateArrange();
}


Hey Presto!  New layout.
I was looking for a way to do this declaratively in the XAML, by creating the Observable collections there, but alas, haven’t yet figured out how to do that.

Problems subclassing UserControl on WinRT

While trying to figure out how to add a generic mechanism for accelerators on buttons on my Win8 port of Bridge Stenographer I was faced with blank stares when asking about Keyboard Shortcuts

AutomationProperties.AccessKey="Number2" looked like the perfect property to add on my 2 button for instance, but I was disappointed to find out that nothing supported it.

In the end, I needed to have a base class that did some of the handling for my keyboard mapping to the access keys, as I don’t want to write that code over and over again (actually, I don’t want to debug and keep parallel copies up to date, but I digress).

So, what better way than a base class I thought.

So, here’s what I did.  I had my keyboard like control based on a UserControl.  Why not just change the base class to SpecializedUserControl like this:

public class SpecializedUserControl : UserControl
{

public SpecializedUserControl()
{
}

public void ExtraFunctionality()
{
}
}



Then, I can create a new user control, and base it on this new base class like this:


public sealed partial class MySpecializedUserControlInstance : SpecializedUserControl
{
public MySpecializedUserControlInstance()
{
this.InitializeComponent();
}
}


and declare it in XAML like this:

<local:SpecializedUserControl
x:Class="hoverbug.MySpecializedUserControlInstance"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:repro"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">

<Grid>
<Button>Sorry Charlie!</Button>
</Grid>
</local:SpecializedUserControl>


Interestingly, while writing this, I was disappointed to find that everything worked fine, and I wasn’t getting the error I got in my actual code.


Here’s how I instantiated the control on my page:


<local:MySpecializedUserControlInstance DataContext={Binding }" />


Not to be beaten (as it really didn’t appear to work in my code), I started porting across bits of my implementation, a feature of which was that I needed a property to attach to controls in my implementation that could hold a function to call when the AccessKey was pressed, so I did it like this in SpecializedUserControl:


public RoutedEventHandler KeyboardAction
{
get { return (RoutedEventHandler)GetValue(KeyboardActionProperty); }
set { SetValue(KeyboardActionProperty, value); }
}

// Using a DependencyProperty as the backing store for KeyboardAction. This enables animation, styling, binding, etc...
public static readonly DependencyProperty KeyboardActionProperty =
DependencyProperty.RegisterAttached("KeyboardAction", typeof(RoutedEventHandler), typeof(SpecializedUserControl),
new PropertyMetadata(null));


Now when I run the same program, I get this error:


oops


Anyone have any idea why adding a declaration of an attached property breaks it in this way?

PointerOver visual state on WinRT, it’s over even if it’s not.

I’ve been trying to get my Bridge Stenographer App ported to Windows 8 and in the process have come across a few problems.  The latest being that I click on a button on the welcome page to get somewhere else in the app, and when I navigate back, my button is still in the pointer over state, despite the pointer being elsewhere.

I’ve tracked this down to using  NavigationCacheMode="Required" on the page, in order to keep my page alive.

As a result, when I navigate back to the page, the controls don’t get whatever the equivalent of MouseLeave is, and therefore don’t transition out of the PointerOver state, and this doesn’t just apply to Buttons.  Combo boxes have this behavior as well.

You’ve been warned.