Sunday, June 26, 2011

How to create a ChildWindow Login Popup for Windows Phone 7

Introduction

After struggling with a navigation issue in my app of when to show/go to/return from the Settings page that captured the user name and password, I decided to pop up a window on any page where and when credentials were necessary but not currently known. Since I knew I was going to add more credential-requiring pages in my app, using a popup allowed me to reduce my dependency on navigation silliness between the pages, and have a more encapsulated design.

 

This post will show you how to pop up a ChildWindow on the app page to grab the user’s login credentials. The control allows the old username and password to be passed into the control so that previous values can appear. The tab order/enter key switches from textbox to textbox to button.

 

image

 

The sample application included in this post just displays the results on the calling page.

 

image

image

Acknowledgements

Several other posts helped me along the way:

 

Jesse Liberty’s video “Creating a custom popup in Window Phone 7” 

Shawn Wildermuth’s “Using ChildWindow in Windows Phone 7 Project

Raj Kumar’s “How to Implement ChildWindow in Windows Phone 7”

Coding4Fun Source code at Codeplex

 

ChildWindow Control Reference

The LoginChildWindow inherits from System.Windows.Controls.ChildWindow so you must add that as a reference. 

 

LoginChildWindow.xaml

   1:  <tk:ChildWindow x:Class="LoginChildWindow.LoginChildWindow"
   2:      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   5:      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   6:      xmlns:tk="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
   7:      mc:Ignorable="d"
   8:                   VerticalAlignment="Top"
   9:                  HorizontalAlignment="Left"
  10:      Title="Login" 
  11:                  
  12:                  BorderBrush="Black"
  13:                  BorderThickness="2"                 
  14:      FontFamily="{StaticResource PhoneFontFamilyNormal}"
  15:      FontSize="{StaticResource PhoneFontSizeNormal}"
  16:      Foreground="{StaticResource PhoneAccentBrush}"                
  17:      d:DesignHeight="256" d:DesignWidth="480"
  18:      HasCloseButton="false">
  19:   
  20:      <Grid x:Name="LayoutRoot" Height="202" Background="{StaticResource PhoneBackgroundBrush}">
  21:          <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="User: " VerticalAlignment="Top" Margin="20,43,0,0"/>
  22:          <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Password: " VerticalAlignment="Top" Margin="20,104,0,0"/>
  23:          <TextBox x:Name="txtUserId" VerticalAlignment="Top" Margin="117,23,8,0" Height="62" FontSize="18.667" TabIndex="1"  KeyUp="txtUserId_KeyUp"/>
  24:          <PasswordBox x:Name="txtPassword"  VerticalAlignment="Top" Margin="117,85,8,0" Height="62" FontSize="18.667"   TabIndex="2" KeyUp="txtPassword_KeyUp"  MouseLeftButtonUp="txtPassword_MouseLeftButtonUp"/>
  25:          
  26:          <Button x:Name="btnLogin" Content="Login" Margin="117,132,214,0" d:LayoutOverrides="Width" Click="btnLogin_Click" FontSize="18.667" BorderBrush="{StaticResource PhoneAccentBrush}" BorderThickness="1" Foreground="{StaticResource PhoneForegroundBrush}" Background="{StaticResource PhoneInactiveBrush}" Height="58" VerticalAlignment="Top" FontFamily="Tahoma" TabIndex="3" />
  27:          <!--<Button x:Name="btnCancel" Content="Cancel" HorizontalAlignment="Left" Margin="232,132,0,0" VerticalAlignment="Top" FontSize="18.667" BorderBrush="{StaticResource PhoneAccentBrush}" BorderThickness="1" Foreground="{StaticResource PhoneForegroundBrush}" Background="{StaticResource PhoneInactiveBrush}" Height="58" FontFamily="Tahoma" Click="btnCancel_Click" />-->
  28:      </Grid>
  29:  </tk:ChildWindow>
 

VerticalAlignment and HorizontalAlignment are set so that the window appears at the top of the screen. Without them, on my HD7, the on-screen keyboard overlays the child window and the user plays a game of tapping the control then the keyboard to get to the right place. I used system fonts so that the control will work with the phone’s current settings. If your app uses custom settings, you will need to change these. The cancel button, which is usually next to the login button, has been commented out on purpose. In my app, the login credentials are vital and canceling makes no sense. The user can always back button or start button away from the app, if they choose. The child window’s upper right corner cancel (icon of small x) is also removed via HasCloseButton="false" for the same reason.

 

