MultiInstanceItemView makes it possible to have more than one configuration for each item view to the right of the structure tree. It allows for multiple, simultaneous configured ItemViews unlike Item-view which can have only one active instance. 


Prerequisites

The prerequisites are the same as those noted in Getting Started With swExplorer Extensions. A MultiInstanceItemView VS template can be found in the zip file attached to the article linked above. 


Example Configuration

<ExampleConfigs>
  <ExampleConfig id="1">  
    <ViewSettings> 
      <Caption>One</Caption> 
      <RibbonGroup>My group</RibbonGroup>
    </ViewSettings>
    <TopItemType itemType="I"/>
    <Message>Hello from 1</Message>
  </ExampleConfig>
  <ExampleConfig id="2">
    <Parameters>
      <Parameter name="p1" caption="Parameter:">
        <Values>
          <ForEach select = "/ISSE">
            <AddValue/>
          </ForEach>
        </Values>
      </Parameter>
    </Parameters>
    <ViewSettings>
      <Caption>Two</Caption>
      <RibbonGroup>My group</RibbonGroup>
    </ViewSettings>
    <TopItemType itemType="I"/>
    <Message>Going places</Message>
    <Path>$p1</Path>
  </ExampleConfig>
</ExampleConfigs>


The above configuration would result in a Ribbon group named "My Group" containing two menu icons: one labeled "One" and the other labeled "Two". Both would be using the same extension. 


Explanation of Configuration Elements

<ExampleConfigs> is the top-level element that contains all of the individual configurations. Each configuration should have a unique id (string value).


<ViewSettings> enables you to set a custom view label, hover-tip, icon, etc. See How to Configure Item View Menu Button Settings.

 

<Parameters> offers parameterization, where the user may select which item to include in a view. Drop-downs will automatically be shown in the GUI. The <Values> tag adds values to the parameter, using <AddValue> sub-elements. See Parameters in the application Help for more details. For MultiInstanceView, you would use Parameters for finding the top item/context.


<TopItemType> identifies the item type of which the configuration is valid.


Multi Instance Implementation

The implementation of multi-instance extensions is very similar to the ordinary extensions, with some minor differences which will be illustrated in the examples below.

 

Multi Instance Item View

When you create a multi-instance item view, make sure it inherits from IswMultiInstanceItemView, and that the view host is of the type IswMultiInstanceItemViewHost.


using RemObjects.Hydra;
using System;
using SystemWeaver.ExtensionsAPI;
using SystemWeaver.ExtensionsAPI.PluginInterfaces;

namespace SWExtension.Examples
{
    [Plugin, NonVisualPlugin]
    public partial class MultiInstanceItemViewExample : NonVisualPlugin, IswMultiInstanceItemView
    {
        public static IswMultiInstanceItemViewHost ViewHost { get; private set; }
        public static IswBroker Broker { get; private set; }
        public MultiInstanceItemViewExample()
        {
            InitializeComponent();
        }

        public Guid GetGUID()
        {
            return Guid.Parse("798C62B2-04E8-4C46-8799-69A344E4A39A");
        }

        public string GetName()
        {
            return typeof(MultiInstanceItemViewExample).FullName;
        }

        public string GetCaption()
        {
            return "### My multi-instance view";
        }


Get the config, example XML, and tag names from the configuration:

        public string GetPluginContentName()
        {
            return typeof(MultiInstanceItemViewExampleContent).FullName;
        }

        public void Init(IswMultiInstanceItemViewHost host)
        {
            ViewHost = host;
            Broker = ViewHost.GetBroker();
        }

        public string GetConfigXMLExample()
        {
            return MultiInstanceItemViewExampleViewConfig.ExampleXmlConfiguration;
        }

        public string GetDocumentElementTagName()
        {
            return MultiInstanceItemViewExampleViewConfig.DocumentElementTagName;
        }

        public string GetConfigElementTagName()
        {
            return MultiInstanceItemViewExampleViewConfig.ConfigElementTagName;
        }

        public IswViewConfig ParseAndGetConfig(string xml)
        {
            return new MultiInstanceItemViewExampleViewConfig(Broker, xml);
        }
        public bool SupportsItem(IswItem item, IswViewConfig viewConfig)
        {
            return item.IsSID("I");
        }
    }
}


Things to Consider

SupportsItems and GetGUID make continuous calls, so it is important that when either of these two are implemented that the code you include executes as fast as possible. For SupportsItems, e.g., it may not be only the item type it is looking for; there may be other variables. 


Multi Instance Configuration

The configuration could preferably look something like this: 

