Recording a Web Performance test from a CodedUI test

On a project that’s well supported with tests, it is very common to have a good suite of automated tests. The two most common frameworks for test automation in the .Net stack are CodedUI and Watin. This article will cover utility code that improves recording a Web Performance test from a CodedUI test to automate the initial recording of the performance test. While it is possible to do the same with Watin, there is less control over the recording process, so I won’t cover Watin in this post.

There are two common tasks while going from a CodedUI into a Web Performance:

  • Find the Browser with the recorder.
  • Control the recording process. Often part of the CodedUI is getting to where we want to do the action, and this process isn’t part of the recording phase.

Finding a browser that is ready for recording

Finding a browser that is able to record is just going through the open browsers and look for the recording toolbar and the recording buttons. If we find them, then we have one and we can use it, otherwise just open a new browser and run the test normally.

Some things to note here:

  • Make sure that you wrap all the code that looks for recording controls in compiler directives. If the CodedUI is looking for these controls and can’t find them, it takes a lot longer to run, doing this as part of a build process will just increase the build time by a great amount.
  • While we are looking for things, keep track of the main buttons, Record and Resume, because we may want to click them later on, as part of scoping the recording process.
  • The method that launches the browser takes a Boolean parameter that allows the browser recorder to be paused at the start of the CodedUI test, instead of the default recording behavior.

The code that handles this:


public static class CodedUIExtensions
{
#if !DO_NOT_FIND_WEBRECORD
private static bool _recording;
private static WinButton _recordButton;
private static WinButton _pauseButton;
#endif
public static BrowserWindow Launch(bool pauseRecording = false)
{
return Launch("main.aspx", pauseRecording);
}
public static BrowserWindow Launch(string path, bool pauseRecording = false)
{
#if !DO_NOT_FIND_WEBRECORD
// Try to find an open browser that is recording to do a web performance recording session
try
{
var recordingBrowser = new BrowserWindow();
recordingBrowser.SearchProperties[UITestControl.PropertyNames.Name] = "Blank Page";
recordingBrowser.SearchProperties[UITestControl.PropertyNames.ClassName] = "IEFrame";
recordingBrowser.Find();
var recordWindow = new WinWindow(recordingBrowser);
recordWindow.SearchProperties[WinControl.PropertyNames.ControlName] = "toolStrip1";
recordWindow.Find();
var toolbar = new WinToolBar(recordWindow);
toolbar.SearchProperties[UITestControl.PropertyNames.Name] = "toolStrip1";
toolbar.Find();
_recordButton = new WinButton(toolbar);
_recordButton.SearchProperties[UITestControl.PropertyNames.Name] = "Record";
_recordButton.Find();
_pauseButton = new WinButton(toolbar);
_pauseButton.SearchProperties[UITestControl.PropertyNames.Name] = "Pause";
_pauseButton.Find();
if (pauseRecording)
{
Mouse.Click(_pauseButton);
recordingBrowser.WaitForControlReady();
}
recordingBrowser.NavigateToUrl(new Uri(path));
_recording = true;
return recordingBrowser;
}
catch
{
}
#endif
// A browser with a session ready to record couldn't be found, so open a new one
var browserWindow = BrowserWindow.Launch(path);
browserWindow.WaitForControlReady();
return browserWindow;
}
}

view raw

gistfile1.cs

hosted with ❤ by GitHub

Controlling the recording process

Besides finding the browser, that are 3 common things that we want, as part of controlling the recording process:

  • Be able to pause the recording process.
  • Be able to resume the recording process.
  • Some applications will spawn multiple windows, so at the end of the test an ALT+F4 is sent to the target app. However in the scope of recording a performance test, we want the browser to stay open, so we can do final adjustments or just stop recording and generate the test.

To accomplish this, just add 3 more methods to the utility class (also with compiler directives to improve test run speeds during builds):


public static void PauseRecording()
{
#if !DO_NOT_FIND_WEBRECORD
if (!_recording) return;
Mouse.Click(_pauseButton);
_pauseButton.WaitForControlReady();
#endif
}
public static void ResumeRecording()
{
#if !DO_NOT_FIND_WEBRECORD
if (!_recording) return;
Mouse.Click(_recordButton);
_recordButton.WaitForControlReady();
#endif
}
public static void CloseWindows()
{
#if !DO_NOT_FIND_WEBRECORD
if (!_recording)
{
Keyboard.SendKeys("%{F4}");
}
#else
Keyboard.SendKeys("%{F4}");
#endif
}

view raw

gistfile1.cs

hosted with ❤ by GitHub

Validation in WebForms with Data Annotations

Some very old projects get enough development time so that certain parts of them move forward, but too often this time isn’t enough for a full re-write to modern day technologies.

In most scenarios the persistence layer will move forward before the Web UI. This is because legacy WebForms projects relied on patterns like the Supervising Controller that don’t translate directly to modern implementations like ASP.NET’s MVC. Migrating projects from old legacy patterns to ASP.NET MVC usually starts with the persistence layer because presenters wrap and transform models into what the view needs instead of providing a way to directly bind these; changing the persistence layer into something that can be bound directly, refactoring the presenter first and paving the way to replacing presenters with controllers is usually the way to go.

In a scenario where a legacy persistence layer is left intact and a change from WebForms to ASP.NET MVC is done instead, it usually takes longer to execute due to the fact that Model wrappers need to be written that wrap around the old persistence layer and bind directly to the views, along with the usual view re-writing and refactoring presenters into controllers. These wrappers also add obscurity to the overall solution, so anyone maintaining the solution between the changes will have a hard time with it.

Doing ASP.NET WebForms validation with Data Annotations

ASP.NET WebForms does validation through a series of ASP.NET Validation Server Controls, what they have in common is that they all inherit from BaseValidator. The strategy is to start from this inheritance, expose two additional properties for the name of the property we want to validate and another for the type of the class where this property exists.

/// <summary>
/// Exposes the Property Name that we want to validate against.
/// </summary>
public string PropertyName { get; set; }
        
/// <summary>
/// Exposes the SourceType for Data Annotation lookup that we want to validate against.
/// </summary>
public string SourceType { get; set; }

The BaseValidator class has an abstract method EnsureIsValid that is the main override point for creating our own Validator. By getting the PropertyName and the SourceType you can use reflection and get the Data Annotations, then use these to check for Validation and to properly create and format the Error Message.

/// <summary>
/// Performs the real Validation process, sets the isValid flag on the
/// BaseValidator class.
/// </summary>
/// <returns>If the property if Valid or Not.</returns>
protected override bool EvaluateIsValid()
{
    var objectType = Type.GetType(SourceType, true, true);
    var property = objectType.GetProperty(PropertyName);

    var control = base.FindControl(ControlToValidate) as TextBox;

    if(control == null)
        throw new InvalidOperationException("This implementation can only be used to validate Textbox controls, attempting to validate something else will fail!");

    foreach (var attr in property.GetCustomAttributes(typeof (ValidationAttribute), true)
                                    .OfType<ValidationAttribute>()
                                    .Where(attr => !attr.IsValid(control.Text)))
    {
        // This implementation will break on the first attribute fail and will only return the first error found.
        // I kept the foreach and the where clause to allow for easier transition into an implementation that
        // tracks and displays all the errors found and not just the first one!
        var displayNameAttr = property.GetCustomAttributes(typeof (DisplayNameAttribute), true)
                                        .OfType<DisplayNameAttribute>()
                                        .FirstOrDefault();

        var displayName = displayNameAttr == null ? property.Name : displayNameAttr.DisplayName;
        ErrorMessage = attr.FormatErrorMessage(displayName);
        return false; 
    }

    return true;
}

This is a very naive implementation, it will only work with the TextBox control, explicitly throwing otherwise:

var control = base.FindControl(ControlToValidate) as TextBox;

if(control == null)
    throw new InvalidOperationException("This implementation can only be used to validate Textbox controls, attempting to validate something else will fail!");

And it doesn’t do any proper logging and trapping of the reflection bits in the code, if there’s any problem setting the SourceType and PropertyName, like for example a typo, it just blows up without any exception handling:

