Wednesday, 6 April 2011

Creating a clickable TextBlock (or any control) in WP7 using a Custom Control

I came across a need on my current windows phone 7 project to have different parts of my item in a listbox clickable with different events. Plus I’m using MVVM Light. Sounds easy, right? Well I thought so until I realised that the TextBlock control doesn’t have a click event.

First thought was putting the TextBlock into a button as content. This works, although you get this inverted effect on clicking which really didn’t look good on the controls I had. I could change this effect using states, but the button still clicked when you happened to be dragging and the starting point was the button.

Next I looked at the GestureService/Listener which is included in the Silverlight Toolkit. This is very useful but doesn’t allow binding to MVVM Light using eventToCommand behaviours.
Then I looked at a TextBlock having MouseLeftButtonDown & Up events which I could capture. But that still fires even if I’m just dragging the list around but happened to start on the control.
So I figured I could get around this by tracking the point of click. My app is using MVVM however and I didn’t want to start putting either
  1. Mouse event handling code in my ViewModel
  2. Lots of events in my View
So instead I thought I’d create a custom control that has a data bindable click event.
Whilst creating this reusable control I thought I’d add the ability to choose it’s click detection type.
  • Point based would look to see if your finger/mouse is in the same spot when you press down and then up (good for scrolling)
  • Border based would look to see if you’re in the bounds of the zone (like a traditional button).
Here’s the steps I took:
Create the new a Windows Phone Class Library project. This will be where the control lives.
Rename the Class1.cs using the Solution Explorer to your new control name. In this instance I’ve called it ClickZone.
Just above the class declaration (or in a separate file if preferred) add a public enumeration to identify the possible click types.
This control will inherit from the ContentControl. This will easily allow it to contain content (other controls), and will act as a click zone for them all.
Add a private Point variable to track the point when the finger/mouse is pressed down. Also add a boolean flag to track when the finger/mouse is in the control.
Your code should look similar to this now:
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Controls;

namespace CustControlTest
public enum ClickDetectType { PointBased, BorderBased };

public class ClickZone : ContentControl
//Reference for point based click
private Point startPoint = new Point();

//Flag for border based click
private bool isInBorder;

Now to add a click Event which can be captured, and a public property for the detection type.

public event EventHandler Click;
protected virtual void OnClick()
EventHandler handler = Click;
if (handler != null)
handler(this, new EventArgs());

private ClickDetectType _detectionType = ClickDetectType.PointBased;
public ClickDetectType DetectionType
get { return _detectionType; }
set { _detectionType = value; }

Next I need to capture the key mouse/finger events and track when it’s entering or leaving the control and when pressing/releasing. It’s on the release that I need to decide whether to fire the Click event or not.

protected override void OnMouseLeave(MouseEventArgs e)
//track border exit
isInBorder = false;

protected override void OnMouseEnter(MouseEventArgs e)
//track border entry
isInBorder = true;

protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
//track point entry
startPoint = e.GetPosition(null);

protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
switch (_detectionType)
case ClickDetectType.BorderBased:
if (isInBorder)
case ClickDetectType.PointBased:
if (startPoint.X == e.GetPosition(null).X && startPoint.Y == e.GetPosition(null).Y)

isInBorder = false;
startPoint = new Point();


Now that’s the class done, but it still needs a template. This is where you need a ResourceDictionary xaml file. Create a folder called Themes, and in it add a new xaml file called generic.xaml. Make sure you switch the Build Action to Resource, as it needs to be compiled into the DLL.


For my control layout I went for a simple structure of a Border control, with the content inside inside it. For more details on creating a ResourceDictionary, see the links at the bottom.

<?xml version="1.0" encoding="utf-8" ?>
<Style TargetType="controls:ClickZone">
<Setter Property="Background" 
<Setter Property="BorderBrush" 
Value="{StaticResource PhoneTextBoxBrush}"/>
<Setter Property="BorderThickness" 
Value="{StaticResource PhoneBorderThickness}"/>
<Setter Property="Template">
<ControlTemplate TargetType="controls:ClickZone">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Margin="{TemplateBinding Padding}"/>

Using the TemplateBindings meant that the properties can be changed when reusing the control later.

Hopefully that should all compile fine now. So to test, create a new Project and reference this project. I’m going to use an MVVM Light one to show binding. You should now see the ClickZone control in the Toolbox


You can now drop this control on your page, and put content inside it. For this I’ll use Blend to show Blendability.


As you can see, I am able to add an EventToCommand behaviour to the ClickZone.

You can see on the Properties of the EventToCommand that I can now bind to the Click event.


Finally adding a command to the ViewModel which updates a property I can see the result!


Links I found useful:

I have included all the code and sample MVVM Light application in the following file:

Thursday, 31 March 2011

Changing ApplicationBar items at runtime on Windows Phone 7

I'm currently developing a Windows Phone 7 application for work (that adds to the list of languages I've worked on since joining 6 months ago, the others being python and java - gotta love the labs environment!)

Something small which vexed me briefly was trying to change icons and menu bar items at runtime. If you've tried to reference them by name in code then you'll have most likely been presented with a null reference error.

The trick is to reference them by index number (zero based), for example:

var iconbutt = (IApplicationBarIconButton)ApplicationBar.Buttons[0];
var menuitem = (IApplicationBarMenuItem)ApplicationBar.MenuItems[0];

You can then modify them as required.

The reason that you have to do this is because the ApplicationBar and it's child items stem from Microsoft.Phone.Shell namespace rather than System.Windows.Controls. This also explains why you can't simply data bind, although there are workarounds for that.

Wednesday, 23 February 2011

Installing Django in VirtualEnv (Ubuntu - also with postgres & piston)

Due to work, I've recently switched from working with MS products and C# development to working in ubuntu developing python.

One of the first bits of advice I was given was to use virtualenv which allows you to isolate python environments, rather than just using the machines environment (and cluttering it/get clashes of versions etc)

The project I'm working on uses Django with a Postgres database, so here are the steps I needed to get it working. I'm using the default version of python however you can install different ones.
#install virtualenv
sudo apt-get install python-virtualenv

#install headers needed for psycopg2
#You can skip the next line if you're not using postgres as the database
sudo apt-get install libpq-dev python-dev

#create a folder for the virtual environment
mkdir mypyenv

#create the virtual environment
#no-site-packages ensures the environment doesn't also include packages installed at machine level
virtualenv --no-site-packages --distribute mypyenv

#switch to environment (environment name will be in brackets on terminal)
source mypyenv/bin/activate

#install django
pip install -E mypyenv Django

#I'm using piston also for my api - skip if you don't want it
pip install -E mypyenv django-piston

#install django
pip install -E mypyenv psycopg2
That should now be installed. Now just switch to your project folder and you should be able to work with it. If this is your first project then I'd highly recommend the official tutorial

Once you're finished using virtual environment, use the deactivate command to come out of it.