LoginChildWindow.xaml.cs

 

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Net;
   5:  using System.Windows;
   6:  using System.Windows.Controls;
   7:  using System.Windows.Documents;
   8:  using System.Windows.Input;
   9:  using System.Windows.Media;
  10:  using System.Windows.Media.Animation;
  11:  using System.Windows.Shapes;
  12:   
  13:  namespace LoginChildWindow
  14:  {
  15:      public partial class LoginChildWindow : ChildWindow
  16:      {
  17:          public string Login { get; set; }
  18:          public string Password { get; set; }
  19:   
  20:          public LoginChildWindow()
  21:          {
  22:              InitializeComponent();
  23:          }
  24:          protected override void OnOpened()
  25:          {
  26:              base.OnOpened();
  27:   
  28:              this.txtUserId.Text = this.Login;
  29:          }
  30:          private void btnLogin_Click(object sender, RoutedEventArgs e)
  31:          {
  32:              // test values
  33:              if ((txtUserId.Text == null) || (txtPassword.Password == null))
  34:              {
  35:                  MessageBox.Show("WP7: Username & Password must be filled in before logging on.");
  36:                  //this.DialogResult = false;
  37:              }
  38:              if ((txtUserId.Text.Trim() == string.Empty) || (txtPassword.Password.Trim() == string.Empty))
  39:              {
  40:                  MessageBox.Show("WP7: Username & Password must be filled in before logging on.");
  41:                  //this.DialogResult = false;
  42:              }
  43:              else if (txtUserId.Text.Trim().Length < 2)
  44:              {
  45:                  MessageBox.Show("WP7: Invalid username or password. Be sure to use the WAZUp website login, not the Windows Azure login.");
  46:                  //this.DialogResult = false;
  47:              }
  48:              else
  49:              {
  50:                  // values are good so close this childwindow
  51:                  this.Login = this.txtUserId.Text.Trim();
  52:                  this.Password = this.txtPassword.Password.Trim();
  53:                  this.DialogResult = true;
  54:              }
  55:          }
  56:          //private void btnCancel_Click(object sender, RoutedEventArgs e)
  57:          //{
  58:          //    this.DialogResult = false;
  59:          //}
  60:          private void txtUserId_KeyUp(object sender, KeyEventArgs e)
  61:          {
  62:              if (e.Key == Key.Enter)
  63:              {
  64:                  if (txtPassword.Password.Length == 0)
  65:                  {
  66:                      txtPassword.Focus();
  67:                  }
  68:                  else
  69:                  {
  70:                      btnLogin_Click(sender, e);
  71:                  }
  72:              }
  73:          }
  74:          private void txtPassword_KeyUp(object sender, KeyEventArgs e)
  75:          {
  76:              if (e.Key == Key.Enter)
  77:              {
  78:                  btnLogin_Click(sender, e);
  79:              }
  80:          }
  81:          private void txtPassword_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
  82:          {
  83:              btnLogin_Click(sender, e);
  84:   
  85:          }
  86:      }
  87:  }

 

The validation routines are shallow. Please use them as a starting point for your own app requirements. The KeyUp and Mouse events are to make sure the enter button moves the cursor to the next logical place in the child window. It just saves the customer a step.

 

Main Page’s calling code

   1:  using System;
   2:  using System.Net;
   3:  using System.Windows;
   4:  using System.Windows.Input;
   5:  using Microsoft.Phone.Controls;
   6:   
   7:  namespace LoginChildWindow
   8:  {
   9:      public partial class MainPage : PhoneApplicationPage
  10:      {
  11:          public string Username { get; set; }
  12:          public string Password { get; set; }
  13:   
  14:          // Constructor
  15:          public MainPage()
  16:          {
  17:              Username = "OldUserName";
  18:              InitializeComponent();
  19:              this.txtBlockUsername.Text = Username;
  20:          }
  21:   
  22:          private void button1_Click(object sender, RoutedEventArgs e)
  23:          {
  24:              LoginChildWindow loginWindow = new LoginChildWindow();
  25:              loginWindow.Login = Username;
  26:              loginWindow.Closed += new EventHandler(OnLoginChildWindowShow);
  27:              
  28:              loginWindow.Show();
  29:          }
  30:          private void OnLoginChildWindowShow(object sender, EventArgs e)
  31:          {
  32:              LoginChildWindow loginChildWindow = sender as LoginChildWindow;
  33:   
  34:              if (loginChildWindow.DialogResult == true)
  35:              {
  36:                  this.txtBlockUsername.Text = loginChildWindow.Login;
  37:                  this.txtBlockPassword.Text = loginChildWindow.Password;
  38:                  //;
  39:              }
  40:          }
  41:      }
  42:  }

 

Caution: While I have included my version of System.Windows.Controls.dll in the app download, please use your own. I’ve grabbed several in the last six months from various locations and I don’t know if mine is the right one.

Looking for More Advanced Concepts for Pop ups?

This is a very simple example of a pop up both in design and usage. If you want a bigger, better, meatier answer, go over to the Coding4Fun project at Codeplex and grab the source code. This toolkit has some great ideas for pop ups.

 

Make sure to unblock the dependency dlls, build the solution, then debug the test project. Set break points in /Samples/Prompts.xaml.cs file.

 

Grab the Code for this Blog Post

Download Visual Studio 2010 Project (zipped)

No comments:

Post a Comment

Post a Comment