var objectType = Type.GetType(SourceType, true, true);
var property = objectType.GetProperty(PropertyName);

Usage examples

To use the DataAnnotationValidator simply add it where you want the validation text to appear like for example:

<asp:Label ID="CardFirstNameTextLabel" runat="server" CssClass="FormLabel" AssociatedControlID="CardFirstNameText">First Name</asp:Label>
<asp:TextBox ID="CardFirstNameText" runat="server" AutoCompleteType="firstname" />

<val:DataAnnotationValidator ID="FirstNameValidator" runat="server"
    ControlToValidate="CardFirstNameText" Text="**" PropertyName="FirstName" SourceType="InnerWorkings.Model.CardDetails, InnerWorkings.Model" />

<span class="Notes">(as it appears on the card)</span>

You can also use the built in ASP.NET ValidationSummary control to display the validation errors summary:

<asp:ValidationSummary runat="server" ID="vSumAll" DisplayMode="BulletList" CssClass="validation-errors" HeaderText="<span>Oops! Please fix the following errors:</span>" />

The full source Code for the DataAnnotationValidator

namespace ValidationWithDataAnnotations
{
    using System;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Web.UI.WebControls;

    /// <summary>
    /// Reasonable wrapper for performing Validation using Data Annotations.
    /// With the inclusion of EntityFramework in the solution, all model elements are properly
    /// Data Annotated, so the logical path is to perform UI validation using the same set
    /// of annotations used by EF.
    /// The Validator still requires the setting of PropertyName and SourceType, this is
    /// where this class could be improved, as both these things can be looked up instead of
    /// just set.
    /// </summary>
    public class DataAnnotationValidator : BaseValidator
    {
        /// <summary>
        /// Exposes the Property Name that we want to validate against.
        /// </summary>
        public string PropertyName { get; set; }
        
        /// <summary>
        /// Exposes the SourceType for Data Annotation lookup that we want to validate against.
        /// </summary>
        public string SourceType { get; set; }

        /// <summary>
        /// Performs the real Validation process, sets the isValid flag on the
        /// BaseValidator class.
        /// </summary>
        /// <returns>If the property if Valid or Not.</returns>
        protected override bool EvaluateIsValid()
        {
            var objectType = Type.GetType(SourceType, true, true);
            var property = objectType.GetProperty(PropertyName);

            var control = base.FindControl(ControlToValidate) as TextBox;

            if(control == null)
                throw new InvalidOperationException("This implementation can only be used to validate Textbox controls, attempting to validate something else will fail!");

            foreach (var attr in property.GetCustomAttributes(typeof (ValidationAttribute), true)
                                         .OfType<ValidationAttribute>()
                                         .Where(attr => !attr.IsValid(control.Text)))
            {
                // This implementation will break on the first attribute fail and will only return the first error found.
                // I kept the foreach and the where clause to allow for easier transition into an implementation that
                // tracks and displays all the errors found and not just the first one!
                var displayNameAttr = property.GetCustomAttributes(typeof (DisplayNameAttribute), true)
                                              .OfType<DisplayNameAttribute>()
                                              .FirstOrDefault();

                var displayName = displayNameAttr == null ? property.Name : displayNameAttr.DisplayName;
                ErrorMessage = attr.FormatErrorMessage(displayName);
                return false; 
            }

            return true;
        }
    }
}

Formatting email HTML with T4 templates

There’s several techniques available to a .Net developer to properly format HTML outside web pages. One of them is actually using an HTML view render engine like Razor to format it.

The one I find the cleaner and easier to maintain is using T4 templates. Since this is a post about T4, I suggest that you take a loot at my T4 Templates page before moving on, to get used to the code reading.

The full demo project can be downloaded here

Project Structure

blog17

The simple demo project is composed of two T4 Runtime Templates:

  • EmailTemplate defines and transforms the default HTML template.
  • The BodyTemplate defines and transforms the HTML that composes the “Body” of the email.

The entry point for this template transformation is on the MailExtensions.cs file and written as extensions to MailMessage. The Program.cs file just contains enough code to setup an email message and call the template entry point

class Program
{
    static void Main(string[] args)
    {
        var mail = new MailMessage
        {
            From = new MailAddress("me@mycompany.com", "Me AndMe"),
            Subject = "Me poking You",
            Body = string.Empty
        };

        mail.To.Add("someemail@somecompany.com");

        var template = new BodyTemplate
                            {
                                FirstName = "You",
                                LastName = "AndYou"
                            };

        mail.CreateHtmlBody(template);

        using (var client = new SmtpClient())
        {
            client.SendAsync(mail, null);
        }
    }
}

The email is just setup to be delivered to a static folder in the app.config file

<system.net>
    <mailSettings>
        <smtp deliveryMethod="SpecifiedPickupDirectory">
            <specifiedPickupDirectory pickupDirectoryLocation="D:\Mail" />
        </smtp>
    </mailSettings>
</system.net>

T4 Runtime Templates

To create a T4 Runtime Template all you have to do is Add New Item, then select the Runtime Text Template Item.

blog18

What this template does is generate a C# class that you can use at Run-Time to transform and generate it’s output. You can either pass parameters to these templates by using their built in T4 Parameter Directive or simply by extending the generated partial class. I prefer extending the generated class as it makes it more unit testable when required, so I used this approach in the demo code.

This type of templates ignores some of the T4 Directives, however some of them are put to good use to trick the editor into proper syntax highlighting. I use the T4 Output Directive to make tangible syntax highlight my HTML, for some reason at the time of this post, tangible didn’t highlight it with “.html” so “.xml” had to do the trick.

<#@ output extension=".xml" #>

The EmailTemplate

The template itself is very simple, containing very simple HTML. This should contain the default style template for your emails, with a proper Header, Footer and common sections in all your emails.

<#@ template language="C#" #>
<#@ output extension=".xml" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<html>
  <body>
    <h1>This is a header</h1>
    <div>
		<#= GetBodyText() #>
    </div>
    <h1>This is a footer</h1>
</body>
</html>

The generated class partial definition contains the method used by the template to generate the Body. This method supports both a Body string and a Body object that will be verified as being another valid template. So if it get’s another template it will attempt to render it, while if it get’s a string it will just dump it.

public partial class EmailTemplate
{
    public string Body { get; set; }

    private object _bodyTemplate;
    public object BodyTemplate
    {
        get { return _bodyTemplate; }
        set
        {
            // Get the type and the TransformText method using reflection
            var type = value.GetType();
            var method = type.GetMethod("TransformText");

            // Reflection signature checks
            if (method == null) throw new ArgumentException("BodyTemplate needs to be a RunTimeTemplate with a TransformText method");
            if (method.ReturnType != typeof(string) || method.GetParameters().Any()) throw new ArgumentException("Wrong TransformText signature on the BodyTemplate");

            // If everything is ok, assign the value
            _bodyTemplate = value;
        }
    }

    private string GetBodyText()
    {
        var result = string.Empty;

        // Use the BodyTemplate if available
        if(BodyTemplate != null)
        {
            dynamic castTemplate = BodyTemplate;
            result = castTemplate.TransformText();
        }
        // Otherwise use the Body string if it's not null or empty
        else if(!string.IsNullOrEmpty(Body))
        {
            result = Body;
        }

        return result;
    }
}

The BodyTemplate

The BodyTemplate is a very simple template just to show the linear transformation of both templates and the inclusion of email specific fields for email customization.

<#@ template language="C#" #>
<#@ output extension=".xml" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<p>Hi there <#= FirstName #> <#= LastName #></p>
<p>This is an Example of a Body.</p>

It’s extension only contains properties so that we can configure the email Body.

public partial class BodyTemplate
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

The Entry Point – MailExtensions

The wrapper methods that manage the main template transformations are in the MailExtensions.cs file and are written as extension methods, one for a using a Body string and another one for using a Body template. This demo however doesn’t make any use of the Body string, it only uses a Body template.

public static class MailExtensions
{
    public static void CreateHtmlBody(this MailMessage message, string body)
    {
        var mailTemplate = new EmailTemplate { Body = body };
        var html = AlternateView.CreateAlternateViewFromString(mailTemplate.TransformText(), Encoding.UTF8, "text/html");
        message.AlternateViews.Add(html);
    }

