Keyboard helper for Monotouch

Last year I started developing for Windows Phone 7 and was disappointed by the lack of form support, i.e. if you enter data into a field it you have to write code to move focus into the next field. Whilst developing a solution I stated iOS has much better support. So I was surprised when developing a similar application for iOS that it doesn’t have such support…unless someone can correct me on that?? In fact it’s worse because the keyboard covers the very field you want to type in. So if you want to put controls in a view and have the use move between them AND have them visible, you might find the following code helps. Please note this is very early days for the code so there are some hard coded sizes and probably a few issues, so please let me know if find anything or have a better mechanism. If anyone wants to contribute more formally I might place it on a public code site. Anyway here it is;

public static class KeyboardHelper
	{
		public static void ScrollControlIntoView(UIScrollView scrollViewer, UIControl field)
		{
			PointF nextPoint = new PointF(field.Frame.X, field.Frame.Top-30);
			scrollViewer.SetContentOffset(nextPoint, true);
		}
		
		public static void InitialiseFormFields(UIScrollView scrollViewer, List<UIControl> formFields)
		{
			System.Diagnostics.Debug.Assert(scrollViewer!=null);
			System.Diagnostics.Debug.Assert(formFields!=null);
			
			if (formFields.Count>1)
			{
				for(int index=0; index< formFields.Count-1; index++)
				{
					UIControl field = formFields[index];
					UITextField textField = field as UITextField;
					
					UIControl nextField = formFields[index+1];
					field.EditingDidBegin += delegate(object sender, EventArgs e) {
						ScrollControlIntoView(scrollViewer,field);
					};
					
					if (textField!=null)
					{
						textField.ShouldReturn = delegate
						{
							
							field.ResignFirstResponder();
								
							if (nextField is IUITextInputTraits)
									nextField.BecomeFirstResponder();
									
							KeyboardHelper.ScrollControlIntoView(scrollViewer, nextField);
							return true;
						};
					}
				}
			}
			UIControl lastField = formFields[formFields.Count-1];
			UITextField lastTextField = lastField as UITextField;
			lastField.EditingDidBegin += delegate(object sender, EventArgs e) {
					ScrollControlIntoView(scrollViewer, lastField);
			};
			
			if (lastTextField!=null)
			{
				lastTextField.ShouldReturn = delegate
				{
					lastField.ResignFirstResponder();
					
					KeyboardHelper.ScrollControlIntoView(scrollViewer, formFields[0]);
					return true;
				};
			}
			
		}
	}

To use the helper place your controls in a ScrollView and pass the helper an ordered list of the controls you want it to manage;

formFields = new List<UIControl>() { textBoxName, segmentedGender};
KeyboardHelper.InitialiseFormFields(scrollView, formFields);

Quick aide-mémoire, returning programmatic html in MVC

public ActionResult SayHello()
{
    return new ContentResult() { Content = "hello" };
}

Added unit test framework to Windows Phone 7 application

Today I finally decided that I needed a proper unit test framework for my Windows Phone 7 applications, no more hidden links on the start page 😉

I knew I wanted to use Jeff Wilcox’s Silverlight Unit Test Framework but it wasn’t as straight forward as I wanted it to be. Eventually I found this very useful page by Michael Sync. Some of the details and links are a bit old so;

  • Download (and remember to unblock) the necessary Dlls from Jeff Wilcox
  • The Windows Phone template no longer stores the starting page in the App.xaml, ignore that and instead remove the ‘NavigationPage’ attribute from the ‘DefaultTask’ element in WMAppManifest.xml

Happy Unit Testing…

Discovering what Data Item the control in your template is bound to

One issue that raises its head every now and again is how to add controls to a List’s Data Template in such a way that you can understand what data item the control is associated with when the control raises an event. E.g. I want to know what data item I should remove from a list when the user de-selects a checkbox;

<DataTemplate x:Key="MyDataClassItemTemplate">
    <StackPanel>
        <CheckBox IsChecked="{Binding IsSelected, Mode=TwoWay}" 
                    Content="{Binding DisplayName}" 
                    Unchecked="CheckBox_Unchecked"
                    />
    </StackPanel>
</DataTemplate>

As you can see the checkbox has an Unchecked event but when that fires you will only be told what specific instance of the checkbox raised the event, not what the associated data item is. Previously I have worked-around this issue using the Visual Tree but I’ve always hated that solution. So I’m now using the following code that relies on the fact that my control has some form of data binding;

