About this article
Written by: | Imar Spaanjaars |
Posted: | 7/29/2010 10:03 PM |
Page views: | 7237 |
Rate this article
About the author
Imar Spaanjaars is the owner of De Vier Koeden, a company specializing in consultancy and development on the Microsoft .NET platform and Dynamicweb.
Interested in custom development or consultancy on Dynamicweb or .NET? Then contact De Vier Koeden through the Contact page.
If you want to find out more about Imar Spaanjaars, check out his About page on this web site or check out his personal website.
Follow Imar on Twitter if you want to be notified of new articles in this Dynamicweb series.
Extending the Ribbon Interface for Ecommerce Orders with Custom Functionality
For quite some time I had an enhancement request in mind for the Order details page in the Dynamicweb backend. What I wanted was the ability to add a tab to the Order details page on the fly with custom buttons on it. I had an extensible base class in mind with a overridable method such as ExecuteCustomAction which would appear on this tab automatically. Based on the presence of a class inheriting this base class, the Custom Actions tab could appear and disappear automatically as well.
The reason I wanted this is that it's quite common to execute some custom code for a specific order driven by a user invokable action. For example, you may want to resubmit your order to a backend warehouse system that processes it. Or you may want to send the customer another e-mail with details about the order. So, today, I finally took the time to resubmit my enhancement request to Dynamicweb (I had mentioned it before in a more informal way). Within minutes I got a reply. Turns out: you can already do this, and it's pretty simple too.
Ribbon Extensibility
The secret to the implementation is in the Ribbon Extensibility. As you may be aware, the Ribbon is now pretty much anywhere in the Dynamicweb interface. The Ribbon does not only look cool: it's also extensible. Some time ago I got a copy of the document Dynamicweb Ribbon Extensibility.pdf. Back then I read it, and played around with it a bit, extending some of the tabs in the standard Page dialog and added some custom functionality. What I didn't realize then is that it's the key to implementing custom actions in the Order pages as well.
In order to execute the custom actions through one or more controls on the Ribbon for the Order details page, you need to do the following:
- Create a class that inherits RibbonBarAddIn
- In its Load method, create one or more controls, add them to the Ribbon and hook up some event handlers
- When the controls are activated (for example, a button gets clicked) execute whatever code you need to accomplish your task.
What's really cool about this implementation of the Ribbon Extensibility is that the Ribbon exposes a DataContext property that gives you access to the object the user is working on: an Order in my case. After discovering this (with the help of Nicolai in an e-mail), the rest is a walk in the park.
To help you understand what I am talking about, take a look at this screen shot of a typical Order page in Dynamicweb:
Notice the new Add-ins tab near the standard Order tab on the Ribbon? When you activate the tab, you see a new button appear:
Figure 2
This button was added there by my own custom code as I'll show you in a bit. When clicked, you can run client or server side code (or both) and at the server access the Order instance that is associated with the page the user is currently viewing. I assigned one of the default images to the button (an address book) but you can also supply your own image if you want to provide a different icon.
Once the button is clicked, some code retrieves the order, creates and sends an e-mail message and then confirms the action to the user (using a cheesy JavaScript alert window in my case, but you could go fancy and show a PopUpWindow which is another part of the Ribbon Extensibility package).
Now that you know how it works, let's look at some code that accomplishes this.
First, I added a new class to my Custom Solution Project and then added the following code:
using System; using Dynamicweb.Controls; using Dynamicweb.Controls.Extensibility; using Dynamicweb.eCommerce.Orders; using Dynamicweb.Extensibility; namespace Dynamicweb.Samples.Lib.RibbonExtensions { [AddInName("SendCustomCustomerEmailRibbonTab")] [AddInTarget(RibbonBarAddInTarget.eCom.OrderEdit)] public class SendCustomCustomerEmail : RibbonBarAddIn { public SendCustomCustomerEmail(RibbonBar ribbon) : base(ribbon) { } public override void Load() { RibbonBarGroup ribbonBarGroup = base.CreateDefaultContainer(); ribbonBarGroup.Name = "E-mail"; RibbonBarButton saveButton = new RibbonBarButton(); saveButton.Click += saveButton_Click; saveButton.EnableServerClick = true; saveButton.Text = "Send Message"; saveButton.Image = Controls.Icons.Icon.Type.Address_book; saveButton.Size = Controls.Icons.Icon.Size.Large; ribbonBarGroup.AddItem(saveButton); } private void saveButton_Click(object sender, EventArgs e) { // TODO Implementation here } } }
There are a few things worth noting in this code. First, the class needs to inherit RibbonBarAddIn, the base class for all RibbonBar add-ins. I added two attributes to the class: One to identify my add-in using the AddInName attribute, the other to tell Dynamicweb where I want the add-in to appear: in my case: when editing an order, using RibbonBarAddInTarget.eCom.OrderEdit. If you browse the RibbonBarAddInTarget class in IntelliSense, you'll see lots of other targets as well, giving you great control as to where your add-in must appear and how it should behave.
Next, in the Load method I create a RibbonBarGroup and call it E-mail (as you can see in Figure 2). I then create a new RibbonBarButton, assign some properties such as an ID, a text, and an image. I also assign a server side click handler which is fired at the server when the button is clicked (its client side counter part is OnClientClick, in-line with how many standard ASP.NET controls operate). If you want to enable server side clicks, you must also set EnableServerClick to true as it's turned off by default. Finally, the code adds the button to the RibbonBarGroup so it eventually ends up on the Ribbon in the Order User Interface, shown in Figure 1.
The final action is implementing the server side Click handler. In my example, I added the following code:
private void saveButton_Click(object sender, EventArgs e) { Order order = Ribbon.DataContext.DataSource as Order; string message; if (order != null) { string emailAddress = order.CustomerEmail; if (!string.IsNullOrEmpty(emailAddress)) { // Implementation here; send message. message = string.Format("E-mail for order {0} was sent successfully.", order.ID); } else { message = string.Format("Couldn\'t send e-mail for order {0} " + "because the e-mail address is missing.", order.ID); } } else { message = "Couldn\\'t send message because the order is missing."; } Page.ClientScript.RegisterStartupScript( GetType(), "ClickHandler", String.Format( "<script type=\"text/javascript\">alert('{0}');</script>", message)); }
Most of this code is pretty standard .NET code. Once I have a reference to the Order, I can do pretty much anything I want: call a web service to update a backend system with order information, call into a Track and Trace system to enquire about the order status, send an e-mail message and so on.
The only thing that's slightly worth explaining here is how I get access to the order. The base class RibbonBarAddIn class has a Ribbon property that returns the RibbonBar for the current page. This Ribbon in turn has a DataContext property which exposes a DataSource property of type object. In case of editing an Order in eCommerce, this DataSource object is actually an Order, so I can cast it to one using the as keyword. You can do similar stuff for other types such as a Page instance when editing a page.
At the end of the code, I register a JavaScript block that pops up an alert message indicating success or failure. This is just an example, and other options exist as well. For example, you could make use of the new PopUpWindow class to show a fancy dialog (based on a separate ASPX page) to display a more informative and rich interface.
Extending the Ribbon bar like this is just the tip of the iceberg. You can extend a whole lot of other Ribbon bars with custom functionality. Be sure to check out the documentation I linked to earlier to learn about more extensibility points.
Downloads
You can download the source for the RibbonBarAddIn here.