    public static void CreateHtmlBody(this MailMessage message, object template)
    {
        var mailTemplate = new EmailTemplate { BodyTemplate = template };
        var html = AlternateView.CreateAlternateViewFromString(mailTemplate.TransformText(), Encoding.UTF8, "text/html");
        message.AlternateViews.Add(html);
    }
}

Async integration with SalesForce Leads web service

The SalesForce Leads web service is used mainly to register new leads from other applications, for example a trial page where a user registers for a trial and a Lead in SalesForce is created to be followed by commercial teams.

The integration itself is very simple and straightforward, this post is about doing it in an async way, and also presents a solution for integrations with several different Models.

The web service is called through a normal HttpWebRequest object, but it’s setup is done in 3 stages:

  • The creation of the HttpWebRequest with the initial configuration.
  • Writing the RequestStream from a string – This is the service’s parameters that will be sent in the HTTP POST.
  • Submiting the request.

The RequestStream writing and the request submission are written as async ready methods (they can be awaited on) but the HttpWebRequest creation isn’t as this is of very fast execution.

Calling the service through the HttpWebRequest in an async manner

The integration is written in a static class. The entry point is the static method SubmitRequest, it takes as a parameter an object that is basically a Model object that will have it’s metadata parsed for Param attributes to get the SalesForce common parameters.

public static async Task SubmitRequest(object info)
{
    var request = CreateSalesForceRequest();
    var message = GetSalesForceParams(info) + "&" + GetSalesForceStaticParams();

    await request.WriteRequestStream(message);

    try
    {
        await request.SubmitSalesForce();
    }
    catch (Exception)
    {
        // This doesn't seem to do anything as the servlet allways returns HTTP 200.OK.
        // Use the debug email param and debug param on the servlet Parameter list instead.
        Trace.TraceError("Error registering lead in salesforce. Encoded message string was: {0}", message);
    }
}

Besides the GetSalesForceParams, we can see the 3 stages described earlier in the following methods:

private static HttpWebRequest CreateSalesForceRequest()
{
    var request = (HttpWebRequest)WebRequest.Create(ConfigurationManager.AppSettings["SalesforceWebToLeadUrl"]);
    request.Timeout = 60000;
    request.ContentType = "application/x-www-form-urlencoded";
    request.Method = WebRequestMethods.Http.Post;
    request.KeepAlive = true;
    request.ProtocolVersion = HttpVersion.Version11;
    request.UserAgent = "";

    return request;
}

This creates the HttpWebRequest properly configured to call the Leads web service. The specific web service URL is being retrieve from the configuration file.

private static Task WriteRequestStream(this WebRequest request, string message)
{
    return Task.Factory.FromAsync<Stream>(request.BeginGetRequestStream, request.EndGetRequestStream, null)
        .ContinueWith(t =>
                            {
                                var stream = t.Result;
                                var data = Encoding.ASCII.GetBytes(message);
                                Task.Factory.FromAsync(stream.BeginWrite, stream.EndWrite, data, 0, data.Length,
                                                        null, TaskCreationOptions.AttachedToParent)
                                    .ContinueWith(x => stream.Close());
                            });
}

This is the first of the async ready methods. It is written as an extension to the WebRequest object. It returns a Task so that it can be awaited and uses the useful FromAsync method in the TPL that wraps a pair of begin and end methods.

private static Task SubmitSalesForce(this WebRequest request)
{
    return Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null)
        .ContinueWith(t =>
                            {
                                var response = t.Result;
                                if (response != null)
                                    response.Close();
                            });
}

The last stage of the request submission is the actual SubmitSalesForce method. It is written as an extension to the WebRequest object.

Formatting the service’s parameters

The request string is composed by 2 different blocks. The first one will compose the static parameters with the Leads group, your company OID in SalesForce and additional things that you might want to setup. These are saved in a static Dictionary

private static readonly Dictionary<string, string> StaticParams = new Dictionary<string, string>
                                                                        {
                                                                            {"oid", "MYOID"},
                                                                            {"lead_source", "Web Trial"},
                                                                            {"debug", "1"},
                                                                            {
                                                                                "debugEmail",
                                                                                "me@mycompany.com"
                                                                            }
                                                                        };

And then transformed by the simple method

private static string GetSalesForceStaticParams()
{
    return string.Join("&", StaticParams.Select(p => p.Key + "=" + HttpUtility.UrlEncode(p.Value)));
}

The tricky part comes from the non-static parameters. In my scenario I have several projects using this integration with SalesForce, and these projects use different types of Models and Model architectures. To cope with these differences I used an attribute decoration pattern, much like ADO.NET does validation, so that Models could be decorated specifying certain properties as SalesForce parameters. An extra degree of complexity is added because I have to support EntityFramework Database first modelling, so property decoration is done through the MetadataType attribute instead of having metadata at the properties themselves, an example of an extension of an EntityFramework Database first model object is given below:

[MetadataType(typeof(LandingPageUserMetadata))]
public partial class LandingPageUser
{
}

public class LandingPageUserMetadata
{
    [Required]
    [Display(Name = "First Name")]
    [SalesForceParam(Type = SalesForceParamType.FirstName)]
    public string FirstName { get; set; }

    [Required]
    [Display(Name = "Last Name")]
    [SalesForceParam(Type = SalesForceParamType.LastName)]
    public string LastName { get; set; }

    [Required]
    [Display(Name = "Email account")]
    [EmailValidation(ErrorMessage = "This has to be a valid email address.")]
    [SalesForceParam(Type = SalesForceParamType.Email)]
    public string EmailAddress { get; set; }
}

To support this type of decoration, additional code needs to be written to check for the MetadataType attribute and then parse it’s configured Type. Then the mapping between the actual metadata and the properties needs to be in place so that the values are retrieved from the Model object and not the object used to define the metadata.

The code that takes an object and parses it’s metadata or metadatatype attribute and returns a request message string is:

public static string GetSalesForceParams(object info)
{
    var sfProperties = info.GetType()
        .GetProperties()
        .Where(p => p.GetCustomAttributes(typeof(SalesForceParamAttribute), true).Any())
        .ToArray();

    if (!sfProperties.Any())
    {
        var metadataTypes = info.GetType()
            .GetCustomAttributes(typeof(MetadataTypeAttribute), true)
            .OfType<MetadataTypeAttribute>()
            .ToArray();

        var metadata = metadataTypes.FirstOrDefault();

        if (metadata != null)
        {
            sfProperties = metadata.MetadataClassType
                .GetProperties()
                .Where(p => p.GetCustomAttributes(typeof(SalesForceParamAttribute), true).Any())
                .ToArray();
        }
    }

    var sfParams =
        sfProperties
            .Where(p => info.GetType().GetProperty(p.Name).GetValue(info) != null)
            .Select(
                p =>
                ((SalesForceParamAttribute)p.GetCustomAttributes(typeof(SalesForceParamAttribute), false).First()).SalesForceParam +
                "=" +
                HttpUtility.UrlEncode(info.GetType().GetProperty(p.Name).GetValue(info).ToString()));

    return string.Join("&", sfParams);
}

The attribute definition is simple and straightforward:

namespace IW.Web.Common.SalesForce
{
    using System;

    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
    public class SalesForceParamAttribute : Attribute
    {
        public SalesForceParamType Type { get; set; }

        public string SalesForceParam
        {
            get
            {
                switch (Type)
                {
                    case SalesForceParamType.FirstName:
                        return "first_name";
                    case SalesForceParamType.LastName:
                        return "last_name";
                    case SalesForceParamType.Email:
                        return "email";
                    case SalesForceParamType.Company:
                        return "company";
                    case SalesForceParamType.Phone:
                        return "phone";
                    default:
                        return string.Empty;
                }
            }
        }
    }

    public enum SalesForceParamType
    {
        FirstName,
        LastName,
        Email,
        Company,
        Phone
    }
}

Calling the Async methods from an ASP.NET MVC 4 controller

Whenever you’re calling async methods, that are awaiting method calls, you need to make sure that the controller awaits on them, so that they can be executed to the end within the lifetime scope of the controller, without destroying the thread running the controller.