namespace SWExtension.Examples
{
    public class MultiInstanceItemViewExampleViewConfig : IswViewConfig
    {
        public static readonly string DocumentElementTagName = "ExampleConfigs";

        public static readonly string ConfigElementTagName = "ExampleConfig";

        public static readonly string ExampleXmlConfiguration =
@"<ExampleConfigs>
  <ExampleConfig id=""1"">  
    <ViewSettings> 
      <Caption>One</Caption> 
      <RibbonGroup>My group</RibbonGroup>
    </ViewSettings>
    <TopItemType itemType=""I""/>
    <Message>Hello from 1</Message>
  </ExampleConfig>
  <ExampleConfig id=""2"">
    <Parameters>
      <Parameter name=""p1"" caption=""Parameter:"">
      <Values>
        <ForEach select = ""/ISSE"">
          <AddValue/>
        </ForEach>
      </Values>
      </Parameter>
    </Parameters>
    <ViewSettings>
      <Caption>Two</Caption>
      <RibbonGroup>My group</RibbonGroup>
    </ViewSettings>
    <TopItemType itemType=""I""/>
    <Message>Going places</Message>
    <Path>$p1</Path>
  </ExampleConfig>
</ExampleConfigs>";


Multi Instance View Content

The multi instance item view content must inherit from MultiInstanceItemViewContent, use the MultiInstanceItemViewWrapper, and the IswMultiInstanceItemViewContentHost.

    [Plugin, VisualPlugin, NeedsManagedWrapper(typeof(MultiInstanceItemViewWrapper))]
    public partial class MultiInstanceItemViewExampleContent : RemObjects.Hydra.WPF.VisualPlugin, IswMultiInstanceItemViewContent
    {
        private IswMultiInstanceItemViewContentHost _host;
        private MultiInstanceItemViewExampleViewConfig _config;
        private IswServerEvent _events;

        public MultiInstanceItemViewExampleContent()
        {
            InitializeComponent();
        }

        public void SetHost(IswMultiInstanceItemViewContentHost host)
        {
            _host = host;
            textServerUrl.Text = MultiInstanceItemViewExample.ViewHost.GetServerUrl();
        }

        public void SetConfig(IswViewConfig config)
        {
            _config = config as MultiInstanceItemViewExampleViewConfig;
            textBlockConfig.Text = _config.Message;
        }

        public void SetCurrentItem(IswItem item)
        {
            if (item == null)
            {
                textBlockCurrentItem.Text = "";
                textBlockPathResult.Text = "";
                return;
            }

            textBlockCurrentItem.Text = $"Current item is {item.Name}";

            IswItems items = (_host as IswHydraStructureTreeGetSubItems).GetSubItems();

            try
            {
                if (string.IsNullOrEmpty(_config.PathExpression))
                {
                    textBlockPathResult.Text = "";
                }
                else
                {
                    IswObjects pathResult = _host.ExecutePathWithParameters(_config.PathExpression, item);
                    textBlockPathResult.Text = string.Join(", ", pathResult.ToArray().Select(x => x.Name));
                }
            }
            catch (COMException e)
            {
                textBlockPathResult.Text = e.Message;
            }
        }

        private void ButtonOpen_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            var handle = SWHandleUtility.ToHandle(textItemId.Text);

            IswItem item = MultiInstanceItemViewExample.Broker.GetItem(handle);

            _host.OpenItem(item, THowToOpenType.ChangeFocusOnly);

        }

        private void ButtonIndicate_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            var handle = SWHandleUtility.ToHandle(textItemId.Text);

            var item = MultiInstanceItemViewExample.Broker.GetItem(handle);

            var list = MultiInstanceItemViewExample.Broker.Lists.NewItemList();

            list.Add(item);

            _host.IndicateItems(list);
        }

        private void ButtonSelectUser_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            MultiInstanceItemViewExample.ViewHost.GetDialogs().SelectUser(out IswUser user);
        }

        private void ButtonCopyToClipboard_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            var handle = SWHandleUtility.ToHandle(textItemId.Text);

            var item = MultiInstanceItemViewExample.Broker.GetItem(handle);

            var list = MultiInstanceItemViewExample.Broker.Lists.NewItemList();

            list.Add(item);

            MultiInstanceItemViewExample.ViewHost.GetClipboard().SetObjects(list);
        }

        private void ButtonConnectClipboard_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            _events = new ExtensionEvents();

            _host.SetEvent(_events);

            IswEvents ev = _events as IswEvents;

            ev.Object_SetName += DoSetName;
        }

        private void DoSetName(IswObject obj)
        {
            textEventInfo.Text = $"Name set to {obj.Name}";
        }
    }
}