The component responsible for XHTML renderering in the Sidewinder Viewer provides a set of COM interfaces enabling it to be embedded inside other applications. This tutorial demonstrates how to achieve this in a simple C# project, although the same techniques may be applied to other languages and projects too.
Before you can begin, you will need to install the latest version of the Sidewinder Viewer. Once you have done that, you must import two of our COM libraries into your project using the 'Add Reference' dialog. They are installed by the Sidewinder Viewer to the following locations:
[Program Files]\Common Files\Sidewinder\Renderer\Renderer4.dll
[Program Files]\Common Files\Sidewinder\DOM\DOM2Events.dll
The first of these, the Renderer, provides all of the XHTML rendering functionality. The second component, an implementation of the W3C's DOM Level 2 Events recommendation, facilitates communication between your application, the Renderer and the live document.
The first thing your application must do is instantiate and initialise a copy of the Renderer, storing a pointer to its IRender interface:
public class RenHost : System.Windows.Forms.Form
{
private RendererLib.IRender Renderer;
...
private void RenHost_Load(object sender, System.EventArgs e)
{
this.Renderer = (IRender)new RendererLib.RendererClass();
this.Renderer.Initialise(null);
...
}
...
}
Your application may now customise various other characteristics of the Renderer component, such as setting the handle to its parent window, setting its initial size or instructing it to delegate any navigation requests to your container application. These properties and others are set by dispatching certain events to the Renderer's IEventTarget interface.
A new method along the following lines can simplify this process for you:
private void DispatchRendererEvent(string sType, int nParam1, int nParam2)
{
IRendererEvent evt = (IRendererEvent)new RendererEventClass();
evt.initRendererEvent(sType, false, false, nParam1, nParam2, "");
IEventTarget tgt = (IEventTarget)this.Renderer;
tgt.dispatchEvent((DOMEvent)evt);
}
It is not necessary to worry about what all of the different parameters mean at this point. Simply know that the code above allows you to dispatch a renderer event of type sType, along with some event-specific contextual parameters.
With this method in place, then, the first thing you might want to do is make the Renderer a child of one of your application's windows:
private void RenHost_Load(object sender, System.EventArgs e)
{
this.Renderer = (IRender)new RendererLib.RendererClass();
this.Renderer.Initialise(null);
DispatchRendererEvent("renderer-set-parentwindow",
(int)this.Panel.Handle, 0);
DispatchRendererEvent("renderer-set-windowstyle", 2, 0);
...
}
You should also inform the Renderer of its intial size and position within its parent window, like this:
private void RenHost_Load(object sender, System.EventArgs e)
{
this.Renderer = (IRender)new RendererLib.RendererClass();
this.Renderer.Initialise(null);
DispatchRendererEvent("renderer-set-parentwindow",
(int)this.Panel.Handle, 0);
DispatchRendererEvent("renderer-set-windowstyle", 2, 0);
DispatchRendererEvent("renderer-set-position", 0, 0);
DispatchRendererEvent("renderer-set-dimensions",
this.Panel.ClientRectangle.Width,
this.Panel.ClientRectangle.Height);
...
}
Once these initial window-related properties have been set, you must instruct the Renderer to perform its own window creation:
private void RenHost_Load(object sender, System.EventArgs e)
{
this.Renderer = (IRender)new RendererLib.RendererClass();
this.Renderer.Initialise(null);
DispatchRendererEvent("renderer-set-parentwindow",
(int)this.Panel.Handle, 0);
DispatchRendererEvent("renderer-set-windowstyle", 2, 0);
DispatchRendererEvent("renderer-set-position", 0, 0);
DispatchRendererEvent("renderer-set-dimensions",
this.Panel.ClientRectangle.Width,
this.Panel.ClientRectangle.Height);
this.Renderer.InitialiseWindow();
...
}
The Renderer object is now initialised and able to render XHTML documents. This, in itself, is a two stage process. First, the document must be loaded in one of three ways:
Regardless of the method that you use, the document must be well formed, otherwise the load will fail; malformed documents may only be rendered using the supplementary IRenderHTML interface. After the document has been loaded successfully, it can be rendered by the Render() method. You may also pass a fragment identifier and a base URI to this method if necessary.
So, based on the above, if your application were to contain a browser-style address bar, the button click handler might look something like the following:
private void Button_Click(object sender, System.EventArgs e)
{
int nFragmentIndex = this.Input.Text.IndexOf('#');
Uri uri;
String sFragId;
if(nFragmentIndex != -1)
{
uri = new Uri(this.Input.Text.Substring(0, nFragmentIndex));
sFragId = this.Input.Text.Substring(nFragmentIndex + 1);
}
else
{
uri = new Uri(this.Input.Text);
sFragId = "";
}
String sURL = uri.AbsoluteUri;
String sBase = sURL.Substring(0, sURL.LastIndexOf('/') + 1);
this.Renderer.LoadURI(sURL);
this.Renderer.Render(sFragId, sBase);
}
You can continue to load and render as many documents after this as you wish. All that remains is to ensure that you call the Destroy() method before your application terminates:
protected override void Dispose(bool disposing)
{
if(disposing)
{
this.Renderer.Destroy();
...
}
base.Dispose(disposing);
}
A sample C# form (see screenshot, below), containing code based on the principles outlined in this tutorial, is available from here.