ASP.NET MVC 2 introduced AsyncController, but then the way we had to use to write async methods was too quirky. With the async framework that was changed and now writing an AsyncController is very clean:

public class HomeController : AsyncController
{
    public ActionResult Index()
    {
        return View(new LandingPageUser());
    }

    [HttpPost]
    public async Task<ActionResult> Index(LandingPageUser model)
    {
        // Check if the model is valid and try to Save it to the Database
        if (ModelState.IsValid && model.Save(ModelState))
        {
            // DO YOUR WORK
            // (...)

            // Integrate with SalesForce and send in the request
            if (Boolean.Parse(ConfigurationManager.AppSettings["EnableSalesforceRegistrations"]))
                await SalesForceExtensions.SubmitRequest(model);

            return View("Success");
        }

        return View(model);
    }
}

Entity Framework Code-First in a “semi-production” context

Lately I used Entity Framework Code First in a “semi-production” context, not in an application, but for managing Load Tests. The scenario was I had a Load Test, based on a unit test (not a web test) and I had to manage a pool of users so that a single user wasn’t used at the same time by 2 instances of the unit test. Because the Load Test ran in a multi-agent scenario, this had to be accessible by all the agents running the unit test, thus a Database approach.

Preparing the Database in SQL Server

Entity Framework Code First will create and manage the Database for you. But in this context, I will be accessing the Database through a connection string using a SQL user, because not all the machines running agents are in the same domain, so going through a trusted connection isn’t an option. The SQL user will have access to the Database for the Load Test, but won’t have access to the master Database.

The first thing you need to do is to create the Database, because using the EF connection string would result in an authorization error when creating the Database.

After creating the Database setup the SQL user so that it can connect to it, read, write and manage the schema.

The Entity Framework Model and Context

The very first thing you need to do is add the Entity Framework NuGet package to your solution, this can be done either by going through the NuGet package manager:

blog12

Or just by opening the package manager console and typing in Install-Package EntityFramework

blog13

After that, create your model and your context. For our scenario we just needed an object User that has a UserName key, a static password that’s not going to the Database, a boolean InUse and a DateTime timestamp ReleasedOn so that we can ask for users that have been released by the unit test for the longest time.

namespace EFCodeFirstStart.Model
{
    using System;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;

    public class User
    {
        [Key]
        public string UserName { get; set; }

        [NotMapped]
        public string Password { get { return "myStaticPassword"; } }

        public bool InUse { get; set; }

        public DateTime ReleasedOn { get; set; }
    }
}

The context is really simple (we’ll get back to it later on in the post). You need to inherit from DbContext and you are implementing the default constructor to call the DbContext constructor that takes a connection string name so that you can point to the Database previously created.

namespace EFCodeFirstStart.Model
{
    using System.Data.Entity;

    public class LoadTestDataContext : DbContext
    {
        public LoadTestDataContext() : base("name=EFConnectionString") { }

        public DbSet<User> Users { get; set; }
   }
}

Creating the Database from the Model – Code First approach

Make sure that the connection string that you’re using on the DbContext contructor is configured in the app.config or web.config of your application:

<connectionStrings>
  <add name="EFConnectionString" providerName="System.Data.SqlClient" connectionString="Server=localhost; Database=LoadTestData; User=efcodefirst; Password=mypwd1234" />
</connectionStrings>

The first step is enabling Code First migrations for your application, this must be done for every project type with the following command Enable-Migrations:

blog14

When this step is executed a new folder Migrations and a Configuration.cs file will be created. The Configuration.cs file is one of the points where control is given to the developer in the Code First approach.

namespace EFCodeFirstStart.Migrations
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Migrations;
    using System.Linq;

    internal sealed class Configuration : DbMigrationsConfiguration<EFCodeFirstStart.Model.LoadTestDataContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
        }

        protected override void Seed(EFCodeFirstStart.Model.LoadTestDataContext context)
        {
            //  This method will be called after migrating to the latest version.

            //  You can use the DbSet<T>.AddOrUpdate() helper extension method 
            //  to avoid creating duplicate seed data. E.g.
            //
            //    context.People.AddOrUpdate(
            //      p => p.FullName,
            //      new Person { FullName = "Andrew Peters" },
            //      new Person { FullName = "Brice Lambson" },
            //      new Person { FullName = "Rowan Miller" }
            //    );
            //
        }
    }
}

You then need to add migrations every time we want to snapshot the Database schema, so let’s do one now and call it InitialSetup by running the command Add-Migration InitialSetup:

blog15

This will create another file on the Migrations folder with a timestamp followed by _InitialSetup (the name you gave to the Migration):

namespace EFCodeFirstStart.Migrations
{
    using System;
    using System.Data.Entity.Migrations;
    
    public partial class InitialSetup : DbMigration
    {
        public override void Up()
        {
            CreateTable(
                "dbo.Users",
                c => new
                    {
                        UserName = c.String(nullable: false, maxLength: 128),
                        InUse = c.Boolean(nullable: false),
                        ReleasedOn = c.DateTime(nullable: false),
                    })
                .PrimaryKey(t => t.UserName);
            
        }
        
        public override void Down()
        {
            DropTable("dbo.Users");
        }
    }
}

In a normal application scenario we would be done, as Entity Framework will handle the Database updates on every run, extra commands are only needed if we need to revert or do other extra work on the migrations. However, because I had to run this from a LoadTest project, the Database update has to be done manually, by calling Update-Database on the package manager console

blog16

Where did the EDMX go?

If you’re like me, you do a lot of code generation based on the ADO.NET EDMX model. So far Code First looked really nice and I was liking it a lot, but without the EDMX I don’t have a good source for writing templates against.

The folks at the Entity Framework team created the ability to Save the EDMX file in the framework, so we just need to call that every time we are changing the model (calling Update-Database). This is done by overriding the OnModelCreating method:

namespace EFCodeFirstStart.Model
{
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;
    using System.Text;
    using System.Xml;

    public class LoadTestDataContext : DbContext
    {
        public LoadTestDataContext() : base("name=EFConnectionString") { }

        public DbSet<User> Users { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            var provider = new DbProviderInfo("System.Data.SqlClient", "2008");
            var model = modelBuilder.Build(provider);

            var writer = new XmlTextWriter(@"D:\TmpEdmx\my.edmx", Encoding.UTF8);
            EdmxWriter.WriteEdmx(model, writer);
        }
    }
}

Code First thoughts

So far I liked using Code First, seemed smooth, flexible and lean, making model and schema change iterations a breeze. With the added support to generate the EDMX everything is in place to do code generation like we used to do with Model First approaches.

Playing around with the Ribbon and RichTextBox–4 of 4: Adding Hyperlink support to the RichTextBox

For my work, one of the things I had to support was Hyperlinks. I could do this the traditional way, where I would create a button in the Ribbon

blog10

And follow it up with a MessageDialogBox asking the user additional Hyperlink details

blog11

However, because my hyperlinks will always list the URI and never a user typed name, detecting hyperlinks as the user types and creating them is a lot better then specifically forcing the user to press a button and fill in the details.

Adding Hyperlink detection to the RichTextBox

I found a very good article on MSDN about this, written by Prajakta Joshi that I modified to suit my needs. It all starts with detecting the preceding word in a FlowDocument Paragraph object

private static string GetPreceedingWordInParagraph(TextPointer position, out TextPointer wordStartPosition)
{
    wordStartPosition = null;
    var word = String.Empty;
    var paragraph = position.Paragraph;

    if (paragraph != null)
    {
        var navigator = position;
        while (navigator != null && navigator.CompareTo(paragraph.ContentStart) > 0)
        {
            var runText = navigator.GetTextInRun(LogicalDirection.Backward);

            if (runText.Contains(" "))
            {
                var index = runText.LastIndexOf(" ", StringComparison.Ordinal);
                word = runText.Substring(index + 1, runText.Length - index - 1) + word;
                wordStartPosition = navigator.GetPositionAtOffset(-1 * (runText.Length - index - 1));
                break;
            }

            wordStartPosition = navigator;
            word = runText + word;
            navigator = navigator.GetNextContextPosition(LogicalDirection.Backward);
        }
    }

    return word;
}

