Custom UI

Custom UI can be used, for example, when an end user selects a custom menu item. Because of CBFS Shell out-of-process architecture, as a .NET developer, you won't be able to display custom UI elements (e.g., dialog boxes, windows) from in-process Explorer upon an end-user action.

Fortunately, CBFS Shell comes with utility functions that make it possible for you to display custom .NET UI elements (e.g., WPF windows, Winforms) from your custom application in a modeless or modal way. These functions provide support for focus transition from Explorer to your UI elements.

The Registry Folder sample demonstrates how to display the .NET dialog box in response to menu item invocation:


When the user clicks "Modify" or double-clicks the item (the boldface font means "Modify" is the default action), the following .NET WinForm is displayed, with keyboard focus set on the input TextBox that contains "This is a custom value":


Here is a commented excerpt from the Registry Folder sample:

// we override MergeContextMenu to add our custom "Modify..." menu item
protected override void MergeContextMenu(ShellFolder folder, IReadOnlyList<ShellItem> items, ShellMenu existingMenu, ShellMenu appendMenu)
{
    ...
    appendMenu.AddInvokeItemHandler(OnShellMenuItemInvoke);
    if (items.Count == 1 && !items[0].IsFolder)
    {
        var modifyItem = new ShellMenuItem(appendMenu, "Modify...");
        modifyItem.Tag = MenuCommand.Modify; // this is just an enum to easily remember what was clicked 
        modifyItem.IsDefault = true; // this is why "Modify..." is displayed in boldface font and is the action that corresponds to the end user double-clicking the item
        appendMenu.Items.Add(modifyItem);
    }
    ...
}

private async void OnShellMenuItemInvoke(object sender, ShellMenuInvokeEventArgs e)
{
    // note that e.MenuItem may be null for standard Shell commands
    var menu = (ShellMenu)sender;
    var mc = Conversions.ChangeType(e.MenuItem?.Tag, MenuCommand.Unknown); // get back the command enum value
    switch (mc)
    {
        ....
        case MenuCommand.Modify:
            if (e.Items.Count == 1) // we only support modification of one value at a time
            {
                // EditValue is a standard WinForm class
                using (var form = new EditValue())
                {
                    var valueItem = (RegistryValueItem)e.Items[0]; // we know the selected item is a RegistryValueItem (ShellItem)
                    form.LoadEditor(BaseParent.Hive, Path, valueItem.KeyName); // a custom EditValue method
                    
                    // show EditValue as a modeless form
                    // the same helper exists for a WPF Window instance
                    await WindowsUtilities.ShowModelessAsync(form, e.HwndOwner).ContinueWith((task) =>
                    {
                        if (task.Result == DialogResult.OK)
                        {
                            using (var key = OpenKey(true)) // open key is a helper method from the sample code, not shown here
                            {
                                // do the real work of changing the key value
                                key.SetValue(valueItem.KeyName, form.NewValue);
 
                                // ask the folder to refresh
                                e.Folder.RefreshShellViews();
                            }
                        }
                    });
                }
                return;
            }
            break;
        ....
    }
}

Hi-DPI support

CBFS Shell is agnostic with regard to Hi-DPI support. The only UI it creates is the UI related to RPC connection problems between the host and the .NET server. This UI supports the "make text bigger" Windows display setting as well as the "make everything bigger" Windows display setting.

For example, here is this UI at 100%:


and the same UI in 225% mode:


Your custom UI will be determined according to the code, settings, application manifests, and UI framework that you use (e.g., WinForms, WPF). Because your custom UI may be hosted visually near or over the Explorer, please ensure that your custom UI supports Hi-DPI.

Threading Issues

If you need to show a window (like a WPF or WinForms window) from your Namespace Extension, you cannot do this from CBFS Shell implicit threads (threads implicitly created by RPC calls, coming from the Shell). These threads are not STA (Single-Threaded Apartment) threads, which is a common requirement for UI-bound objects.

Instead, to accomplish this, you should create your own STA threads or use CBFS Shell utilities. For example, here is how you can show a WPF window before enumerating items:

public override IEnumerable<ShellItem> EnumItems(SHCONTF options)
{
    // run code on an STA thread
    var ret = callback.ShellBoost.Core.Utilities.TaskUtilities.StartSTAThreadTask(() =>
    {
        var win = new MyWpfWindow(); // create the WPF window
        return win.ShowDialog(); // show it as a modal dialog
    }).Result; // => the result of ShowDialog
    ...
}

Windows Services

CBFS Shell Custom UI is not supported if the CBFS Shell folder server application is a Windows service. In this scenario, it's not running on the same Windows desktop as the client Windows Shell that is talking to the service.

Copyright (c) 2022 Callback Technologies, Inc. - All rights reserved.
CBFS Shell 2022 .NET Edition - Version 22.0 [Build 8367]