Microsoft Dynamics AX Support

This blog contains posts by the Microsoft Dynamics AX Support Teams Worldwide

AX for Retail 2012 R2: Adding a Custom User Control to the POS

In the 2012 R2 release of AX for Retail we have added a very powerful extensibility feature for the POS application:  the ability to add a custom user control to the POS.  This article will show you how to easily create a user control and add it to the POS till layout.  Hopefully it will spur ideas for some creative uses.

Step 1:  Creating the Custom Field

Before you can add your custom user control to the till layout it must first be defined in the Custom Fields window in Headquarters.  This is essentially the same process as custom fields for receipts (AX for Retail 2012 R2: Working with Custom Fields for Receipts) and the till layout (AX for Retail 2012: Working with Custom Fields).  Instead of adding a field to an existing control on the till layout, however, this custom field will be a new control altogether.

in Dynamics AX, open the Custom Fields form (Retail > Setup > POS > Profiles > Custom fields) and create a new field of type Custom control.  The Name field is important to remember as it will be the C# class name of the control.  I used MyControl for this example:

2013-02-26 11_31_40-‪Custom fields‬ (‎‪1‬)‎

Similar to the receipt custom field, the Caption text ID is used for the text of the screen layout designer.  Once again, this ID must match a value in the RetailLanguageText table.  Because there is no form for maintaining this table, it must be modified directly in the AOT.  Open a new developer workspace and navigate to Data Dictionary > Tables > RetailLanguageText.  Right-click and select Open.  Create a new record by populating the languageID, Text and textID fields:  “en-us”, “22002”, and “My Custom Control”.

Step 2:  Adding the Custom Control to the Screen Layout

To add the control to an existing till layout, open the Screen layouts window:  Retail > Setup > POS > Screen layouts.  Click on the Designer button for any screen layout ID:

2013-02-26 11_51_18-‪Screen layouts‬ (‎‪1‬)‎

From the Design mode drop-down button select Main layout to bring up the customization toolbar.  On the Hidden Items tab you should see your custom control.  As you can see in my screenshot I haven’t yet created my string in the RetailLanguageText table:

Once you have your string created correctly, you can then drag your custom control onto the form layout it just like any other item:

Resize your control as necessary and press the OK button to save the layout.  After pushing out the changes (N-1090 or A-1090 job) you should be able to see the control in your POS, even though we haven’t yet done anything programmatically.

Step 3:  Creating the Custom Control

Now comes the development part:  creating the custom control and adding it to the POS.  As long as it implements the interface properly, the control can be included in any POS Service and the layout will find it.  The easiest place for this is… (you guessed it) … the Blank Operation.

Fire up an instance of Visual Studio and open the Services solution.  Navigate to the BlankOperations project;  right-click and select Add > New Item:

VisualStudio1

Select User Control (you can find it in the Windows Forms sections) and give it a file name.  The file name isn’t really important, but Visual Studio automatically names the class the same as the file name, so save yourself some future confusion and use the same file name as you named your custom field in headquarters:  MyControl.cs:

NewControl

Your control should automatically open in the designer.  Drag a couple of labels and a button to the control and then to make it stand out, change the Border Style to FixedSingle and the BackColor to a color of your choosing: 

ControlLookAndFeel

Now that we have made the control visually appealing, we need to add some code to identify it as a POS control.  Right-click anywhere on the control and select “View Code”. 

The first thing to do is add a couple of using statements:

using System.ComponentModel.Composition;
using Microsoft.Dynamics.Retail.Pos.Contracts.UI;
  

Then implement the IPosCustomControl interface and add two attributes to your class:

 [Export(typeof(IPosCustomControl))]
 [PartCreationPolicy(CreationPolicy.NonShared)]
    public partial class MyControl : UserControl, IPosCustomControl

If you attempt to build at this point you should get a couple of errors letting you know that you haven’t fully implemented the interface:

The easiest way to take care of this is to right-click on the IPosCustomControl and select Implement Interface > Implement Interface.  This will create two new methods:  TransactionChanged and LoadLayout:

        public void LoadLayout(string layoutId)
        {
            throw new NotImplementedException();
        }

        public void TransactionChanged(Contracts.DataEntity.IPosTransaction transaction)
        {
            throw new NotImplementedException();
        }
  

LoadLayout() is called when the till layout is loaded and is where you would add initialization code for your control if needed.  You can delete the “throw new NotImplementedException()” line in this method since we will not be using it.

The TransactionChanged() method is the main event handler for the control and is called whenever something changes on the transaction object:  an item is added to the transaction, a payment is received, the transaction is concluded, etc.  As in other POS services and triggers, you have full access to the contents of the current transaction in this method.

Once you have implemented the two methods, you should be able to build and deploy the BlankOperations DLL and launch the POS.  Your control should display in the POS and look something like this:

2013-02-26 14_34_17-Microsoft Dynamics AX for Retail POS

 

Step 4:  Adding Logic to the Custom Control

Getting the control to display is one thing; getting it to do something is another.  Here are a few ideas we can try out.

First, if we need to work with the transaction and lines on the transaction, a couple more using statements will be handy:

using LSRetailPosis.Transaction;
using LSRetailPosis.Transaction.Line.SaleItem;
  

Our first line is pretty simple:  just count the actual number of lines on the transaction.  For the second, we will steal the GetTotalQuantity() method the receipts article:

public void TransactionChanged(Contracts.DataEntity.IPosTransaction transaction)
{
    RetailTransaction retailTransaction = transaction as RetailTransaction;

    label1.Text = string.Format("Sale line(s) count : {0}", retailTransaction == null ? 0 : retailTransaction.SaleItems.Count);
    label2.Text = "Total Quantity: " + GetTotalQuantity(retailTransaction);
}
private string GetTotalQuantity(RetailTransaction theTransaction)
{

    try
    {
        decimal qty = 0.0m;
        foreach (SaleLineItem s in theTransaction.SaleItems)
        {
            qty += s.Quantity;
        }
        return qty.ToString();
    }
    catch
    {
        return string.Empty;
    }

}
  

And then to get the button to do something, just add an event handler:

private void button1_Click(object sender, EventArgs e)
{
    MessageBox.Show("Do something here...");
}
  

Hook it all up and you can see that the control is now functional:

 

Next Steps:

With some imagination, you can see that this new feature can be quite powerful:

  • Using a timer control, periodically show information to the user (current snow conditions, latest currency exchange rate, company stock price, total sales for the day)
  • Show the elapsed time for the current transaction; change the color of the control if the transaction takes longer than a certain amount of time
  • Provide a call button so the user can notify a shift supervisor that assistance is needed (see note 1)
  • Show a picture of the most recently scanned item (see note 2)
  • Make a pretty clock (see note 3)

Note 1:  Using a button on the control doesn’t really give you much advantage over a Blank Operation aside from the fact that you have more control over the look and feel and it can exist outside of a button grid.

Note 2:  This is a pretty common request.  Note that I said “most recently scanned” and not “currently highlighted” item.  This is because the control doesn’t have access to the transaction grid – only the transaction object.  Since the transaction object doesn’t actually change when focus changes in the grid, the TransactionChanged() method doesn’t fire.  I have raised this as a request for a future version of this feature.

Note 3:  I’ve included a not-so-pretty clock in the attached sample code.

 

I’m very interested in seeing some of the controls that developers come up with – please drop me a line with some of your examples or if you have any ideas on how to enhance this new functionality.

BlankOperations_UserControl.zip