I then hooked an Event Handler on the KeyDown Event of the RichTextBox on the constructor of my UserControl

public RibbonRichTextBox()
{
    InitializeComponent();
    _richTextBox.KeyDown += RibbonRichTextBoxKeyDown;
}

With the following implementation

private static void RibbonRichTextBoxKeyDown(object sender, KeyEventArgs e)
{
    var rtb = (RichTextBox) sender;
    if (e.Key != Key.Space && e.Key != Key.Return) return;

    var caretPosition = rtb.Selection.Start;
    TextPointer wordStartPosition;

    var word = GetPreceedingWordInParagraph(caretPosition, out wordStartPosition);
    if (!Uri.IsWellFormedUriString(word, UriKind.Absolute)) return;

    if (wordStartPosition == null || caretPosition == null) return;

    var tpStart = wordStartPosition.GetPositionAtOffset(0, LogicalDirection.Backward);
    var tpEnd = caretPosition.GetPositionAtOffset(0, LogicalDirection.Forward);

    if(tpStart != null && tpEnd != null)
    {
        var link = new Hyperlink(tpStart, tpEnd)
                        {
                            NavigateUri = new Uri(word)
                        };

        link.MouseLeftButtonDown += FollowHyperlink;
    }
}

Notice that I’m using the Uri class to check if the word is an URI or not, this could be changed for a Regex or other forms of checking this out

if (!Uri.IsWellFormedUriString(word, UriKind.Absolute)) return;

Adding the ability to Ctrl+Click Hyperlinks and open them in IE

If you notice the RibbonRichTextBoxKeyDown imlpementation, there’s a line there, after creating the Hyperlink, where I add an event handler for the MouseLeftButtonDown Event

link.MouseLeftButtonDown += FollowHyperlink;

In the Handler implementation, I check for Ctrl (left or right) is down, then just start IE with the URI present on the Link and make sure the event’s Handled is set to true to stop the routing

private static void FollowHyperlink(object sender, MouseButtonEventArgs e)
{
    if (!Keyboard.IsKeyDown(Key.LeftCtrl) && !Keyboard.IsKeyDown(Key.RightCtrl)) return;

    var link = (Hyperlink) sender;
    Process.Start(new ProcessStartInfo(link.NavigateUri.ToString()));
    e.Handled = true;
}

The Full Series

The full solution can be downloaded from here.

This is the third article in the series Playing around with the Ribbon and RichTextBox.

Playing around with the Ribbon and RichTextBox–3 of 4: Creating an Insert Picture button in the Ribbon

For the work I was doing I had to design and create special buttons that extended the EditingCommands Class like special text formatting for special text blocks, an Insert Image command and an insert Video command. The special text formatting was very specific to my work and the Video command is a lot more tricky to implement and the implementation is bound to a transformation that is performed later where I convert the RichTextBox’s document XAML to XML.

So I choose to demonstrate the Insert Picture command.

blog9

The button is a normal RibbonButton that’s defined inside a RibbonControlGroup inside a RibbonGroup

<ribbon:RibbonGroup Header="Media" x:Name="_mediaHeader">
    <ribbon:RibbonControlGroup>
        <ribbon:RibbonButton x:Name="_btnImage" Label="Image" LargeImageSource="/PlayingWithRibbon;component/Images/picture.png" Click="ButtonImageClick">
            <ribbon:RibbonButton.ControlSizeDefinition>
                <ribbon:RibbonControlSizeDefinition ImageSize="Large" />
            </ribbon:RibbonButton.ControlSizeDefinition>
        </ribbon:RibbonButton>
    </ribbon:RibbonControlGroup>
</ribbon:RibbonGroup>

Once the button is clicked an OpenFileDialog is shown for the user to select the image, since in my work I can only support JPG and PNG file formats, these are the ones that are being filtered

private static Image SelectImage()
{
    var dlg = new OpenFileDialog
    {
        Filter = "Image Files|*.png;*.jpg;*.gif"
    };

    var result = dlg.ShowDialog();
    if (result.Value)
    {
        var bitmap = new BitmapImage(new Uri(dlg.FileName));
        return new Image
        {
            Source = bitmap,
            Height = bitmap.Height,
            Width = bitmap.Width
        };
    }

    return null;
}

The Click Event Handler implementation, that inserts the actual picture in the Document

private void ButtonImageClick(object sender, RoutedEventArgs e)
{
    var image = SelectImage();
    if (image == null) return;

    var tp = _richTextBox.CaretPosition.GetInsertionPosition(LogicalDirection.Forward);
    new InlineUIContainer(image, tp);
}

Extra work could be done to create text flow around the image or other fancy tricks that the System.Windows.Document namespace offers, but since my final output is XML, none of those were going to be supported anyways.

The Full Series

The full solution can be downloaded from here.

This is the third article in the series Playing around with the Ribbon and RichTextBox.

Playing around with the Ribbon and RichTextBox–2 of 4: Creating a good User Experience with Reveal

The Ribbon provides for an overall good User Experience, however it takes a big chunk of screen space. The Ribbon design doesn’t allow for it to be minimalist, and if it was it wouldn’t be the same Ribbon we are used to from all those Microsoft applications.

This is where Reveal from Bag of Tricks comes in handy. By placing the Ribbon inside a Reveal and controlling it’s appearance we can make good use of screen space in scenarios where the User’s screen is already filled with other things, or even more Ribbon’s!

The Reveal that I use in my solution has added features to it besides the one from BoT, as described in a previous post.

Binding the Reveal’s IsExpanded

What I found that worked best, in terms of User Experience, and after responding to some user feedback, was to hook the Reveal to the Focus handlers on the top Grid inside the UserControl. I hooked it to IsReadOnly on the RichTextBox and control that property directly on the Focus hooks.

First I declared the reveal around the Ribbon declaration

<PlayingWithRibbon:Reveal VerticalReveal="FromTopToBottom"
                    HorizontalReveal="None"
                    Duration="200"
                    IsExpanded="{Binding ElementName=_richTextBox, Path=IsReadOnly, Converter={StaticResource ResourceKey=InverseBooleanConverter}}"
                    Stretch="HorizontalAndVertical"
                    Grid.Row="0"
                    >

    <ribbon:Ribbon Name="_ribbon">

    (...)

    </ribbon:Ribbon>
</PlayingWithRibbon:Reveal>

Because I want the Reveal.IsExpanded to be true when RichTextBox.IsReadOnly is false, I had to put in a simple InverseBooleanConverter that’s declared on the code behind of the RibbonRichTextBox.

/// <summary>
/// Inverse Boolean Converter - Inverts the value of a boolean bind.
/// </summary>
[ValueConversion(typeof(bool), typeof(bool))]
public class InverseBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (targetType != typeof(bool))
            throw new InvalidOperationException("The target must be a boolean");

        return !(bool)value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (targetType != typeof(bool))
            throw new InvalidOperationException("The target must be a boolean");

        return !(bool)value;
    }
}
<UserControl.Resources>
    <PlayingWithRibbon:InverseBooleanConverter x:Key="InverseBooleanConverter" />
</UserControl.Resources>

Then I went and setup the event handlers for the GotFocus and LostFocus on the top Grid of the UserControl

<Grid GotFocus="GridGotFocus" LostFocus="GridLostFocus">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition />
    </Grid.RowDefinitions>

    (...)

</Grid>

With a very simple implementation on the code behind file

private void GridGotFocus(object sender, RoutedEventArgs e)
{
    _richTextBox.IsReadOnly = false;
}

private void GridLostFocus(object sender, RoutedEventArgs e)
{
    _richTextBox.IsReadOnly = true;
}

In the end what you get is the Reveal to show the Ribbon on Focus and closing it when losing Focus. This makes a very smooth and cool effect while keeping the screen space to a minimum.

blog7

The Full Series

The full solution can be downloaded from here.

This is the second article in the series Playing around with the Ribbon and RichTextBox.

Playing around with the Ribbon and RichTextBox–1 of 4: Putting it all together, the Ribbon and the RichTextBox