private MyDataClass MyDataClassFromCheckBox(object sender)
{
    FrameworkElement fe = sender as FrameworkElement;
    BindingExpression be = fe.GetBindingExpression(CheckBox.IsCheckedProperty);
    MyDataClass selectedMyDataClass = be.DataItem as MyDataClass;
    return selectedMyDataClass;
}

There, a much nicer solution. Note the ‘IsCheckedProperty’, this would need to be changed depending upon the property you are using in the binding – it is easy to pass that in as a dependancy property argument. Another quick point, previously I’ve had a similar problem using a Button in a template. However, the button only had a fixed caption so there was no binding expression to use. One simple trick here is to create a fixed property in your view model and bind to that, e.g. myViewModel.ButtonCaption { get {return “My Button Caption” }}. Yes it’s a slight overhead but you may prefer that to using the visual tree, I do.

MVC Helper for Gravatar

Jus a quick code snippet for display a user’s Gravatar in MVC;

public static MvcHtmlString DisplayGravatar(this HtmlHelper helper,
            string emailAddress, int size=80)
        {
            return new MvcHtmlString("<img src=" + 
                GravatarUrl(helper, emailAddress, size) + " />");
        }

        public static string GravatarUrl(this HtmlHelper helper, 
            string emailAddress, int size=80)
        {
            if (size < 1 || size > 512)
            {
                size = 80;
            }
            //1.Trim leading and trailing whitespace from an email address            
            //2.Force all characters to lower-case
            emailAddress = emailAddress.Trim().ToLower();
            //3.md5 hash the final string
            string md5Hash = GetMD5Hash(emailAddress);

            return string.Format("http://www.gravatar.com/avatar/{0}?s={1}",
                                                            md5Hash, size);
        }

        private static string GetMD5Hash(string input)
        {
            System.Security.Cryptography.MD5CryptoServiceProvider x =
                new System.Security.Cryptography.MD5CryptoServiceProvider();
            byte[] bs = System.Text.Encoding.UTF8.GetBytes(input);
            bs = x.ComputeHash(bs);
            System.Text.StringBuilder s = new System.Text.StringBuilder();
            foreach (byte b in bs)
            {
                s.Append(b.ToString("x2").ToLower());
            }
            string password = s.ToString();
            return password;
        }

Update to Keyboard Behavior

Found a bug in my Keyboard Behavior where it didn’t correct discover the page the behavior was on. This meant that under certain circumstances the keyboard would not be hidden after the last tab.

I’ve updated the source code.

LongListSelector nullexception gotcha

Just had a little puzzler with my Windows Phone 7 application. My application uses the LongListSelector which is bound to a view model. However, if I launch a second page that will add extra data to the model and return back the LongListSelector kept throwing a nullexception error. It would appear the the LongSelector does not like receiving an OnPropertyChanged whilst on a page that is not currently showing. To workaround the problem I’ve had to expose a ‘Refresh’ method on my view model that the page invokes when it redisplays. I dare say it’s something I’ve not understood correctly about the page life cycle, so I thought I’d share it to a) help someone else with the same problem b) hope someone helps me with a better solution

Firebrand Bootcamp training review

My company needed to push four staff members through the Microsoft Certification program, so I was asked to attended a training bootcamp supplied by Firebrand Training. Here is my review of my time there;

What is it?
My course was 11 days long, including taking exams in Data, Web Development, WCF and an the solution designed based Web Pro.

What does a day consist of?
The basic timetable is;
7am-8:20am Breakfast
8:20-12 Working though the official Microsoft courseware with a teacher. Some of the hands-on labs are worked through, but only a selected few. There are few 10 min breaks during this time.
NB The courseware is typically aimed a 5-days, the bootcamp asks you to complete them in at most 3 days and for WCF 1 day.
12:00-12:30 Lunch
12:30-19:00 Typically a mix of courseware and the MeasureUp tests and the end of the session. MeasureUp tests provide 150 mock questions that provide an explanation of the correct (and incorrect) answers.
19:00-19:30 Dinner
19:30-23:00/00:00 Completion of MeasureUp tests, reading of the provided Study Guide and reading of the next days slides

Exam days are different. Typically they include a classroom review where everyone goes through a set of mock questions and talk about why they chose the answers they selected. Then a period of time (changed for each exam) to cram for the exam. Then the exam itself.

