Clone our Wealth-Lab 8 Extension Demo project on GitHub to get a head start in developing your own Extensions!

Wealth-Lab Client Extension API

This document details the API for building Client Extensions for Wealth-Lab 8. A Client Extension lets you install one or more menu items into the WL8 Extensions menu, and the menu items can be assigned to an event handler that you define. The event handler typically uses the other features of the API to show a child window in WL8.

Client Extensions are implemented by creating derived classes of the following two base classes:

  • WL8ExtensionBase - one time initialization and integrating Help System content (cross platform, located in WealthLab.Core)
  • WL8ClientExtensionBase - adding items to the Extension menu, creating child windows, adding Preference pages (targets Windows WPF, located in WealthLab.WPF)

Build Environment

You can create a WL8 Client Extension in a .NET development tool such as Visual Studio 2022. Create a class library project that targets .NET8, then reference the WealthLab.WPF library DLL that you'll find in the WL8 installation folder.

Note: If you are using Visual Studio 2022, it will need to be updated to at least version 17.8.6 to use .NET8.

Your WL8 Client Extension will be a class in this library that descends from WL8ClientExtensionBase, which is defined in the WealthLab.WPF library, in the WealthLab.WPF namespace. After you implement and build your library, simply copy the resulting assembly DLL into the WL8 installation folder. The next time WL8 starts up, it will discover your WL8 Client Extension, making it available in appropriate locations of the WL8 user interface.

Visual Studio 2022 Build Environment

Accessing the Host (WL8) Environment

The IHost interface allows your extension to access information about the user's WealthLab environment. For example, the location of the user data folder, or obtaining a list of DataSets defined by the user. At any point in your extension's code base, you can access an instance of the IHost interface using the singleton class WLHost and its Instance property. Example:

//get user data folder
string folder = WLHost.Instance.DataFolder;

The WL8ExtensionBase Class

WL8ExtensionBase, which is defined in WealthLab.Core, is a base class you can inherit from. WL8 instantiates classes derived from WL8ExtensionBase upon startup. It has an Initialize method that you can override to perform one-time initialization required by your Client Extension.

To leverage this functionality, create a class derived from WL8ExtensionBase and override its Initialize method. WL8 will call this once upon startup. The other required override is the Name property which you should implement to return the name of your Client Extension.

Integrating with the Help System

You can add new pages of content into the WL8 Help System that contain documentation for your Client Extension. This is best done in the WL8ExtensionBase Initialize method.

Call the method HelpManager.InsertPage, passing a string that describes how your page fits into the Help System contents. The string consists of a set of page names separated by backslashes which describes the hierarchy of how page fits into the Help.

If you integrate with the Help System, you should typically put your pages under the "Extensions" help page, so this would be the first page name in your string. The next page should be a top level page that describes your Client Extension. It should typically use the same string as your ChildWindow Token. If you provide more than one ChildWindow you can insert multiple help pages. You can add more detailed pages by placing them underneath.

Note: You can override the HelpToken property in your ChildWindow if you need the Help Page to be different from the ChildWindow Token.

For example, assuming our Client Extension is named "MyExtension", the calls to InsertPage might look like this:

