Creating a reusable Silverlight login window – part 2
This is part 2 on how to create a reusable login window for Silverlight, part 1 is here.
The Authenticate.xaml child window created in the last post has evolved a little, instead of using Actions it now uses regular old events.
public partial class Authenticate : ChildWindow { #region "Properties" private readonly AuthenticationContext _authContext = new AuthenticationContext(); public static String Email { get; set; } public static event EventHandler OnBeforeAuthentication; public static event EventHandler OnAuthenticated; public static event EventHandler OnAfterAuthentication; public static event EventHandler OnFailedAuthentication; public static Boolean IsAuthenticated { get; set; } #endregion public Authenticate() { InitializeComponent(); if (IsAuthenticated) if (OnAuthenticated != null) OnAuthenticated(this, null); } private void OKButton_Click(object sender, RoutedEventArgs e) { DialogResult = true; if (OnBeforeAuthentication != null) OnBeforeAuthentication(sender,e); _authContext.Authenticate( Username.Text, Password.Password, delegate(InvokeOperation<Boolean> inv) { IsAuthenticated = inv.Value; if (inv.Value) { Email = Username.Text; IsAuthenticated = true; if (OnAuthenticated != null) OnAuthenticated(sender, e); } else { IsAuthenticated = false; if (OnFailedAuthentication != null) { OnFailedAuthentication(sender,e); } } }, null); if (OnAfterAuthentication != null) OnAfterAuthentication(sender,e); } private void CancelButton_Click(object sender, RoutedEventArgs e) { if (OnFailedAuthentication != null) { OnFailedAuthentication(sender,e); App.LoadControl(new Unauthorised()); } DialogResult = false; } }
I also made the EventHandlers static so that multiple controls can wire up delegates.
I added a new UserControl (AuthenticateControl.xaml) in order to house the Authenticate child window. The xaml for this control only contains the following.
<UserControl x:Class="EMASolutions.CMS.Plugins.Silverlight.Controls.AuthenticateControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" > </UserControl>
The code behind contains the following.
public partial class AuthenticateControl : UserControl { public Boolean RequiresAuthentication { get; set; } public Authenticate LoginControl { get; set; } public AuthenticateControl() { InitializeComponent(); LoginControl = new Authenticate(); Loaded += Control_Loaded; } void Control_Loaded(object sender, RoutedEventArgs e) { if (!RequiresAuthentication) return; LoginControl = new Authenticate { Title = "Authenticate" }; if (!Authenticate.IsAuthenticated) LoginControl.Show(); Authenticate.OnFailedAuthentication += delegate { LoginControl.Show(); }; } }
This control is going to become a base control for our others to inherit from. In our other controls we can then set the RequiresAuthentication property to true and if the user has not yet authenticated they will be prompted to do so.
Here is an example of how we can use it in a control.
public partial class FolderBrowser : AuthenticateControl { public FolderBrowser() { _folderContext = new FolderContext(); _documentContext = new DocumentContext(); InitializeComponent(); Loaded += MainPage_Loaded; } void MainPage_Loaded(object sender, RoutedEventArgs e) { RequiresAuthentication = true; Authenticate.OnBeforeAuthentication += delegate { Dispatcher.BeginInvoke( () => { IsBusy = true; }); }; Authenticate.OnAuthenticated += delegate { _folderContext.Load( _folderContext.GetFoldersQuery(), LoadBehavior.RefreshCurrent, delegate { Dispatcher.BeginInvoke ( () => { folders.ItemsSource = _folderContext.Folders.Where(f => f.ParentId == 0); IsBusy = false; } ); }, null); }; } }
Notice this control now inherits from AuthenticateControl, the xaml must also be changed to include the AuthenticateControl as its root tag in place of UserControl.
In other controls, that do not require any sort of authentication we dont have to inherit from AuthenticateControl, we can just inherit from UserControl.
We can still make use of the static event handlers in the Authenticate child window, consider the following as an example.
public partial class TopBar : UserControl { public TopBar() { InitializeComponent(); Authenticate.OnAuthenticated += delegate { Email.Text = Authenticate.Email; }; } }
This simply appends an additional action to the OnAuthenticated event handler, so if a user has Authenticated using a control that required it we can tap in an use the email address they authenticated with to display it on screen.
Using this method we can be flexible in displaying authentication prompts and we can also allow dynamic loading of any control as the RootVisual in our Silverlight application.
This means we can pass a parameter from the server when the Silverlight application launches and define which control we want as our root visual based on something a user did. We dont have to direct them to a login area by default. We just allow our control to handle that.
I hope this makes sense, it seems like a nice way of doing things to me but I’m not sure I’ve explained it well. I’m still learning about the best way of doing things with Silverlight, so take everything with a ‘large’ pinch of salt.