What are the facilities like?
The training ‘camp’ is on a hotel complex where the class rooms and accommodation are on a separate part of the complex. The training area can be accessed 24×7 and has hot/cold drinks, fruit and vending machines for chocolate and cans/bottle drinks. There is a common area where you can watch the news or play Fifa on the Xbox.
The accommodation is simple but clean enough and the staff are helpful. However, I was originally placed in a room that was 20′ from the main A1 and I lost two nights sleep before I asked to change room, a decision I should have taken after the first night. The bed linen is not very nice either, sorry but it’s not good. My room did have a mini kettle, contrary to the web site description. There is an ironing room too, which I did have to use.
The food was decent, with a choice between a vegetarian or meat dish for dinner and a sandwich bar or hot food for lunch.

What was it like?
First up, we almost achieved the goal. At the end of the course the four of us had passed all the exams except for one exam. I failed the Data exam (by one mark) but passed the retest. You got (or get if the offer is still on) one free retake per exam. So the ends would seem to justify the means. I would also add that many of my fellow students were keen to go home and create sites using the technologies on the course, so it was certainly successful for some people. However, I think it really depends on why you attend such a course. There seemed to be three distinct groups of people on the course; 1) Company sent Certification hunters – know about technology and have the foundations to allow them to rush through a 5-day course in 1-3 days. 2) Professionals looking to enhance their knowledge of specific areas – certification is a nice to have, more interested in learning new stuff 3) Retraining – professionals looking to learn something new. The course is certainly aimed at (1). You are directed through the course with the prime aim of learning just enough to get you through the exam. Did I learn new stuff, yes I did. Do I know it to a good depth, probably not, the lack of time spent on the lab work means you do not gain the experience of using the technologies. So for those in group (2) then I think they were a little disappointed. Group (3) would be better served by taking a course focused on one specific subject.

My recommendations;

  1. Make sure you can sleep – ask to change room, take ear muffs if you must. If you’re driving there then consider taking your own pillows. Also close the window vents at night, that really helps to reduce the noise
  2. Don’t put up with people chatting (or celebrating) at the end of the corridors outside your room. It’s not nice but you can’t afford to be distracted, ask them nicely to move on
  3. Hold your questions – this is about passing the exams, don’t be tempted to consider the wider use of the technologies you really can’t afford to lose time. Also don’t ask, “it’s on the next slide” questions – there is a reason you’re asked to read the slides the night before.
  4. Don’t waste time. Don’t read emails, go on Twitter, nothing. I can’t emphasise enough that you don’t have any spare time. You’ll be working at least 16 hour days, you’ll need them all
  5. The study guide is your friend, read it and read it well
  6. Before you go I would advise you brush up on your asp.net page life cycle, what Transactions are and the Session managers (In Proc, State Server, Sql Server). You need those and there isn’t enough time spent on them
  7. It’s as much about learning how to test, get into the ‘groove’ of the questions. Learn how they’ll try and trick you, read the questions very carefully. I know it’s been said before, but often they’ll be more than one correct answer, just a subtle change in the question will mean one is more correct than the other – I hate that, stupid IMO

Summary:
Overall it did produce the results but it is not easy. The pass rate was not great and one student failed 3 of the 4 but was obviously very bright. If, like them (and me) you like to go into these exams with a real sense that you know it all (well most of it) then this might not be for you. If you’re good at hands-off book learning then it’s probably well suited to you. That’s not to say you can’t pass from just studying, I managed it after-all 😉

My .net performance counters were missing on Windows 7

I had a strange problem today. I wanted to take a peek at the CLR memory performance counters but I couldn’t find them. After some searching it turns out I needed to set the following registery key to 0;

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\.NETFramework\Performance\Disable Performance Counters

How to add a link to a project folder in Visual Studio

I’ve had a quick play with adding the contents of a folder from another project, i.e. I want to add links to all the files in another project’s folder. So for example; I have a project called ConsoleApplication1 and I want to ensure it always has links to the images in another project called ClassLibrary1 (yes nice names eh). So first create a folder with the same name, e.g. images, in ConsoleApplication1. Add a link to one of the files in ClassLibrary1\Images (Add existing item->add as link). Unload ConsoleApplication1 and Edit the project file. Locate the Content Include and replace it as follows;

<ItemGroup>
  <Content Include="..\ClassLibrary1\images\*.*">
    <Link>images\%(RecursiveDir)%(FileName)</Link>
  </Content>
</ItemGroup>

So whatever changes you make to ClassLibrary1\Images will automatically be reflected in ConsoleApplication\Images. It’s early days but it seems to run ok.