BlogMarq

WPF, SILVERLIGHT and WINDOWS PHONE development

Xamarin Android development

A friend introduced me to Xamarin recently.  Compared to some other cross platform development API's I've reviewed I have to that I am very impressed.  We will be release some Android apps soon as a taster to the market (we're virgins in that territory).

We'll probably also do some articles using the the Xamarin Studio IDE and general Android development using C#.  Watch this space!

How to implement a login in your WP7 app without breaking Certification Requirement 5.2.4.2

The WP7 App Technical Cerfication Requirements 5.2.4.2 (Back Button: First Screen) states that the Back Button when pressed from the first screen must close the application.

So how do we do this if we require a Login page? The answer is quite simple, you need to have 2 states for your MainPage (first screen). And I found the best approach is to create 2 user controls and assign one to each state of the MainPage.

  • MainPage.xaml
  • LoginUserControl.xaml
  • MainUserControl.xaml

Within MainPage create a VisualStateGroup for Login and another for Main, each state should only show one of the UserControls. You then bind the “current” state to a property on your MainViewModel. Now all you have to do is set that property at the appropriate time, so for example the default view would be to show the Login control and hide the Main control. then once the user has successfully logged-in you just set the property on MVM and teh VisualStateManager will do the rest for you. Easy.

This is exactly how we achieved this in our Notebox Pro WP7 App.

WP7 Measuring Performance

During development and certainly debugging its extremely useful to observe the various performance metrics available within the Windows Phone 7 environment.

Performance Counters
You can enable the performance counters in Windows Phone using the following line of code.

Application.Current.Host.Settings.EnableFrameRateCounter = true;

When you create a Windows Phone 7 App in Visual Studio this line of code will already be present in the App.xml.cs class, and by default it only shows Performance counters when a debugger is attached.

Redraw Regions
You can enable redraw regions in Windows Phone using the following line of code.

Application.Current.Host.Settings.EnableRedrawRegions = true;

Cache Visualization
You can enable cache visualization in Windows Phone using the following line of code.

Application.Current.Host.Settings.EnableCacheVisualization = true;

WPF Switch Color Theme at Runtime

This very simple class will allow you to switch a Themes in a WPF application. Its not the only way to do it and is not a MVVM implementation, but can be modified to be if needed. For this example I’m keeping it simple. Here is the resource (theme) switching code:

public static class ThemeHelper
    {
        public static void SwitchTheme(string stylefile)
        {
            if (File.Exists(stylefile))
            {
                using (FileStream fs = new FileStream(stylefile, FileMode.Open))
                {
                    ResourceDictionary dic = (ResourceDictionary) XamlReader.Load(fs);
                    Application.Current.Resources.MergedDictionaries.Clear();
                    Application.Current.Resources.MergedDictionaries.Add(dic);
                }
            }   
        }
 
        public static void SwitchTheme(Uri themeUri)
        {
            var theme = new ResourceDictionary();
            theme.Source = themeUri;
            Application.Current.Resources.MergedDictionaries.Clear();            
            Application.Current.Resources.MergedDictionaries.Add(theme);
        }
    }

For this to work just create a folder called “Themes” add your Theme files into there and mark as content. Each theme file must be in the same structure (i.e. use the same Key names obviously) for this to work.
Here is an example of a theme file:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <SolidColorBrush x:Key="ThemeColor1">Green</SolidColorBrush>
    <SolidColorBrush x:Key="ThemeColor2">Red</SolidColorBrush>
    <SolidColorBrush x:Key="ThemeColor3">Orange</SolidColorBrush>
</ResourceDictionary>

Then anywhere in code you can changes themes like so (assuming you added a file called MangoTheme.xaml into the \Themes\ directory:

ThemeHelper.SwitchTheme(new Uri("/Themes/MangoTheme.xaml", UriKind.Relative));

WP7 Internationalization

Internationalization doesn’t have to be that difficult. I have recently Internationalized #Notebox using the following method. Firstly, I added a helper class that will act as my store for the current culture strings/phrase for use in my View bindings:

public class InternationalizationHelper
    {
        private static readonly AppResources LocalizedResource = new AppResources();
 
        public AppResources Resources
        {
            get { return LocalizedResource; }
        }
    }

Next, I made this class available to my Views by adding this line to my App.xaml

<Code:InternationalizationHelper x:Key="localizedResx" />

Now for the actual strings and phrases. I added a Resources file called “AppResources.resx” to my project and started adding the Name/Value strings. e.g. Name=”LoginPageTile”, Value=”Login Page”. This default resources file will be used by the application Neutral Language, which can be found on the Project Properties, Assembly Info panel. To add further support for other languages I needed to do 2 things:

  • Add support for the cultrue to the visual studio project file (edit the proj file and add to the SupportCulture section, e.g.
    <SupportedCultures>it-IT;el-GR;es-ES;</SupportedCultures>
  • Add a AppResources.xx-XX.resx for each culture you want to support, where “xx-XX” is the culture code.
  • For this to work all of the resource files must use the same key Name(s). If a resource file for a particular culture does not contain the key Name then the default AppResources.resx Name entry will be used.

    The final step was to refer to these Names within the Resources file. This was achieved using a binding like this:

    Text="{Binding Path=Resources.LoginPageTitle, 
    Source={StaticResource localizedResx}}"

Useful C# DeepCopy method

Here is a simple DeepCopy method I use in my projects. To use it I just decorate my objects using the DataContract attribute.

public static T DeepCopy<T>(T obj)
        {
            using (var stream = new MemoryStream())
            {
                var serializer = new DataContractSerializer(typeof(T));
                serializer.WriteObject(stream, obj);
                stream.Position = 0;
                return (T) serializer.ReadObject(stream);
            }
        }

Create a Licence Key Web Service using WCF

This guide will get you started with web services using wcf.

1. Create a new project in Visual Studio 2010 of type “WCF Service Library”

2. Add these classes (delete the pre-made ones)


[ServiceContract]
    public interface ILicenceKeyService
    {
        [OperationContract]
        ClientKeyResponse GetChartClientKey(ClientKeyRequest composite);
    }
 
    [DataContract]
    public class ClientKeyRequest
    {
        [DataMember]
        public string CompanyName { get; set; }
 
        [DataMember]
        public string ContactName { get; set; }
 
        [DataMember]
        public string ContactTelephone { get; set; }
 
        [DataMember]
        public string ContactEmail { get; set; }
 
        [DataMember]
        public string ClientContactNumber { get; set; }
 
        [DataMember]
        public string OrderTransactionId { get; set; }
 
        [DataMember]
        public string OrderNumber { get; set; }
    }
 
    [DataContract]
    public class ClientKeyResponse
    {
        [DataMember]
        public string Key { get; set; }
    }
 
public class LicenceKeyService : ILicenceKeyService
    {
        public ClientKeyResponse GetChartClientKey(ClientKeyRequest request)
        {
            if (request == null)
            {
                throw new ArgumentNullException();
            }
            if (!Validate(request))
            {
                throw new Exception("nice try");
            }
 
            // do anything else you need here
 
            return new ClientKeyResponse {Key = GenerateKey(request)};
        }
 
        private bool Validate(ClientKeyRequest request)
        {
            // validate the request, ideally checking the transaction id is valid
 
            return true;
        }
 
        private string GenerateKey(ClientKeyRequest request)
        {
            // generate a key, store it in a db and reply all in one transaction
 
            return "";
        }
    }

3. Edit the App.config file and change the http addresses to match your namespaces/class names.

4. Run the project. While its running, start a V2 2010 command prompt and type the following to get the client code needed to connect to the webservice.

    svcutil http://localhost:8732/Design_Time_Addresses/SimpleWcfService/LicenceKeyService/mex?wsdl

This will generate 2 files, the Service class and a config file.

Launch WPF Window from Winforms Host with communication

An example of how to launch a WPF window from a Winforms host and enable intercommunication using the excellent EventAggregator from PRISM.

  1. Create a Winforms application. Add a button and label to the Form1.
  2. Add WPF Custom Control library to the solution. Add a WPF Window.
  3. Reference the WPF project from the Winforms project
  4. add click event handler for your button
  5. edit the winform code behind and make it look like this

private IEventAggregator eventAggregator;

public Form1()
{
    InitializeComponent();
    eventAggregator = new EventAggregator();
    eventAggregator.GetEvent().Subscribe(OnMessageReceived);
}

private void Button1Click(object sender, EventArgs e)
{
    var wpfWindow = new WpfCustomControlLibrary1.WpfWindow1(eventAggregator);
    ElementHost.EnableModelessKeyboardInterop(wpfWindow);
    wpfWindow.Show();
}

private void OnMessageReceived(AppMessagePayload obj)
{
    label1.Text = "Message received [" + DateTime.Now.ToString("HH:mm:ss.fff") + "]" + obj.Message;
}

You will need to reference the WindowsFormsIntegration assembly from the Winforms project as well as the PRISM library Microsoft.Practices.Composite and Microsoft.Practices.Composite.Presentation.

The EventAggregator will allow you to publish or subscribe to events across the winforms/wpf boundaries.

To achieve this I created a separate class library to contain the “Infrastructure” code that you can see below:

public class AppMessageEvent : CompositePresentationEvent { }

public class AppMessagePayload : EventArgs
{
    public AppMessagePayload(string message)
    {
        Message = message;
    }
    public string Message { get; private set; }
}

Forcing binding update on focused element

This has come in very useful on a recent project whereby the View was bound directly to a Model for reasons too verbose to explain here.
I found that a Textbox value was not updating back to the Model if focus remained on that Textbox when the user clicked on a Toolbar Button bound to an ICommand on the parent (which is a ViewModel). Provided the user moved focus BEFORE clicking the ICommand all was well, but if not the underlying modal was not updated. So I used this to update the source just before running the normal ICommand execute code.

public static class ControlHelper
    {
        /// <summary>
        /// Will update the source of the current keyboard focused element
        /// control dependency property provided it matches <see cref="T"/>.
        /// If a <see cref="IValueConverter"/> is attached to binding that
        /// will get fired
        /// </summary>
        /// <typeparam name="T">type of element</typeparam>
        /// <param name="targetProperty">dependency property binding to update</param>
        public static void UpdateFocusedElementBindingSource<T>(DependencyProperty targetProperty)
        {
            if (targetProperty == null) return;
 
            var element = Keyboard.FocusedElement;
            if (!(element is T)) return;
 
            var control = element as Control;
            if (control == null) return;
 
            var expression = control.GetBindingExpression(targetProperty);
            if (expression == null) return;
 
            // update the source
            expression.UpdateSource();       
 
            // move focus
            control.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));     
        }
    }