Due to a customers request for a specific feature, I’ve just discovered LiveZilla. It’s a really good and FREE live chat program for your website.
It basically requires putting a small piece of JavaScript into your page wherever you want the Live Chat button to appear. This code can contain “variables” to help identify the person browsing your site and what part of the site they are on.
The problem I had was updating this code. The LiveZilla Server comes with a nifty program to generate this code and initially I started by placing the code at runtime into an ASP.NET Literal Control. This soon became a pain whenever I wanted to update the code and had to manually double-quote all of the Javascript so I could place it in a string variable, replace the variables in the code (allowing for HTML encoding) with the values to identify the user browsing the site and then writing it out to the Literal control.
Another spanner was thrown in the works because the site(s) I was using this on are sold to multiple customers (hosted separately) and each “version” of the site needed to use code specific to the customer. Well not wanting to have to put customer specific code into my pages, I needed a way to populate the Chat buttons easily and dynamically from data retrieved from a database.
What I wanted to achieve was:
- Chat buttons populated from database.
- Ability to use different Chat buttons on different pages
- Each button should populate with customer specific code.
Here’s what I did:-
Create a new ASP.Net Server Control project called “LiveZillaButton”. This creates a project and gives you the following code to get you started (I’m using VS2008):
Imports System Imports System.Collections.Generic Imports System.ComponentModel Imports System.Text Imports System.Web Imports System.Web.UI Imports System.Web.UI.WebControls <DefaultProperty("Text"), ToolboxData("<{0}:ServerControl1 runat=server></{0}:ServerControl1>")> _ Public Class ServerControl1 Inherits WebControl <Bindable(True), Category("Appearance"), DefaultValue(""), Localizable(True)> Property Text() As String Get Dim s As String = CStr(ViewState("Text")) If s Is Nothing Then Return "[" + Me.ID + "]" Else Return s End If End Get Set(ByVal Value As String) ViewState("Text") = Value End Set End Property Protected Overrides Sub RenderContents(ByVal output As HtmlTextWriter) output.Write(Text) End Sub End Class
I replaced the default “Text” property with my own “Tag” property. This property is going to be used to identify the database record that the button should get it’s code from. I’ve altered the attributes so the property appears in it’s own “Livezilla” section in the property grid instead of the “Appearance” section.
<Bindable(True), Category("Livezilla"), DefaultValue("")> _ Property Tag() As String Get Dim s As String = CStr(ViewState("Tag")) Return If(String.IsNullOrEmpty(s), String.Empty, s) End Get Set(ByVal Value As String) ViewState("Tag") = Value End Set End Property
<Bindable(True), Category("Livezilla"), DefaultValue("")> _ Property TrackingCode() As String Get Dim s As String = CStr(ViewState("TrackingCode")) Return If(String.IsNullOrEmpty(s), String.Empty, s) End Get Set(ByVal Value As String) ViewState("TrackingCode") = Value End Set End Property
Public Class LivezillaEventargs Inherits EventArgs Public Sub New(ByVal tag As String, ByVal ButtonContent As String) _tag = tag _buttonContent = ButtonContent End Sub Private _tag As String Public ReadOnly Property Tag() As String Get Return _tag End Get End Property Private _buttonContent As String Public Property ButtonContent() As String Get Return _buttonContent End Get Set(ByVal Value As String) _buttonContent = Value End Set End Property End Class
Back to the main control, I need an Event and also some default HTML that will be used when the none of the controls properties are populated. Lets add the following to our control.
Friend Const EmptyButton = "<div style=""border: thin groove #000080; margin: 0px; padding: 0px; width: 150px; height: 80px""><table style=""width: 100%; height: 100%""><tr><td style=""height: 30px; font-weight: bold; font-family: Arial, Helvetica, sans-serif; text-align: center; color: #000080;"">Livezilla</td></tr><tr><td style=""font-size: 11px; vertical-align: middle; text-align: center; font-family: Arial, Helvetica, sans-serif;"">Populate the TrackingCode property or handle the BeforeRender event</td></tr></table></div>" Public Event BeforeRender(ByVal sender As Object, ByRef e As LivezillaEventargs)
Remember we still have a “RenderContents” Method that has been complaining about it’s lack of a “Text” property since we replaced it with a Tag property. Modify this method so it now contains:-
Protected Overrides Sub RenderContents(ByVal output As HtmlTextWriter) Dim TC As String = TrackingCode Dim EV As New LivezillaEventargs(Tag, TC) RaiseEvent BeforeRender(Me, EV) If String.IsNullOrEmpty(EV.ButtonContent) Then EV.ButtonContent = EmptyButton End If output.Write(EV.ButtonContent) End Sub
This raises our event and allows us to manipulate the HTML before it is output.
The button now is fully functional and you can build the project and add it to the toolbox. However, you may want to make a few more changes first for better design time support.
The control attributes still have their default values so let’s change them to :-
<DefaultEvent("BeforeRender"), DefaultProperty("TrackingCode"), ToolboxData("<{0}:LivezillaButton runat=server></{0}:LivezillaButton>")> _Double clicking the Livezilla button on your web form will now automatically create the BeforeRender Event Handler and dropping the Button onto your page will highlight the TrackingCode property by default. I also renamed the control from it’s default of “ServerControl1”.
Imports System.Web.UI <Assembly: TagPrefix("LiveZillaButton", "LZ")>This gives our control a custom Tag prefix otherwise our button would be created on the web form with the default prefix of cc1. The next part is totally optional. We don’t necessarily want the control to render the button at design time so we need to tell it to do something different when we are working on the design surface. Add a reference to System.Design to the project and then create a new class containing:-
Friend Class LivezillaControlDesigner Inherits System.Web.UI.Design.ControlDesigner Protected Button As LivezillaButton Public Overrides Sub Initialize(ByVal component As System.ComponentModel.IComponent) If TypeOf component Is LivezillaButton Then MyBase.Initialize(component) Button = DirectCast(component, LivezillaButton) End If End Sub Public Overrides Function GetDesignTimeHtml() As String Return If(String.IsNullOrEmpty(Button.TrackingCode), LivezillaButton.EmptyButton, Button.TrackingCode) End Function End Class
This is the designer that will handle our design time HTML. As it stands, it just outputs our standard button HTML but you can modify the GetDesignTimeHtml method to return whatever you want to use instead. I’ll leave this part up to you.
The final step is to tell our button to use our new ControlDesigner so add the following attribute to the LiveZillaButton Class.
Designer(GetType(LivezillaControlDesigner))
- Populate the TrackingCode property if you want a static button with specific markup.
- Populate the Tag property and handle the BeforeRender Event to dynamically change the markup.
e.g Protected Sub LivezillaButton1_BeforeRender(ByVal sender As Object, ByRef e As LiveZillaButton.LivezillaEventargs) Handles LivezillaButton1.BeforeRender If e.Tag = "LoginPage" Then e.ButtonContent = "Our Button Content - Possibly from a database" Else e.ButtonContent = "Our other Button content" End If End Sub