The Ribbon for WPF is a very cool control, with a lot of customization options. In terms of User Experience it’s something everyone is used to these days from all the Microsoft Tools that have been using it, including Office since 2007 and all the way up to 2013.

To show off the Ribbon, I present a use of it with just a few commands, most of them are out-of-the box from the RichTextBox and one of them (Insert Picture) is custom.

The application itself is very simple, it’s a set of 2 controls (RichTextBox + Ribbon: RibbonRichTextBox) one on top of the other. I chose to place two of them, so that the focus changing hiding and showing of the Ribbon could be easily demonstrated.

blog7

The solution has a very flat structure, the main functionality is inside the RibbonRichTextBox UserControl. The MainWindow is very simple and just hosts the two RibbonRichTextBoxes:

<Window x:Class="PlayingWithRibbon.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:PlayingWithRibbon="clr-namespace:PlayingWithRibbon"
        Title="MainWindow" Height="620" Width="600">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <PlayingWithRibbon:RibbonRichTextBox Grid.Row="0" Margin="10" />
        <PlayingWithRibbon:RibbonRichTextBox Grid.Row="1" Margin="10" />
    </Grid>

</Window>

blog8

Besides the Reveal, which I will talk about later in the series, there’s the Images Folder, with all the images required by the several controls inside the Ribbon.

The Ribbon

Using the Ribbon in .Net 4.0 or 4.5 just requires a reference to the assembly RibbonControlsLibrary.dll. In a very simplified description (it can do a lot more): The Ribbon control can host RibbonTab’s that can host RibbonControlGroups that can host all sorts of RibbonControls. The various controls in the Ribbon are mostly bound to the RichTextBox EditingCommands part of the System.Windows.Documents namespace.

<ribbon:Ribbon Name="_ribbon">
    <ribbon:RibbonTab Header="Home">
        <ribbon:RibbonGroup Header="Edit">
            <ribbon:RibbonButton x:Name="_btnPaste" Label="Paste" LargeImageSource="/PlayingWithRibbon;component/Images/Paste32.png"
                            Command="{x:Static ApplicationCommands.Paste}" CommandTarget="{Binding ElementName=_richTextBox}">
                <ribbon:RibbonButton.ControlSizeDefinition>
                    <ribbon:RibbonControlSizeDefinition ImageSize="Large" />
                </ribbon:RibbonButton.ControlSizeDefinition>
            </ribbon:RibbonButton>
            <ribbon:RibbonButton x:Name="_btnCut" Label="Cut" SmallImageSource="/PlayingWithRibbon;component/Images/Cut16.png"
                            Command="{x:Static ApplicationCommands.Cut}" CommandTarget="{Binding ElementName=_richTextBox}">
                <ribbon:RibbonButton.ControlSizeDefinition>
                    <ribbon:RibbonControlSizeDefinition ImageSize="Small" />
                </ribbon:RibbonButton.ControlSizeDefinition>
            </ribbon:RibbonButton>
            <ribbon:RibbonButton x:Name="_btnCopy" Label="Copy" SmallImageSource="/PlayingWithRibbon;component/Images/Copy16.png"
                            Command="{x:Static ApplicationCommands.Copy}" CommandTarget="{Binding ElementName=_richTextBox}">
                <ribbon:RibbonButton.ControlSizeDefinition>
                    <ribbon:RibbonControlSizeDefinition ImageSize="Small" />
                </ribbon:RibbonButton.ControlSizeDefinition>
            </ribbon:RibbonButton>
            <ribbon:RibbonButton x:Name="_btnClear" Label="Clear" SmallImageSource="/PlayingWithRibbon;component/Images/Delete16.png"
                            Command="{x:Static EditingCommands.Delete}" CommandTarget="{Binding ElementName=_richTextBox}">
                <ribbon:RibbonButton.ControlSizeDefinition>
                    <ribbon:RibbonControlSizeDefinition ImageSize="Small" />
                </ribbon:RibbonButton.ControlSizeDefinition>
            </ribbon:RibbonButton>
            <ribbon:RibbonButton x:Name="_btnUndo" Label="Undo" SmallImageSource="/PlayingWithRibbon;component/Images/Undo16.png"
                            Command="{x:Static ApplicationCommands.Undo}" CommandTarget="{Binding ElementName=_richTextBox}">
                <ribbon:RibbonButton.ControlSizeDefinition>
                    <ribbon:RibbonControlSizeDefinition ImageSize="Small" />
                </ribbon:RibbonButton.ControlSizeDefinition>
            </ribbon:RibbonButton>
            <ribbon:RibbonButton x:Name="_bntRedo" Label="Redo" SmallImageSource="/PlayingWithRibbon;component/Images/Redo16.png"
                            Command="{x:Static ApplicationCommands.Redo}" CommandTarget="{Binding ElementName=_richTextBox}">
                <ribbon:RibbonButton.ControlSizeDefinition>
                    <ribbon:RibbonControlSizeDefinition ImageSize="Small" />
                </ribbon:RibbonButton.ControlSizeDefinition>
            </ribbon:RibbonButton>
            <ribbon:RibbonButton x:Name="_btnSelectAll" Label="Select All"
                            Command="{x:Static ApplicationCommands.SelectAll}" CommandTarget="{Binding ElementName=_richTextBox}"/>
        </ribbon:RibbonGroup>
        <ribbon:RibbonGroup Header="Font">
            <ribbon:RibbonControlGroup>
                <ribbon:RibbonToggleButton x:Name="_btnBold" 
                                    SmallImageSource="/PlayingWithRibbon;component/Images/Bold16.png" 
                                    Command="{x:Static EditingCommands.ToggleBold}" CommandTarget="{Binding ElementName=_richTextBox}">
                    <ribbon:RibbonToggleButton.ControlSizeDefinition>
                        <ribbon:RibbonControlSizeDefinition ImageSize="Small" IsLabelVisible="False" />
                    </ribbon:RibbonToggleButton.ControlSizeDefinition>
                </ribbon:RibbonToggleButton>
                <ribbon:RibbonToggleButton x:Name="_btnItalic" SmallImageSource="/PlayingWithRibbon;component/Images/Italic16.png"                                               
                                    Command="{x:Static EditingCommands.ToggleItalic}" CommandTarget="{Binding ElementName=_richTextBox}">
                    <ribbon:RibbonToggleButton.ControlSizeDefinition>
                        <ribbon:RibbonControlSizeDefinition ImageSize="Small" IsLabelVisible="False" />
                    </ribbon:RibbonToggleButton.ControlSizeDefinition>
                </ribbon:RibbonToggleButton>
                <ribbon:RibbonToggleButton x:Name="_btnUnderline" SmallImageSource="/PlayingWithRibbon;component/Images/Underline16.png"
                                    Command="{x:Static EditingCommands.ToggleUnderline}" CommandTarget="{Binding ElementName=_richTextBox}">
                    <ribbon:RibbonToggleButton.ControlSizeDefinition>
                        <ribbon:RibbonControlSizeDefinition ImageSize="Small" IsLabelVisible="False" />
                    </ribbon:RibbonToggleButton.ControlSizeDefinition>
                </ribbon:RibbonToggleButton>
            </ribbon:RibbonControlGroup>
        </ribbon:RibbonGroup>
        <ribbon:RibbonGroup Header="Paragraph">
            <ribbon:RibbonControlGroup>
                <ribbon:RibbonRadioButton x:Name="_btnBullets" Label="" SmallImageSource="/PlayingWithRibbon;component/Images/Bullets16.png"
                                    Command="{x:Static EditingCommands.ToggleBullets}" CommandTarget="{Binding ElementName=_richTextBox}">
