Monthly Archives: January 2015

Reading NumPad keys using WinRT

Recently, I discovered a bug with one of my Windows Store games – Maths Races. The issue was that when a number key was pressed, the program works fine, but pressing a number pad key – even with NumLock on wasn’t recognised.

Here’s the code that I was using the detect the keypress:

KeyboardState newState = Keyboard.GetState();
var keys = newState.GetPressedKeys();

foreach (var key in keys)
{
    if (!IsNewKeyPressed(key))
        continue;

    byte keychar;
    if (byte.TryParse(key.GetHashCode().ToString(), out keychar))
    {
        char newChar = Convert.ToChar(keychar);

        if (Char.IsNumber(newChar))
        {
            . . . 

So, when I press a number pad key with Num Lock off, it behaves as though I’d pressed a different character; for example NumPad0 resolves to a key character code of 96:

(byte.TryParse(key.GetHashCode().ToString(), out keychar))

Which when converted to a char is “`”.

Okay, so here’s how I got around this:

if (key.HasFlag(Keys.NumPad0 & Keys.NumPad1 & Keys.NumPad2 &
    Keys.NumPad3 & Keys.NumPad4 & Keys.NumPad5 & Keys.NumPad6 &
    Keys.NumPad7 & Keys.NumPad8 & Keys.NumPad9))
{
    char number = key.ToString().Substring(6)[0];
    . . .
}                
else
   . . .

Admittedly it isn’t very pretty, and if someone knows a better, or more elegant way to do this, then please let me know.

MVVM Cross – Creating a New Plug-in

This is quite a straightforward process, and well documented in several places – including here and here; and the sample that I used to create mine (and this tutorial) is here. However, I couldn’t find a step-by-step tutorial in a single place. So this is pretty much for my future self.

Disclaimer(s)

This only applies to Windows Store and Windows Phone. Although I believe the same process applies to iOS and Android.

The plug-in that I’m creating here will create a secondary tile on Windows Phone / Windows Store. However, this only covers the phone part, and doesn’t actually cover tile creation.

Create a Project

The project that I’m dealing with is a re-write of this application, using C# and MVVM Cross.

Obviously, your structure may be different, but the important thing is the Plugins folder at this stage; create a new portable project.

plugin1

Next, add the MVVMCross libraries:

plugin2

Interface and Plugin Loader

The portable class library above needs two files. Start with creating an interface:

    public interface ITile
    {
        Task<bool> CreateTile(string title);
    }

And next, the plug-in loader:

    public class PluginLoader : IMvxPluginLoader
    {
        public static readonly PluginLoader Instance = new PluginLoader();

        public void EnsureLoaded()
        {
            var manager = Mvx.Resolve<IMvxPluginManager>();
            manager.EnsurePlatformAdaptionLoaded<PluginLoader>();
        }
    }
}

Obviously, the next stage depends on your specific implementation. Mine depends entirely on the platform, so that’s all I need to do in the portable library.

Windows Phone

Create a new library project:

plugin3

plugin4

As before, you need to add the MVVM Cross Libraries, and a reference to the portable class above:

plugin5

The next stage is to implement your plug-in logic for the destination platform; in my case, this is logic to add a tile to Windows Phone:

    public class TilePlugin : ITile
    {
        public async Task<bool> CreateTile(string title)
        {
            // Create Tile code
        }
    }

Finally, just implement IMvxPlugin like this:

    public class Plugin : IMvxPlugin
    {
        public void Load()
        {
            Mvx.RegisterSingleton<ITile>(new TilePlugin());
        }
    }

Using the plug-in – the View Model

So, to all intents and purposes, the plug-in is now written (admittedly it only exists for Windows Phone, but that’s beside the point).

Next, it needs to be used; the first thing is to reference it.

plugin6

Here’s my logic to actually use the plug-in inside the view model:

    class SetupNewMailViewModel : BaseViewModel
    {
	. . . 
	
	        private void AddTile()
	        {
	            var tile = Mvx.Resolve<ITile>();
	            tile.CreateTile(MailHeading);
	        }
	    }
	

Using the plugin – Platform Specific

In the relevant project, a reference is needed:

plugin7

The only thing left to do for the platform is to add the bootstrap code:

public class TilePluginBootstrap : MvxPluginBootstrapAction<Tile.Plugin.PluginLoader> {    }

`MvxPluginBootstrapAction` signifies that the call to `MvxSetup` will call the BootstrapRunner for this plugin. Or, to put it another way, this magically makes MVVMCross aware of your new plugin for each platform.

Notes on Deployment

Above, I’ve basically manually added the reference to the correct project. This works fine when I’m working locally, but for an actual distributed plug-in, it’s NuGet that handles this.

Assigning an index to a collection using LINQ

This is a neat little trick that I came across when looking for a way to arbitrarily assign a unique index to each element in a collection. Imagine a scenario where you have a collection of a class such as the following:

    class TestIndex
    {
        public string Title { get; set; }
        public int Amount { get; set; }
        public int Index { get;set; }

        public override string ToString()
        {
            return string.Format("{0}: {1}, {2}", Index, Title, Amount);
        }

    }

Here’s the code to populate it:

List<TestIndex> l = new List<TestIndex>()
{
    new TestIndex() { Title="test1", Amount=20 },
    new TestIndex() { Title="test2", Amount=30 },
    new TestIndex() { Title="test3", Amount=5 },
    new TestIndex() { Title="test4", Amount=30 }
};

I’ve overriden ToString so that we can see what’s in it:

foreach (var t in l)
{
    Console.WriteLine(t.ToString());
}

linq1

A you can see, we have a field called Index, but it contains nothing (well, 0). However, it can be populated in a single line:

var newList = l.Select((el, idx) => { el.Index = idx; return el; });

linq2

The Select statement has an override that will tell you the index of that element based on the order; for example:

var newList = l.OrderBy(a => a.Amount).Select((el, idx) => { el.Index = idx; return el; });

linq3

Complete Code Listing

    class Program
    {
        static void Main(string[] args)
        {
            List<TestIndex> l = new List<TestIndex>()
            {
                new TestIndex() { Title="test1", Amount=20 },
                new TestIndex() { Title="test2", Amount=30 },
                new TestIndex() { Title="test3", Amount=5 },
                new TestIndex() { Title="test4", Amount=30 }
            };

            foreach (var t in l)
            {
                Console.WriteLine(t.ToString());
            }

            Console.WriteLine(" - - - ");

            var newList = l.Select((el, idx) => { el.Index = idx; return el; });

            foreach (var t in newList)
            {
                Console.WriteLine(t.ToString());
            }

            Console.ReadLine();
        }

        
    }

    class TestIndex
    {
        public string Title { get; set; }
        public int Amount { get; set; }
        public int Index { get;set; }

        public override string ToString()
        {
            return string.Format("{0}: {1}, {2}", Index, Title, Amount);
        }
    }

Returning an unknown interface from a WCF Service

The Problem

There are times when creating a WCF service that you may want to return a value, whilst not knowing precisely which value; for example, a service contract such as this:

[ServiceContract]
public interface IMyService
{
    [OperationContract()]
    FunctionResult MyFunction(string parameter);
}

… and a data contact like this:


[DataContract]
public class FunctionResult
{
    private int _myData;
    [DataMember(Name="MyData")]
    public int MyData
    {
        get { return _myData; }
        set { _myData = value; }
    }
	
    // Here, I want to return a class, 
    // but it may be a number of different 
    // options that share no commonality
}

So, how?

One solution to this, right or wrong, is to create a blank interface:

interface IData { }

Then to implement it in whichever class I want to return:

public class MyClass : IData

Finally, include this in my `FunctionResult` return class:

[DataContract]
public class FunctionResult
{
    private int _myData;
    [DataMember(Name="MyData")]
    public int MyData
    {
        get { return _myData; }
        set { _myData = value; }
    }

    private IData _returnData;
    [DataMember(Name="ReturnData")]
    public IData ReturnData
    {
        get { return _returnData; }
        set { _returnData = value; }
    }
}

You do need to declare the concrete class as a `ServiceKnownType`:


[ServiceContract]
[ServiceKnownType(typeof(MyClass))]
public interface IMyService
{
    [OperationContract()]
    OperationResult MyFunction(string paramater);
}

Acknowledgements

The `ServiceKnownType` wasn’t something I had come across before – thankfully, we have StackOverflow for that kind of thing:

http://stackoverflow.com/questions/310160/passing-interface-in-a-wcf-service

Startup Uri Not Working – Cannot locate recource ‘mainwindow.xaml’

I recently re-visited this project, and found that, amongst other things, it would no longer run up. Clearly something had changed, and it was a while until I realised what. The error I was getting was this:

Cannot locate resource

The App.Xaml looked like this:


<Application x:Class="TFSUtils.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:vm="clr-namespace:TFSUtils.ViewModel"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             StartupUri="MainWindow.xaml"
             mc:Ignorable="d">

Solution

I finally realised that I must have copied the MainWindow.Xaml into the Views folder as a last minute cleanup. The fix was very simple:


<Application x:Class="TFSUtils.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:vm="clr-namespace:TFSUtils.ViewModel"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             StartupUri="View/MainWindow.xaml"
             mc:Ignorable="d">

Conclusion

So, there you go: long untouched and untested code just spontaneously breaks! Magic.

Using a RepeatButton to Rapidly Increment Values

Recently, I’ve been playing with the WPF `RepeatButton`. I’ve not used it before, as it does seem to fulfil a very specific purpose. The use that I was trying to put it to was to act in the same way as you would expect your alarm clock to behave if you changed the time.

Say it’s currently 3:10 and you need it to be 3:15; you’d simply press the plus button five times, right? But what if you want it to be 17:50? Well, you’d hold the plus button down, but you wouldn’t expect it to increase by minutes; you’d maybe expect it to jump by 30 mins at a time after holding the plus button for a while.

The RepeatButton can do the same… but unfortunately not out of the box.

The Box

What you can do out of the box is this:

 <RepeatButton Content="+" Name="IncreaseButton"/>

And to handle the click:

IncreaseButton.Click += new RoutedEventHandler(IncreaseButton_Click);

Finally:

private void IncreaseButton_Click(object sender, RoutedEventArgs e)
{            
    Value += 1;
}

What’s wrong with that?

So far, so good, but what if I want the increment to increase though, as described in the alarm clock scenario above? I have two options here. One thing you can do is to increase the frequency that you increment; however, what I wanted to do was to increase the increment. The way I did it was to store a count:

private int _incrementButtonRepeat;

Then, in the `click` event:

private void IncreaseButton_Click(object sender, RoutedEventArgs e)
{            
    if (_incrementButtonRepeat > 5)
        Value += 5;
    else
        Value += 1;
    _incrementButtonRepeat++;        
}

Finally, you’ll need to reset:

private void IncreaseButton_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
    _incrementButtonRepeat = 0;
}

A little gotcha here is the MouseUp command never seems to fire, because it’s apparently handled internally. Use the preview to intercept it first.

Conclusion

You could create a very basic control that encapsulates this behaviour, based on some parameters; then you’d never have to consider this again.