HelpManager.InsertPage('Extensions\MyExtension);
HelpManager.InsertPage('Extensions\MyExtension\SomeDetails');
HelpManager.InsertPage('Extensions\MyExtension\MoreDetails');

Each entry that you create in this manner should have an accompanying page of content that is installed into the WL8 "Help" folder as part of your Client Extension's installer. These content pages should have the same file name as the final page name in your contents string, with the ".md" extension. This stands for Markdown, and is the formatting language that WL8 uses for its Help System. Using Markdown, you can easily write your formatted help pages for inclusion in WL8 Help.

The WL8ClientExtensionBase Class

WL8ClientExtensionBase, which is defined in WealthLab.WPF, is a base class that allows your Client Extension to add menu items and child windows to a WL8 Main Window. Create a class in your project that derives from WL8ClientExtensionBase, and override the following properties and methods.

Name

public abstract string Name

Override the Name property to return a descriptive name for your Client Extension. This should be the same Name as you returned in your WL8ExtensionBase derived class.

Adding Menu Items to WL8

GetMenuItems

public virtual List<MenuItem> GetMenuItems

Override the GetMenuItems method to return a list of WPF MenuItem instances that will be added to WL8's "Extensions" menu. You can create these MenuItem instances by hand, or use the helper method below.

CreateExtensionMenuItem

public MenuItem CreateExtensionMenuItem(string caption, ImageSource glyph, RoutedEventHandler reh, bool reversableImage = false)

Call this helper method to create a WPF MenuItem that can be added to the list of MenuItem instances in the implementation of GetMenuItems above. The text of the menu item is specified in the caption parameter, and its image in the glyph parameter. The reh parameter should contain a RoutedEventHandler instance that points to the method that should execute when the user clicks the menu item. Typically this will spawn a new child window as described below.

By default, WL8 will not invert the menu item's glyph image when operating in a dark theme. To disable this behavior, and cause WL8 to invert the image in a dark theme, pass true in the reversableImage parameter.

Interacting with the Parent Main Window

The menu items added above are within the context of a WL8 Main Window. Since WL8 supports multiple main windows, the framework needs a way to allow your extension to identity and interact with the specific MainWindow that currently has the context. The Client Extension framework uses the IWLClientHost interface to provide this hook into the Main Window.

MyClientHost

public IWLClientHost MyClientHost

Returns an instance of the IWLClientHost interface that allows your Client Extension to interact with the Main Window that is hosting it. The interface provides several useful properties and methods, the most important being ShowExtensionChildWindow which lets you spawn a child window (that you define) in WL8 when the user clicks your Client Extension's menu item.

Child Windows

Your Client Extension can spawn a new child window within WL8 when the user clicks your menu item. Call the ShowExtensionChildWindow method of the MyClientHost property to spawn the window. You need to pass an instance of a UserControl derived from the ChildWindow base class. Consult the ChildWindow class reference for information on how to design a child window for WL8.

Adding Preference Pages

public virtual List<TabPage> PreferencePages

Override this property to add one or more new tab pages to the WL8 Preferences tool. Return a list of TabPage instances. TabPage is a custom class defined in WealthLab.WPF and derived from UserControl. See the TagPage reference for more information about this class.

Adding a Child Window from a WL8 Workspace

public virtual ChildWindow GetChildWindow(string token)

Users can use Workspaces in WL8 to save and then later restore the state of their Main Window(s) and all child windows contained therein. Your Client Extension Child Windows need to participate in this process. Override the GetChildWindow method, and examine the token parameter which is passed. If the token matches the Token property of one of your Client Extension's Child Windows, construct an instance of that Child Window derived class and return it. Otherwise, return null.

Help Tokens

public virtual bool ProcessHelpToken(string token)

The WL8 Help System includes a feature that allows the launch of a Client Extension ChildWindow when the user clicks a specially-formatted link in your help content page. To use this feature, add a link such as the one below to your help page:

 - [take me there now](action:extension:MyExtension)

When the user clicks such a link in the Help System, WL8 calls the ProcessHelpToken in your WL8ClientExtensionBase derived class, passing you the token that was part of the link. If the token matches one of your Client Extension ChildWindow Tokens, create an instance of the ChildWindow and call MyClientHost.ShowExtensionWindow to display it, and then return true. If the token does not match, return false.

Example Extension

Below is the complete source code for the Candlesticks Client Extension. It adds a menu item to the Extensions method, brings up a ChildWindow when clicked, and adds a new Preference page.

using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using WealthLab.Core;
using WealthLab.WPF;

namespace WealthLab.Candlesticks
{
    //Candlesticks Extension object
    public class CandlesticksClientExtension : WL8ClientExtensionBase
    {
        //Name
        public override string Name => "Candlesticks";

        //initialize
        public override List<MenuItem> GetMenuItems()
        {
            List<MenuItem> mi = new List<MenuItem>();
            MenuItem mni = CreateExtensionMenuItem("Candlestick Genetic Evolver", Glyph, mniClick);
            mi.Add(mni);
            return mi;
        }

        //get the child window from a workspace token
        public override ChildWindow GetChildWindow(string token)
        {
            if (token != "Candlesticks")
                return null;
            return CreateChildWindow();
        }

        //process help action token
        public override bool ProcessHelpToken(string token)
        {
            if (token == "Candlesticks")
            {
                CreateChildWindow();
                return true;
            }
            return false;
        }

        //get the Preference Page
        public override List<TabPage> PreferencePages
        {
            get
            {
                List<TabPage> lst = new List<TabPage>();
                lst.Add(new prefCandlesticks());
                return lst;
            }
        }

        //private members

        //click handler for generated menu item
        private void mniClick(object sender, RoutedEventArgs e)
        {
            CreateChildWindow();
        }

        //create the child window
        private ChildWindow CreateChildWindow()
        {
            cwCandlesticks cw = new cwCandlesticks();
            MyClientHost.ShowExtensionChildWindow(cw, "Candlestick Genetic Evolver", Glyph);
            return cw;
        }

        //return the Glyph
        private ImageSource Glyph => GlyphManager.GetImageSource("WealthLab.Candlesticks.WPF.Glyphs.Candlesticks.png", this);
    }
}