d                                <ribbon:RibbonRadioButton.ControlSizeDefinition>
                        <ribbon:RibbonControlSizeDefinition ImageSize="Small" IsLabelVisible="False" />
                    </ribbon:RibbonRadioButton.ControlSizeDefinition>
                </ribbon:RibbonRadioButton>
            </ribbon:RibbonControlGroup>
        </ribbon:RibbonGroup>
        <ribbon:RibbonGroup Header="Media" x:Name="_mediaHeader">
            <ribbon:RibbonControlGroup>
                <ribbon:RibbonButton x:Name="_btnImage" Label="Image" LargeImageSource="/PlayingWithRibbon;component/Images/picture.png" Click="ButtonImageClick">
                    <ribbon:RibbonButton.ControlSizeDefinition>
                        <ribbon:RibbonControlSizeDefinition ImageSize="Large" />
                    </ribbon:RibbonButton.ControlSizeDefinition>
                </ribbon:RibbonButton>
            </ribbon:RibbonControlGroup>
        </ribbon:RibbonGroup>
    </ribbon:RibbonTab>
</ribbon:Ribbon>

The RichTextBox

Connected with the Ribbon is a RichTextBox control. The control is simple, just has a Resource to force the Paragraph Margin to be 0 and is hooking the event SelectionChanged so that we can properly update the Ribbon’s ToggleButtons whenever we change the selection on the RichTextBox.

<RichTextBox x:Name="_richTextBox"
                Grid.Row="1"
                Height="200"
                BorderBrush="#3D5261"
                BorderThickness="2"
                IsReadOnly="True"
                SelectionChanged="RichTextBoxSelectionChanged">
    <RichTextBox.Resources>
        <Style TargetType="{x:Type Paragraph}">
            <Setter Property="Margin" Value="0"/>
        </Style>
    </RichTextBox.Resources>
</RichTextBox>

Updating ToggleButton state with SelectionChanged

Making sure that the ToggleButton’s in the Ribbon have their state updated with the current selection starts with the SelectionChanged Event Handler.

private void RichTextBoxSelectionChanged(object sender, RoutedEventArgs e)
{
    UpdateVisualState();
}

private void UpdateVisualState()
{
    UpdateToggleButtonState();
    UpdateSelectionListType();
}

This is then divided into two groups, the ToggleButton CheckedState and the ListType selection. For the ItemCheckedState we handle it like this:

private void UpdateToggleButtonState()
{
    UpdateItemCheckedState(_btnBold, TextElement.FontWeightProperty, FontWeights.Bold);
    UpdateItemCheckedState(_btnItalic, TextElement.FontStyleProperty, FontStyles.Italic);
    UpdateItemCheckedState(_btnUnderline, Inline.TextDecorationsProperty, TextDecorations.Underline);
}

private void UpdateItemCheckedState(ToggleButton button, DependencyProperty formattingProperty, object expectedValue)
{
    var currentValue = _richTextBox.Selection.GetPropertyValue(formattingProperty);
    button.IsChecked = (currentValue != DependencyProperty.UnsetValue) && (currentValue != null && currentValue.Equals(expectedValue));
}

While the ListType is handled like this:

private void UpdateSelectionListType()
{
    var startParagraph = _richTextBox.Selection.Start.Paragraph;
    var endParagraph = _richTextBox.Selection.End.Paragraph;

    if (startParagraph != null &&
        endParagraph != null &&
        (startParagraph.Parent is ListItem)
        && (endParagraph.Parent is ListItem) &&
        ReferenceEquals(((ListItem)startParagraph.Parent).List, ((ListItem)endParagraph.Parent).List))
    {
        var targetList = (startParagraph.Parent as ListItem).List;
        if (targetList == null) return;

        var markerStyle = targetList.MarkerStyle;

        switch (markerStyle)
        {
            case TextMarkerStyle.Disc:
                _btnBullets.IsChecked = true;
                break;
        }
    }
    else
    {
        _btnBullets.IsChecked = false;
    }
}

The Full Series

The full solution can be downloaded from here.

This is the first article in the series Playing around with the Ribbon and RichTextBox.

Glyphs that can be Outlined in WPF

Most modern day applications use glyphs these days. A glyph in developer lingo is a monochromatic icon. In technologies like WPF that use render engines that can easily work with vectors, these glyphs tend to be in the form of vectors, so that UI designers and developers can use them in any form of scale without destroying any of the looks of the glyph.

While using glyphs, one of the things I wanted to do was bind some of them to boolean properties and have the glyph in it’s full colour when it was true, and revert back to an outlined form when it was false.

The example application has 2 glyphs and a CheckBox, both glyphs Outlined property are bound to the CheckBox’s IsChecked property, so that we can go from this state

blog5

To this state

blog6

The glyphs

The glyphs in this example were made in Adobe Illustrator, then imported into blend and the corresponding Path’s generated. They were then inserted into a Viewbox to allow scaling while retaining Blend’s absolute margin values for alignment. In the end what we have is a WPF vector glyph.

bell

<l:BaseGlyph x:Class="GlyphOutline.Bell"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
            xmlns:l="clr-namespace:GlyphOutline"
            mc:Ignorable="d" 
            d:DesignHeight="200" d:DesignWidth="200">

    <Viewbox Stretch="Fill">
        <Canvas x:Name="Icon" Height="64" Width="64">
            <Path Data="F1M32,6C34.205,6,36,7.797,36,10C36,12.203,34.205,14,32,14C29.795,14,28,12.203,28,10C28,7.797,29.795,6,32,6 M53,32C53,21.5,47.217,15.563,41.719,12.266C41.889,11.535,42,10.781,42,10C42,4.477,37.523,0,32,0C26.477,0,22,4.477,22,10C22,10.781,22.111,11.535,22.281,12.266C16.783,15.563,11,21.5,11,32C11,52,4,40,4,56L60,56C60,40,53,52,53,32" Height="56" Canvas.Left="0" Stretch="Fill" Canvas.Top="0" Width="64"/>
            <Path Data="F1M32,64C35.723,64,38.824,61.445,39.717,58L24.283,58C25.176,61.445,28.277,64,32,64" Height="6" Canvas.Left="21.783" Stretch="Fill" Canvas.Top="58" Width="18.434"/>
        </Canvas>
    </Viewbox>

</l:BaseGlyph>

calculator

<l:BaseGlyph x:Class="GlyphOutline.Calculator"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:l="clr-namespace:GlyphOutline"
            mc:Ignorable="d" 
            d:DesignHeight="200" d:DesignWidth="200">

    <Viewbox Stretch="Fill">
        <Canvas x:Name="Icon" Height="64" Width="64">
            <Path Data="F1M48,16C48,16.547,47.555,17,47,17L17,17C16.453,17,16,16.547,16,16L16,9C16,8.445,16.453,8,17,8L47,8C47.555,8,48,8.445,48,9z M44,31.5C42.07,31.5,40.5,29.938,40.5,28C40.5,26.07,42.07,24.5,44,24.5C45.937,24.5,47.5,26.07,47.5,28C47.5,29.938,45.937,31.5,44,31.5 M44,43.5C42.07,43.5,40.5,41.934,40.5,40C40.5,38.066,42.07,36.5,44,36.5C45.937,36.5,47.5,38.066,47.5,40C47.5,41.934,45.937,43.5,44,43.5 M44,55.5C42.07,55.5,40.5,53.934,40.5,52C40.5,50.066,42.07,48.5,44,48.5C45.937,48.5,47.5,50.066,47.5,52C47.5,53.934,45.937,55.5,44,55.5 M32,31.5C30.07,31.5,28.5,29.938,28.5,28C28.5,26.07,30.07,24.5,32,24.5C33.937,24.5,35.5,26.07,35.5,28C35.5,29.938,33.937,31.5,32,31.5 M32,43.5C30.07,43.5,28.5,41.934,28.5,40C28.5,38.066,30.07,36.5,32,36.5C33.937,36.5,35.5,38.066,35.5,40C35.5,41.934,33.937,43.5,32,43.5 M32,55.5C30.07,55.5,28.5,53.934,28.5,52C28.5,50.066,30.07,48.5,32,48.5C33.937,48.5,35.5,50.066,35.5,52C35.5,53.934,33.937,55.5,32,55.5 M20,31.5C18.07,31.5,16.5,29.938,16.5,28C16.5,26.07,18.07,24.5,20,24.5C21.937,24.5,23.5,26.07,23.5,28C23.5,29.938,21.937,31.5,20,31.5 M20,43.5C18.07,43.5,16.5,41.934,16.5,40C16.5,38.066,18.07,36.5,20,36.5C21.937,36.5,23.5,38.066,23.5,40C23.5,41.934,21.937,43.5,20,43.5 M20,55.5C18.07,55.5,16.5,53.934,16.5,52C16.5,50.066,18.07,48.5,20,48.5C21.937,48.5,23.5,50.066,23.5,52C23.5,53.934,21.937,55.5,20,55.5 M49,0L15,0C11.148,0,8,3.148,8,7L8,57C8,60.852,11.148,64,15,64L49,64C52.852,64,56,60.852,56,57L56,7C56,3.148,52.852,0,49,0" Height="64" Canvas.Left="9" Stretch="Fill" Canvas.Top="0" Width="48"/>

        </Canvas>
    </Viewbox>

</l:BaseGlyph>

The MainWindow

The layout of the main window is simple, it’s a stackpanel nested inside a Grid for aligning the glyphs and the CheckBox and a Viewbox to scale the CheckBox to a nice size.

<Window x:Class="GlyphOutline.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:GlyphOutline="clr-namespace:GlyphOutline"
        Title="MainWindow" Height="140" Width="150">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        
        <StackPanel Grid.Row="0"
                    Orientation="Horizontal"
                    VerticalAlignment="Center"
                    HorizontalAlignment="Center">

            <GlyphOutline:Bell Height="40"
                               Width="40"
                               Outlined="{Binding ElementName=OutlineCheck, Path=IsChecked}" />
            <GlyphOutline:Calculator Height="40"
                                     Width="40"
                                     Margin="20 0 0 0"
                                     Outlined="{Binding ElementName=OutlineCheck, Path=IsChecked}" />
        </StackPanel>
        
        <Viewbox Grid.Row="1"
                 Height="40"
                 Width="40"
                 HorizontalAlignment="Center"
                 VerticalAlignment="Center">

            <CheckBox Name="OutlineCheck" />
        </Viewbox>
    </Grid>

</Window>

The Outlining

To implement the Outline feature I created a custom ContentControl that I called the “BaseGlyph”. This control hosts the Outlined property and it’s implementation.

First there’s the Outline property implementation with a callback defined to handle the conversion of styles on the paths when the property is either true or false.

public static readonly DependencyProperty OutlinedProperty = DependencyProperty.Register(
    "Outlined",
    typeof(Boolean),
    typeof(BaseGlyph),
    new UIPropertyMetadata(
        false, // default value for this DP
        OnOutlinedChanged)); // callback on change
                

private static void OnOutlinedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var caller = (BaseGlyph)d;

    if ((bool)e.NewValue)
    {
        foreach (var item in d.GetVisualDescendents().OfType<Path>())
            item.Style = (Style)caller.FindResource("OutlinePath");
    }
    else
    {
        foreach (var item in d.GetVisualDescendents().OfType<Path>())
            item.Style = (Style)caller.FindResource(typeof(Path));
    }
}

public Boolean Outlined
{
    get { return (Boolean)GetValue(OutlinedProperty); }
    set { SetValue(OutlinedProperty, value); }
}

There’s a bit of code on the constructor to create the ResourceDictionary that needs to be present to transform the Paths in the glyph in Shapes with thickness.

public BaseGlyph()
{
    // Build the Resource Dictionary
    Resources = new ResourceDictionary();

    var binding = new Binding();
    var style = new Style();

    // Ancestor Foreground Binding,
    binding.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(BaseGlyph), 1);
    binding.Path = new PropertyPath(ForegroundProperty);

    style.TargetType = typeof(Path);
    style.Setters.Add(new Setter(Shape.FillProperty, binding));

    var transparentBrush = new SolidColorBrush(Colors.White) {Opacity = 0};
    var outline = new Style {TargetType = typeof (Path)};

    outline.Setters.Add(new Setter(Shape.StrokeThicknessProperty, 2d));
    outline.Setters.Add(new Setter(Shape.StrokeProperty, binding));
    outline.Setters.Add(new Setter(Shape.FillProperty, transparentBrush));

    Resources.Add(typeof(Path), style);
    Resources.Add("OutlinePath", outline);

    // Register event handlers
    Loaded += BaseIconLoaded;
}

To support the callback method in the Outlined property I used some Bag-of-Tricks visual helpers and isolated them in the static class VisualHelper

namespace GlyphOutline
{
    #region Using Declarations

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows;
    using System.Windows.Media;

    #endregion

    public static class VisualHelper
    {
        public static IEnumerable<DependencyObject> GetVisualDescendents(this DependencyObject source)
        {
            return source
                .GetVisualChildren()
                .SelectRecursive(element => element.GetVisualChildren());
        }

        public static IEnumerable<DependencyObject> GetVisualChildren(this DependencyObject source)
        {
            var count = VisualTreeHelper.GetChildrenCount(source);

            for (var i = 0; i < count; i++)
                yield return VisualTreeHelper.GetChild(source, i);
        }

        public static IEnumerable<TSource> SelectRecursive<TSource>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TSource>> recursiveSelector)
        {
            var stack = new Stack<IEnumerator<TSource>>();
            stack.Push(source.GetEnumerator());

            try
            {
                while (stack.Any())
                {
                    if (stack.Peek().MoveNext())
                    {
                        var current = stack.Peek().Current;
                        yield return current;
                        stack.Push(recursiveSelector(current).GetEnumerator());
                    }
                    else
                    {
                        stack.Pop().Dispose();
                    }
                }
            }
            finally
            {
                while (stack.Any())
                {
                    stack.Pop().Dispose();
                }
            }
        }

    }
}

The full source of BaseGlyph is listed below

namespace GlyphOutline
{
    #region Using Declarations

    using System;
    using System.Linq;
    using System.Windows.Controls;
    using System.Windows;
    using System.Windows.Media;
    using System.Windows.Shapes;
    using System.Windows.Data;

    #endregion

    public class BaseGlyph : ContentControl
    {
        
        #region Dependency Properties

        public static readonly DependencyProperty OutlinedProperty = DependencyProperty.Register(
            "Outlined",
            typeof(Boolean),
            typeof(BaseGlyph),
            new UIPropertyMetadata(
                false, // default value for this DP
                OnOutlinedChanged)); // callback on change
                

        private static void OnOutlinedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var caller = (BaseGlyph)d;

            if ((bool)e.NewValue)
            {
                foreach (var item in d.GetVisualDescendents().OfType<Path>())
                    item.Style = (Style)caller.FindResource("OutlinePath");
            }
            else
            {
                foreach (var item in d.GetVisualDescendents().OfType<Path>())
                    item.Style = (Style)caller.FindResource(typeof(Path));
            }
        }

        public Boolean Outlined
        {
            get { return (Boolean)GetValue(OutlinedProperty); }
            set { SetValue(OutlinedProperty, value); }
        }

        #endregion

        #region Constructors

        public BaseGlyph()
        {
            // Build the Resource Dictionary
            Resources = new ResourceDictionary();

            var binding = new Binding();
            var style = new Style();

            // Ancestor Foreground Binding,
            binding.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(BaseGlyph), 1);
            binding.Path = new PropertyPath(ForegroundProperty);

            style.TargetType = typeof(Path);
            style.Setters.Add(new Setter(Shape.FillProperty, binding));

            var transparentBrush = new SolidColorBrush(Colors.White) {Opacity = 0};
            var outline = new Style {TargetType = typeof (Path)};

            outline.Setters.Add(new Setter(Shape.StrokeThicknessProperty, 2d));
            outline.Setters.Add(new Setter(Shape.StrokeProperty, binding));
            outline.Setters.Add(new Setter(Shape.FillProperty, transparentBrush));

            Resources.Add(typeof(Path), style);
            Resources.Add("OutlinePath", outline);

            // Register event handlers
            Loaded += BaseIconLoaded;
        }

        #endregion

        #region Event Handlers

        private void BaseIconLoaded(object sender, RoutedEventArgs e)
        {
            // if it's Outlined (set in XAML) need to raise the event at the end of the Load
            // to actually load it as Outlined
            if (Outlined)
                OnOutlinedChanged(this, new DependencyPropertyChangedEventArgs(OutlinedProperty, false, true));
        }

        #endregion

    }
}

The full project can be downloaded here.