ExtendibleTreeStructure 1.0.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package ExtendibleTreeStructure --version 1.0.0
NuGet\Install-Package ExtendibleTreeStructure -Version 1.0.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ExtendibleTreeStructure" Version="1.0.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add ExtendibleTreeStructure --version 1.0.0
#r "nuget: ExtendibleTreeStructure, 1.0.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install ExtendibleTreeStructure as a Cake Addin
#addin nuget:?package=ExtendibleTreeStructure&version=1.0.0

// Install ExtendibleTreeStructure as a Cake Tool
#tool nuget:?package=ExtendibleTreeStructure&version=1.0.0

This is a high level overview of ExtendibleTreeStructure package. For more details look at the code docs and the tests in ExtendibleTreeStructure.Tests.

Overview

ExtendibleTreeStructure is a .NET package that allows easy configuration of tree structures that need to be copied to some other trees with new parents and children. The package allows providing as an input collections (called data stores in subsequent text) of simple objects (called data store items in subsequent text) that have minimum state (id, parent id, priority, id and data store id of copied data store item, etc). The classes in this package construct proper tree structures for each data store.

Good example of application of ExtendibleTreeStructure package is when we want to configure menu structure of a project (say in xml file). Lets say some part of menu structure is common for all file type (e.g., File Menu with Exit, Save, SaveAs menu items, Edit menu with search, etc). Also, lets suppose that the project supports C# and image file types, that support some additional functionality, and require new menu items on top of common (shared) menu structure. In this scenario we can provide a menu data store with shared data store items. Then we can define two more data stores for these two file types, with additional data store items (menu items) specific to these file types. In these new data stores we can copy the data store items in shared data store while spcifying new parent id (or no parent at all). Say we can copy File menu bar to data store for C# file type, and add new data store item for 'Compile' with parent id equal to id of File menu bar data store item. In other words, we specify copy data store items (data store items that specify the referenced data store item data id), with new parent id (or no parent id at all). Also, we can add new data store items with parent Ids equal to ids of children of copied data store items (i.e., add new children to children of copied data store items).

The classes in this package will create tree structures in all the specifiedspecified data stores with proper parent/children relationship, and will make sure the referenced (copied) data store items are copied under new parents (or are copied as top level data store items). Also, the package logs any errors, and prevents circular references that might otherwise result via parent/reference relationships.

The following is some vocabulary we use in this document to describe the package

  • Data store item: simple structure that has an Id, Priority and might have parent tree item Id (see interfaces ExtendibleTreeStructure.IDataStoreItem, ExtendibleTreeStructure.INonCopyDataStoreItem, ExtendibleTreeStructure.ICopyDataStoreItem, and ExtendibleTreeStructure.ICanHaveParent).
  • Data store: collection of data store items (see IDataStor< TDataStoreItem>)
  • Data store item wrapper: A wrapper object constructed from data store items by ExtendibleTreeStructure.IDataStoresCacheFactory in this package, that has a reference to data store item, parent data store item wrapper, and child data store items (see ExtendibleTreeStructure.IDataStoreItemWrapper< TNonCopyDataStoreItem>).

Notes

  • The interface IDataStoresCacheFactory< TDataStoreItem, TNonCopyDataStoreItem, TDataStoreItemWrapper> shown below takes as an input list of data stores and returns an instance of type IDataStoresCache< TNonCopyDataStoreItem, TDataStoreItemWrapper>. IDataStoresCache< TNonCopyDataStoreItem, TDataStoreItemWrapper> contains dictionaries of IDataStoreItemsCache< TNonCopyDataStoreItem, TDataStoreItemWrapper> which in turn contains collection of top level data store item wrappers (i.e., instances of IDataStoreItemWrapper<TNonCopyDataStoreItem>) which have been constructed from dat store items in input data stores.

  • When data IDataStoresCache< TNonCopyDataStoreItem, TDataStoreItemWrapper>** is loaded, any errors are logged with details of data store items that are sources of errors. Also, the prevents circular references and logs the paths in circular references (see examples below).

Below is an example of constructing data stores (see collection menuDataStores in this code), and then using this collection of data stores to construct an instance of IDataStoreItemsCache<TNonCopyDataStoreItem, TDataStoreItemWrapper>.

  • The last line in the example below visualizes the IDataStoreItemsCache< TNonCopyDataStoreItem, TDataStoreItemWrapper> constructed from data stores using IDataStoresCacheFactory< TDataStoreItem, TNonCopyDataStoreItem, TDataStoreItemWrapper>.

Example of constructing a cache that contains tree structures from data stores.

var menuDataStores = new List<IDataStore<IMenuObject>>();

menuDataStores.Add(
    new DataStore<IMenuObject>(MenuIds.SharedMenuObjects,
         new List<IMenuObject>
         {
             new MenuItemCollection(MenuIds.SharedToolsCollection),
             new MenuItemData(CommandIds.Projects, MenuIds.SharedToolsCollection),
             new MenuItemData(CommandIds.Errors, MenuIds.SharedToolsCollection),
         }));

menuDataStores.Add(
    new DataStore<IMenuObject>(MenuIds.NoFileSelectedMenuObjects,
         new List<IMenuObject>
         {
             new MenuBarData(MenuIds.NoFileSelectedDefaultMenuBar),
             new MenuBarItemData(CommandIds.ViewMenuBarItem, MenuIds.NoFileSelectedDefaultMenuBar),
             new MenuItemData(CommandIds.ToolsSubmenuItem, CommandIds.ViewMenuBarItem),             
             
             // Copy SharedToolsCollection from SharedMenuObjects data store and add the copy to CommandIds.ToolsSubmenuItem as a new child.
             new CopyMenuObject(MenuIds.SharedMenuObjects, MenuIds.SharedToolsCollection, 
                 CommandIds.ToolsSubmenuItem),
             
             // Add new child CommandIds.Git to child CommandIds.Projects of MenuIds.SharedToolsCollection copied from data store
             // MenuIds.SharedToolsCollection.
             new MenuItemData(CommandIds.Git, CommandIds.Projects)
         }));

menuDataStores.Add(
    new DataStore<IMenuObject>(MenuIds.TextFileMenuObjects,
         new List<IMenuObject>
         {
             // Copy the menu bar NoFileSelectedDefaultMenuBar from MenuIds.NoFileSelectedMenuObjects data store
             // and add new children top copied data store item.
             new CopyMenuObject(MenuIds.NoFileSelectedMenuObjects, MenuIds.NoFileSelectedDefaultMenuBar, null),

             // Add child CommandIds.RecentLocations to CommandIds.Projects, which is copied from MenuIds.NoFileSelectedMenuObjects
             // as a child of MenuIds.SharedToolsCollection.
             new MenuItemData(CommandIds.RecentLocations, CommandIds.Projects)
             {
                 // CommandIds.RecentLocations has a priority 0 and will appear before 
                 // other siblings in Project (default value is null) 
                 Priority = 0
             },

             // Add new menu bar item under menu bar MenuIds.NoFileSelectedDefaultMenuBar copied from data store 
             // MenuIds.NoFileSelectedMenuObjects.
             new MenuBarItemData(CommandIds.BuildMenuBarItem, MenuIds.NoFileSelectedDefaultMenuBar),
             new MenuItemData(CommandIds.RecentFiles, CommandIds.BuildMenuBarItem),

             // This item will result in error message being logged and item not being added
             // to MenuIds.NoFileSelectedDefaultMenuBar, since menu bars can have only menu bar items as children,
             // according to logic we provided in second parameter in IDataStoresCacheFactory.LoadDataStoresCache() below
             new MenuItemData(CommandIds.SaveToCloud, MenuIds.NoFileSelectedDefaultMenuBar)
         }));

var dataStoresCacheFactory = new DataStoresCacheFactory<IMenuObject, INonCopyMenuObject, MenuDataObjectWrapper>();

var loadedDataStoresCache = dataStoresCacheFactory.LoadDataStoresCache(menuDataStores,
         (dataStoreItemWrapper, parent) =>
         {
             var dataStoreItem = dataStoreItemWrapper.DataStoreItem;
             var dataStoreId = dataStoreItemWrapper.DataStoreId;

             if (parent?.DataStoreItem is IMenuBarData)
             {
                 if (dataStoreItem is not IMenuBarItemData)
                     return (null, new LoggedMessage(
                         MessageType.InvalidChildDataStoreItem,
                         String.Format("[{0}] cannot be used as a child for [{1}].",
                             dataStoreItem.GetDisplayValue(dataStoreId, true),
                             parent.DataStoreItem.GetDisplayValue(dataStoreId, false)),
                         dataStoreId, dataStoreItem, MessageCategory.Error));
             }

             return (new MenuDataObjectWrapper(dataStoreItem, dataStoreItemWrapper.DataStoreId, parent), null);
         },
         loggedMessage =>
         {
             Console.WriteLine(string.Format("[Data Store Id:{0}, Data Store Item: [{1}], MessageType: {2}, MessageCategory: {3}]{4}{4}\t\tMessage:{5}{4}",
                 loggedMessage.DataStoreId, loggedMessage.DataStoreItem?.GetDisplayValue(loggedMessage.DataStoreId, false),
                 loggedMessage.MessageType,
                 loggedMessage.MessageCategory,
                 System.Environment.NewLine,
                 loggedMessage.Message));
         });

var visualizedCacheFilePath = Path.Combine(Path.GetDirectoryName(typeof(TestHelpers).Assembly.Location)!,
            @"SuccessfulCacheBuildTests\TestFiles\SimpleDataStoresCacheLoadDemo.processed.xml");

Console.WriteLine(TestHelpers.VisualizeTestDataStoresCache(loadedDataStoresCache));

Visualized instance of IDataStoreItemsCache< TNonCopyDataStoreItem, TDataStoreItemWrapper> (loadedDataStoresCache in code above).

The xml file below is the visualized text for loadedDataStoresCache variable in C# code above

<?xml version="1.0" encoding="utf-8" ?>
<menuDataStores>
	<menuDataStore id="SharedMenuObjects">
		<menuItemCollection id="SharedToolsCollection">
			<menuItem commandId="Projects" parentId="ExtendibleTreeStructure.Tests.MenuIds.SharedToolsCollection" />
			<menuItem commandId="Errors" parentId="ExtendibleTreeStructure.Tests.MenuIds.SharedToolsCollection" />
		</menuItemCollection>
	</menuDataStore>
	<menuDataStore id="NoFileSelectedMenuObjects">
		<menuBar id="NoFileSelectedDefaultMenuBar">
			<menuBarItem commandId="ViewMenuBarItem" parentMenuBarId="ExtendibleTreeStructure.Tests.MenuIds.NoFileSelectedDefaultMenuBar">
				<menuItem commandId="ToolsSubmenuItem" parentId="ExtendibleTreeStructure.Tests.CommandIds.ViewMenuBarItem">
					<menuItemCollection id="SharedToolsCollection" parentId="ExtendibleTreeStructure.Tests.CommandIds.ToolsSubmenuItem">
						<menuItem commandId="Projects" parentId="ExtendibleTreeStructure.Tests.MenuIds.SharedToolsCollection">
							<menuItem commandId="Git" parentId="ExtendibleTreeStructure.Tests.CommandIds.Projects" />
						</menuItem>
						<menuItem commandId="Errors" parentId="ExtendibleTreeStructure.Tests.MenuIds.SharedToolsCollection" />
					</menuItemCollection>
				</menuItem>
			</menuBarItem>
		</menuBar>
	</menuDataStore>
	<menuDataStore id="TextFileMenuObjects">
		<menuBar id="NoFileSelectedDefaultMenuBar">
			<menuBarItem commandId="ViewMenuBarItem" parentMenuBarId="ExtendibleTreeStructure.Tests.MenuIds.NoFileSelectedDefaultMenuBar">
				<menuItem commandId="ToolsSubmenuItem" parentId="ExtendibleTreeStructure.Tests.CommandIds.ViewMenuBarItem">
					<menuItemCollection id="SharedToolsCollection" parentId="ExtendibleTreeStructure.Tests.CommandIds.ToolsSubmenuItem">
						<menuItem commandId="Projects" parentId="ExtendibleTreeStructure.Tests.MenuIds.SharedToolsCollection">
							<menuItem commandId="RecentLocations" parentId="ExtendibleTreeStructure.Tests.CommandIds.Projects" priority="0" />
							<menuItem commandId="Git" parentId="ExtendibleTreeStructure.Tests.CommandIds.Projects" />
						</menuItem>
						<menuItem commandId="Errors" parentId="ExtendibleTreeStructure.Tests.MenuIds.SharedToolsCollection" />
					</menuItemCollection>
				</menuItem>
			</menuBarItem>
			<menuBarItem commandId="BuildMenuBarItem" parentMenuBarId="ExtendibleTreeStructure.Tests.MenuIds.NoFileSelectedDefaultMenuBar">
				<menuItem commandId="RecentFiles" parentId="ExtendibleTreeStructure.Tests.CommandIds.BuildMenuBarItem" />
			</menuBarItem>
		</menuBar>
	</menuDataStore>
</menuDataStores>

Messages logged by code above

[Data Store Id:637754484146601333, Data Store Item: [menu object (Id:CommandIds.SaveToCloud), (ParentId:MenuIds.NoFileSelectedDefaultMenuBar), (DataStoreId:MenuIds.TextFileMenuObjects)], MessageType: InvalidChildDataStoreItem, MessageCategory: Error]

	Message:[Menu object (Id:CommandIds.SaveToCloud), (ParentId:MenuIds.NoFileSelectedDefaultMenuBar), (DataStoreId:MenuIds.TextFileMenuObjects)] cannot be used as a child 
           for [menu object (Id:MenuIds.NoFileSelectedDefaultMenuBar), (DataStoreId:MenuIds.TextFileMenuObjects)].

##Some more examples

  • The examples below show data stores as xml files (the code parses the xml file into collection of IDataStore< TDataStoreItem> objects), then an instance of IDataStoreItemsCache< TNonCopyDataStoreItem, TDataStoreItemWrapper> loaded from the data stores in xml file visualized into another xml file.

Simple example demonstrating copying a data store items from a different data store, and extending the copied data store with new child data store items (pretty similar to example above).

  • Input data stores
<?xml version="1.0" encoding="utf-8" ?>
<menuDataStores
	xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
	xsi:noNamespaceSchemaLocation="http://oroptimizer.com/ExtendibleTreeStructure/TestsXmlSchemas/MenuDataStoresSchema.xsd">
	<menuDataStore id="SharedMenuObjects">
		<menuItemCollection id="RecentObjectsCollection" usesMenuSeparator="true" />

		<menuItem commandId="RecentFiles" parentId="RecentObjectsCollection" />
		<menuItem commandId="RecentlyChangedFiles" parentId="RecentObjectsCollection" />
	</menuDataStore>

	<menuDataStore id="SharedMenuObjects2">
		<menuBarItem commandId="ViewMenuBarItem"/>

		
		<copyMenuObject referencedMenuDataStoreId="SharedMenuObjects" referencedMenuObjectId="RecentObjectsCollection"
		                parentId="ExtendibleTreeStructure.Tests.CommandIds.ViewMenuBarItem" />

		
		<menuItem commandId="RecentChanges" parentId="RecentObjectsCollection" />
		
		<menuItem commandId="RecentSubmissions" parentId="ExtendibleTreeStructure.Tests.CommandIds.RecentFiles" />
	</menuDataStore>
</menuDataStores>
  • Loaded IDataStoreItemsCache< TNonCopyDataStoreItem, TDataStoreItemWrapper>
<?xml version="1.0" encoding="utf-8" ?>
<menuDataStores>
	<menuDataStore id="SharedMenuObjects">
		<menuItemCollection id="RecentObjectsCollection" usesMenuSeparator="true">
			<menuItem commandId="RecentFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection" />
			<menuItem commandId="RecentlyChangedFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection" />
		</menuItemCollection>
	</menuDataStore>
	<menuDataStore id="SharedMenuObjects2">
		<menuBarItem commandId="ViewMenuBarItem">
			<menuItemCollection id="RecentObjectsCollection" usesMenuSeparator="true" parentId="ExtendibleTreeStructure.Tests.CommandIds.ViewMenuBarItem">
				<menuItem commandId="RecentFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection">
					<menuItem commandId="RecentSubmissions" parentId="ExtendibleTreeStructure.Tests.CommandIds.RecentFiles" />
				</menuItem>
				<menuItem commandId="RecentlyChangedFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection" />
				<menuItem commandId="RecentChanges" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection" />
			</menuItemCollection>
		</menuBarItem>
	</menuDataStore>
</menuDataStores>

Copying a copy of data store item.

  • Input data stores
<?xml version="1.0" encoding="utf-8" ?>
<menuDataStores
	xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
	xsi:noNamespaceSchemaLocation="http://oroptimizer.com/ExtendibleTreeStructure/TestsXmlSchemas/MenuDataStoresSchema.xsd">
	<menuDataStore id="SharedMenuObjects">
		<menuItemCollection id="RecentObjectsCollection" usesMenuSeparator="true" />

		<menuItem commandId="RecentFiles" parentId="RecentObjectsCollection" />
		<menuItem commandId="RecentlyChangedFiles" parentId="RecentObjectsCollection" />
	</menuDataStore>

	<menuDataStore id="SharedMenuObjects2">
		<menuBarItem commandId="ViewMenuBarItem"/>

		
		<copyMenuObject referencedMenuDataStoreId="SharedMenuObjects" referencedMenuObjectId="RecentObjectsCollection"
		                parentId="ExtendibleTreeStructure.Tests.CommandIds.ViewMenuBarItem" />

		
		<menuItem commandId="RecentChanges" parentId="RecentObjectsCollection" />
	</menuDataStore>

	<menuDataStore id="NoFileSelectedMenuObjects">
		<menuBar id="NoFileSelectedDefaultMenuBar" />
		<menuBarItem commandId="FileMenuBarItem" parentMenuBarId="NoFileSelectedDefaultMenuBar"/>

		
		<copyMenuObject referencedMenuDataStoreId="SharedMenuObjects2" referencedMenuObjectId="RecentObjectsCollection"
		                parentId="ExtendibleTreeStructure.Tests.CommandIds.FileMenuBarItem" />

		
		<menuItem commandId="RecentLocations" parentId="RecentObjectsCollection" />
		<menuItem commandId="RecentSubmissions" parentId="RecentObjectsCollection" />

		
		<menuItem commandId="Errors" parentId="ExtendibleTreeStructure.Tests.CommandIds.RecentChanges" />
	</menuDataStore>
</menuDataStores>
  • Loaded IDataStoreItemsCache< TNonCopyDataStoreItem, TDataStoreItemWrapper>
<?xml version="1.0" encoding="utf-8" ?>
<menuDataStores>
	<menuDataStore id="SharedMenuObjects">
		<menuItemCollection id="RecentObjectsCollection" usesMenuSeparator="true">
			<menuItem commandId="RecentFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection" />
			<menuItem commandId="RecentlyChangedFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection" />
		</menuItemCollection>
	</menuDataStore>
	<menuDataStore id="SharedMenuObjects2">
		<menuBarItem commandId="ViewMenuBarItem">
			<menuItemCollection id="RecentObjectsCollection" usesMenuSeparator="true" parentId="ExtendibleTreeStructure.Tests.CommandIds.ViewMenuBarItem">
				<menuItem commandId="RecentFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection" />
				<menuItem commandId="RecentlyChangedFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection" />
				<menuItem commandId="RecentChanges" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection" />
			</menuItemCollection>
		</menuBarItem>
	</menuDataStore>
	<menuDataStore id="NoFileSelectedMenuObjects">
		<menuBar id="NoFileSelectedDefaultMenuBar">
			<menuBarItem commandId="FileMenuBarItem" parentMenuBarId="ExtendibleTreeStructure.Tests.MenuIds.NoFileSelectedDefaultMenuBar">
				<menuItemCollection id="RecentObjectsCollection" usesMenuSeparator="true" parentId="ExtendibleTreeStructure.Tests.CommandIds.FileMenuBarItem">
					<menuItem commandId="RecentFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection" />
					<menuItem commandId="RecentlyChangedFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection" />
					<menuItem commandId="RecentChanges" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection">
						<menuItem commandId="Errors" parentId="ExtendibleTreeStructure.Tests.CommandIds.RecentChanges" />
					</menuItem>
					<menuItem commandId="RecentLocations" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection" />
					<menuItem commandId="RecentSubmissions" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection" />
				</menuItemCollection>
			</menuBarItem>
		</menuBar>
	</menuDataStore>
</menuDataStores>

Sorting data store items in parent data store using the value of Priority property of ExtendibleTreeStructure.IDataStoreItem..

  • Input data stores
<?xml version="1.0" encoding="utf-8" ?>
<menuDataStores
	xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
	xsi:noNamespaceSchemaLocation="http://oroptimizer.com/ExtendibleTreeStructure/TestsXmlSchemas/MenuDataStoresSchema.xsd">
	
	<menuDataStore id="SharedMenuObjects">
		
		<menuItemCollection id="RecentObjectsCollection" usesMenuSeparator="true" />

		<menuItem commandId="RecentFiles" parentId="RecentObjectsCollection" />
		<menuItem commandId="RecentLocations" parentId="RecentObjectsCollection" priority="20" />
		<menuItem commandId="RecentlyChangedFiles" parentId="RecentObjectsCollection" priority="10" />

		
		<menuItem commandId="EncodingUtf8"/>
		
		<menuItem commandId="SaveFile" />
		
		<menuItem commandId="SaveFileAs" priority="15"/>

		
		<menuItem commandId="Projects" />
		
		<menuItem commandId="Errors" priority="10"/>
		<menuItem commandId="BuildSolution" priority="20"/>

		
	</menuDataStore>

	<menuDataStore id="SharedMenuObjects2">
		<menuBarItem commandId="ViewMenuBarItem"/>

		
		<copyMenuObject referencedMenuDataStoreId="SharedMenuObjects" referencedMenuObjectId="RecentObjectsCollection"
		                parentId="ExtendibleTreeStructure.Tests.CommandIds.ViewMenuBarItem" />

		
		
		<menuItem commandId="RecentChanges" parentId="RecentObjectsCollection" priority="3" />
		
		<menuItem commandId="RecentSubmissions" parentId="RecentObjectsCollection" />

		<copyMenuObject referencedMenuDataStoreId="SharedMenuObjects" 
		                referencedMenuObjectId="ExtendibleTreeStructure.Tests.CommandIds.EncodingUtf8" 
		                parentId="RecentObjectsCollection" priority="12"/>
		<copyMenuObject referencedMenuDataStoreId="SharedMenuObjects"
		                referencedMenuObjectId="ExtendibleTreeStructure.Tests.CommandIds.SaveFile"
		                parentId="RecentObjectsCollection"/>
		<copyMenuObject referencedMenuDataStoreId="SharedMenuObjects"
		                referencedMenuObjectId="ExtendibleTreeStructure.Tests.CommandIds.SaveFileAs"
		                parentId="RecentObjectsCollection" priority="4"/>

		
		<copyMenuObject referencedMenuDataStoreId="SharedMenuObjects" 
		                referencedMenuObjectId="ExtendibleTreeStructure.Tests.CommandIds.Projects"/>
		<copyMenuObject referencedMenuDataStoreId="SharedMenuObjects" 
		                referencedMenuObjectId="ExtendibleTreeStructure.Tests.CommandIds.Errors"
		                priority="30" />

		
		<copyMenuObject referencedMenuDataStoreId="SharedMenuObjects" 
		                referencedMenuObjectId="ExtendibleTreeStructure.Tests.CommandIds.BuildSolution"
		                priority="5"/>

		
		<menuBarItem commandId="FileMenuBarItem" priority="2"/>
	</menuDataStore>
</menuDataStores>
  • Loaded IDataStoreItemsCache< TNonCopyDataStoreItem, TDataStoreItemWrapper>
<?xml version="1.0" encoding="utf-8" ?>
<menuDataStores>
	<menuDataStore id="SharedMenuObjects">
		<menuItem commandId="Errors" priority="10" />
		<menuItem commandId="SaveFileAs" priority="15" />
		<menuItem commandId="BuildSolution" priority="20" />
		<menuItemCollection id="RecentObjectsCollection" usesMenuSeparator="true">
			<menuItem commandId="RecentlyChangedFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection" priority="10" />
			<menuItem commandId="RecentLocations" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection" priority="20" />
			<menuItem commandId="RecentFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection" />
		</menuItemCollection>
		<menuItem commandId="EncodingUtf8" />
		<menuItem commandId="SaveFile" />
		<menuItem commandId="Projects" />
	</menuDataStore>
	<menuDataStore id="SharedMenuObjects2">
		<menuBarItem commandId="FileMenuBarItem" priority="2" />
		<menuItem commandId="BuildSolution" priority="5" />
		<menuItem commandId="Errors" priority="30" />
		<menuBarItem commandId="ViewMenuBarItem">
			<menuItemCollection id="RecentObjectsCollection" usesMenuSeparator="true" parentId="ExtendibleTreeStructure.Tests.CommandIds.ViewMenuBarItem">
				<menuItem commandId="RecentChanges" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection" priority="3" />
				<menuItem commandId="SaveFileAs" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection" priority="4" />
				<menuItem commandId="RecentlyChangedFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection" priority="10" />
				<menuItem commandId="EncodingUtf8" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection" priority="12" />
				<menuItem commandId="RecentLocations" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection" priority="20" />
				<menuItem commandId="RecentFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection" />
				<menuItem commandId="RecentSubmissions" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection" />
				<menuItem commandId="SaveFile" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection" />
			</menuItemCollection>
		</menuBarItem>
		<menuItem commandId="Projects" />
	</menuDataStore>
</menuDataStores>

Copy data store item multiple times in data store.

  • Input data stores
<?xml version="1.0" encoding="utf-8" ?>
<menuDataStores
	xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
	xsi:noNamespaceSchemaLocation="http://oroptimizer.com/ExtendibleTreeStructure/TestsXmlSchemas/MenuDataStoresSchema.xsd">
	<menuDataStore id="SharedMenuObjects">
		<menuBarItem commandId="ViewMenuBarItem"/>
		<menuItemCollection id="RecentObjectsGroup" parentId="ExtendibleTreeStructure.Tests.CommandIds.ViewMenuBarItem"/>
		<menuItem commandId="RecentlyChangedFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsGroup"/>
		<menuItem commandId="RecentLocations" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsGroup"/>
	</menuDataStore>

	<menuDataStore id="SharedMenuObjects2">

		
		<copyMenuObject referencedMenuDataStoreId="SharedMenuObjects"
		                referencedMenuObjectId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsGroup"/>

		
		<menuItem commandId="RecentFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsGroup"/>
		<menuItem commandId="Errors" parentId="ExtendibleTreeStructure.Tests.CommandIds.RecentFiles"/>

		<menuBarItem commandId="FileMenuBarItem"/>
		
		
		<copyMenuObject referencedMenuDataStoreId="SharedMenuObjects2"
		                referencedMenuObjectId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsGroup"
						id="RecentObjectsGroupCopy1"
		                parentId="ExtendibleTreeStructure.Tests.CommandIds.FileMenuBarItem"/>
		
		<copyMenuObject referencedMenuDataStoreId="SharedMenuObjects2"
		                referencedMenuObjectId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsGroup"
		                id="RecentObjectsGroupCopy2"
		                parentId="ExtendibleTreeStructure.Tests.CommandIds.FileMenuBarItem"/>

		<menuBarItem commandId="BuildMenuBarItem"/>

		
		<copyMenuObject referencedMenuDataStoreId="SharedMenuObjects2"
		                referencedMenuObjectId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsGroup"
		                id="RecentObjectsGroupCopy3"
		                parentId="ExtendibleTreeStructure.Tests.CommandIds.BuildMenuBarItem"/>

		
		<menuItem commandId="RecentSubmissions" parentId="ExtendibleTreeStructure.Tests.CommandIds.RecentLocations"/>
	</menuDataStore>
</menuDataStores>
  • Loaded IDataStoreItemsCache< TNonCopyDataStoreItem, TDataStoreItemWrapper>
<?xml version="1.0" encoding="utf-8" ?>
<menuDataStores>
	<menuDataStore id="SharedMenuObjects">
		<menuBarItem commandId="ViewMenuBarItem">
			<menuItemCollection id="RecentObjectsGroup" parentId="ExtendibleTreeStructure.Tests.CommandIds.ViewMenuBarItem">
				<menuItem commandId="RecentlyChangedFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsGroup" />
				<menuItem commandId="RecentLocations" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsGroup" />
			</menuItemCollection>
		</menuBarItem>
	</menuDataStore>
	<menuDataStore id="SharedMenuObjects2">
		<menuItemCollection id="RecentObjectsGroup">
			<menuItem commandId="RecentlyChangedFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsGroup" />
			<menuItem commandId="RecentLocations" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsGroup">
				<menuItem commandId="RecentSubmissions" parentId="ExtendibleTreeStructure.Tests.CommandIds.RecentLocations" />
			</menuItem>
			<menuItem commandId="RecentFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsGroup">
				<menuItem commandId="Errors" parentId="ExtendibleTreeStructure.Tests.CommandIds.RecentFiles" />
			</menuItem>
		</menuItemCollection>
		<menuBarItem commandId="FileMenuBarItem">
			<menuItemCollection id="RecentObjectsGroupCopy1" parentId="ExtendibleTreeStructure.Tests.CommandIds.FileMenuBarItem">
				<menuItem commandId="RecentlyChangedFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsGroupCopy1" />
				<menuItem commandId="RecentLocations" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsGroupCopy1">
					<menuItem commandId="RecentSubmissions" parentId="ExtendibleTreeStructure.Tests.CommandIds.RecentLocations" />
				</menuItem>
				<menuItem commandId="RecentFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsGroupCopy1">
					<menuItem commandId="Errors" parentId="ExtendibleTreeStructure.Tests.CommandIds.RecentFiles" />
				</menuItem>
			</menuItemCollection>
			<menuItemCollection id="RecentObjectsGroupCopy2" parentId="ExtendibleTreeStructure.Tests.CommandIds.FileMenuBarItem">
				<menuItem commandId="RecentlyChangedFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsGroupCopy2" />
				<menuItem commandId="RecentLocations" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsGroupCopy2">
					<menuItem commandId="RecentSubmissions" parentId="ExtendibleTreeStructure.Tests.CommandIds.RecentLocations" />
				</menuItem>
				<menuItem commandId="RecentFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsGroupCopy2">
					<menuItem commandId="Errors" parentId="ExtendibleTreeStructure.Tests.CommandIds.RecentFiles" />
				</menuItem>
			</menuItemCollection>
		</menuBarItem>
		<menuBarItem commandId="BuildMenuBarItem">
			<menuItemCollection id="RecentObjectsGroupCopy3" parentId="ExtendibleTreeStructure.Tests.CommandIds.BuildMenuBarItem">
				<menuItem commandId="RecentlyChangedFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsGroupCopy3" />
				<menuItem commandId="RecentLocations" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsGroupCopy3">
					<menuItem commandId="RecentSubmissions" parentId="ExtendibleTreeStructure.Tests.CommandIds.RecentLocations" />
				</menuItem>
				<menuItem commandId="RecentFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsGroupCopy3">
					<menuItem commandId="Errors" parentId="ExtendibleTreeStructure.Tests.CommandIds.RecentFiles" />
				</menuItem>
			</menuItemCollection>
		</menuBarItem>
	</menuDataStore>
</menuDataStores>

Data stores referencing each other.

  • Input data stores
<?xml version="1.0" encoding="utf-8" ?>
<menuDataStores
	xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
	xsi:noNamespaceSchemaLocation="http://oroptimizer.com/ExtendibleTreeStructure/TestsXmlSchemas/MenuDataStoresSchema.xsd">
	<menuDataStore id="SharedMenuObjects">
		<menuItemCollection id="RecentObjectsCollection" usesMenuSeparator="true" />

		<menuItem commandId="RecentFiles" parentId="RecentObjectsCollection" />
		<menuItem commandId="RecentlyChangedFiles" parentId="RecentObjectsCollection" />
		<copyMenuObject referencedMenuDataStoreId="SharedMenuObjects2" 
		                referencedMenuObjectId="ExtendibleTreeStructure.Tests.CommandIds.SaveToCloud"
						parentId="ExtendibleTreeStructure.Tests.CommandIds.RecentlyChangedFiles" />

	</menuDataStore>

	<menuDataStore id="SharedMenuObjects2">
		<menuBarItem commandId="ViewMenuBarItem"/>

		
		<copyMenuObject referencedMenuDataStoreId="SharedMenuObjects" referencedMenuObjectId="RecentObjectsCollection"
		                parentId="ExtendibleTreeStructure.Tests.CommandIds.ViewMenuBarItem" />

		
		<menuItem commandId="RecentChanges" parentId="RecentObjectsCollection" />

		<menuItem commandId="SaveToCloud"/>
		<menuItem commandId="SaveFile" parentId="ExtendibleTreeStructure.Tests.CommandIds.SaveToCloud"/>
	</menuDataStore>
</menuDataStores>
  • Loaded IDataStoreItemsCache< TNonCopyDataStoreItem, TDataStoreItemWrapper>
<?xml version="1.0" encoding="utf-8" ?>
<menuDataStores>
	<menuDataStore id="SharedMenuObjects">
		<menuItemCollection id="RecentObjectsCollection" usesMenuSeparator="true">
			<menuItem commandId="RecentFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection" />
			<menuItem commandId="RecentlyChangedFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection">
				<menuItem commandId="SaveToCloud" parentId="ExtendibleTreeStructure.Tests.CommandIds.RecentlyChangedFiles">
					<menuItem commandId="SaveFile" parentId="ExtendibleTreeStructure.Tests.CommandIds.SaveToCloud" />
				</menuItem>
			</menuItem>
		</menuItemCollection>
	</menuDataStore>
	<menuDataStore id="SharedMenuObjects2">
		<menuBarItem commandId="ViewMenuBarItem">
			<menuItemCollection id="RecentObjectsCollection" usesMenuSeparator="true" parentId="ExtendibleTreeStructure.Tests.CommandIds.ViewMenuBarItem">
				<menuItem commandId="RecentFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection" />
				<menuItem commandId="RecentlyChangedFiles" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection">
					<menuItem commandId="SaveToCloud" parentId="ExtendibleTreeStructure.Tests.CommandIds.RecentlyChangedFiles">
						<menuItem commandId="SaveFile" parentId="ExtendibleTreeStructure.Tests.CommandIds.SaveToCloud" />
					</menuItem>
				</menuItem>
				<menuItem commandId="RecentChanges" parentId="ExtendibleTreeStructure.Tests.MenuIds.RecentObjectsCollection" />
			</menuItemCollection>
		</menuBarItem>
		<menuItem commandId="SaveToCloud">
			<menuItem commandId="SaveFile" parentId="ExtendibleTreeStructure.Tests.CommandIds.SaveToCloud" />
		</menuItem>
	</menuDataStore>
</menuDataStores>

Circular references (prevention and error logging).

  • Input data stores
<?xml version="1.0" encoding="utf-8" ?>
<menuDataStores
	xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
	xsi:noNamespaceSchemaLocation="http://oroptimizer.com/ExtendibleTreeStructure/TestsXmlSchemas/MenuDataStoresSchema.xsd">
	
	<menuDataStore id="SharedMenuObjects">

		<menuItem commandId="ToolsSubmenuItem" />

		<menuItem commandId="RecentSubmissions" parentId="ExtendibleTreeStructure.Tests.CommandIds.ToolsSubmenuItem" />
		
		<menuItem commandId="RecentFiles" parentId="ExtendibleTreeStructure.Tests.CommandIds.ToolsSubmenuItem" />

		<copyMenuObject referencedMenuDataStoreId="SharedMenuObjects2" 
		                referencedMenuObjectId="ExtendibleTreeStructure.Tests.CommandIds.Projects"
		                parentId="ExtendibleTreeStructure.Tests.CommandIds.RecentFiles"/>
		
		<menuItem commandId="RecentChanges" parentId="ExtendibleTreeStructure.Tests.CommandIds.ToolsSubmenuItem" />
	</menuDataStore>

	<menuDataStore id="SharedMenuObjects2">
		<menuItem commandId="Projects"/>
		<copyMenuObject referencedMenuDataStoreId="SharedMenuObjects" 
		                referencedMenuObjectId="ExtendibleTreeStructure.Tests.CommandIds.ToolsSubmenuItem" 
		                parentId="ExtendibleTreeStructure.Tests.CommandIds.Projects"/>
	</menuDataStore>
</menuDataStores>
  • Loaded IDataStoreItemsCache< TNonCopyDataStoreItem, TDataStoreItemWrapper>
<?xml version="1.0" encoding="utf-8" ?>
<menuDataStores>
	<menuDataStore id="SharedMenuObjects">
		<menuItem commandId="ToolsSubmenuItem">
			<menuItem commandId="RecentSubmissions" parentId="ExtendibleTreeStructure.Tests.CommandIds.ToolsSubmenuItem" />
			<menuItem commandId="RecentFiles" parentId="ExtendibleTreeStructure.Tests.CommandIds.ToolsSubmenuItem">
				<menuItem commandId="Projects" parentId="ExtendibleTreeStructure.Tests.CommandIds.RecentFiles" />
			</menuItem>
			<menuItem commandId="RecentChanges" parentId="ExtendibleTreeStructure.Tests.CommandIds.ToolsSubmenuItem" />
		</menuItem>
	</menuDataStore>
	<menuDataStore id="SharedMenuObjects2">
		<menuItem commandId="Projects">
			<menuItem commandId="ToolsSubmenuItem" parentId="ExtendibleTreeStructure.Tests.CommandIds.Projects">
				<menuItem commandId="RecentSubmissions" parentId="ExtendibleTreeStructure.Tests.CommandIds.ToolsSubmenuItem" />
				<menuItem commandId="RecentFiles" parentId="ExtendibleTreeStructure.Tests.CommandIds.ToolsSubmenuItem" />
				<menuItem commandId="RecentChanges" parentId="ExtendibleTreeStructure.Tests.CommandIds.ToolsSubmenuItem" />
			</menuItem>
		</menuItem>
	</menuDataStore>
</menuDataStores>
  • Logged error messages. When circular references are logged, the logged message is of type ExtendibleTreeStructure.MessageLogging.ICircularReferencesErrorMessage that extends ExtendibleTreeStructure.MessageLogging.ILoggedMessage and has a property CircularReferencesPath of type IReadOnlyList<PathComponentEdge> with more details on data store items that cause the circular references. Below, is the message that is logged for the data stores above (using the data in ExtendibleTreeStructure.MessageLogging.ICircularReferencesErrorMessage).

ERROR : [Data Store Id:MenuIds.SharedMenuObjects, Data Store Item (Id:CommandIds.ToolsSubmenuItem), MessageType:CircularReferences] Message: Menu object (Id:CommandIds.ToolsSubmenuItem), (DataStoreId:MenuIds.SharedMenuObjects) results in the following circular references:

  • [menu object (Id:CommandIds.ToolsSubmenuItem), (DataStoreId:MenuIds.SharedMenuObjects)] going to child [menu object (Id:CommandIds.RecentFiles), (ParentId:CommandIds.ToolsSubmenuItem), (DataStoreId:MenuIds.SharedMenuObjects)]
  • [menu object (Id:CommandIds.RecentFiles), (ParentId:CommandIds.ToolsSubmenuItem), (DataStoreId:MenuIds.SharedMenuObjects)] going to child [copy menu object: (Id:CommandIds.Projects), (ParentId:CommandIds.RecentFiles), (DataStoreId:MenuIds.SharedMenuObjects), (ReferencedDataStoreId:MenuIds.SharedMenuObjects2), (ReferencedDataStoreItemId:CommandIds.Projects)]
  • [copy menu object: (Id:CommandIds.Projects), (ParentId:CommandIds.RecentFiles), (DataStoreId:MenuIds.SharedMenuObjects), (ReferencedDataStoreId:MenuIds.SharedMenuObjects2), (ReferencedDataStoreItemId:CommandIds.Projects)] going to copied item [menu object (Id:CommandIds.Projects), (DataStoreId:MenuIds.SharedMenuObjects2)]
  • [menu object (Id:CommandIds.Projects), (DataStoreId:MenuIds.SharedMenuObjects2)] going to child [copy menu object: (Id:CommandIds.ToolsSubmenuItem), (ParentId:CommandIds.Projects), (DataStoreId:MenuIds.SharedMenuObjects2), (ReferencedDataStoreId:MenuIds.SharedMenuObjects), (ReferencedDataStoreItemId:CommandIds.ToolsSubmenuItem)]
  • [copy menu object: (Id:CommandIds.ToolsSubmenuItem), (ParentId:CommandIds.Projects), (DataStoreId:MenuIds.SharedMenuObjects2), (ReferencedDataStoreId:MenuIds.SharedMenuObjects), (ReferencedDataStoreItemId:CommandIds.ToolsSubmenuItem)] going to copied item [menu object (Id:CommandIds.ToolsSubmenuItem), (DataStoreId:MenuIds.SharedMenuObjects)]

ERROR : [Data Store Id:MenuIds.SharedMenuObjects2, Data Store Item (Id:CommandIds.ToolsSubmenuItem, ParentId:CommandIds.Projects), MessageType:FailedToCopyDataStoreItem] Message: Failed to copy data store item referenced by [copy menu object: (Id:CommandIds.ToolsSubmenuItem), (ParentId:CommandIds.Projects), (DataStoreId:MenuIds.SharedMenuObjects2), (ReferencedDataStoreId:MenuIds.SharedMenuObjects), (ReferencedDataStoreItemId:CommandIds.ToolsSubmenuItem)]. This might be a result of other errors logged earlier.

ERROR : [Data Store Id:MenuIds.SharedMenuObjects, Data Store Item (Id:CommandIds.Projects, ParentId:CommandIds.RecentFiles), MessageType:FailedToCopyDataStoreItem] Message: Failed to copy data store item referenced by [copy menu object: (Id:CommandIds.Projects), (ParentId:CommandIds.RecentFiles), (DataStoreId:MenuIds.SharedMenuObjects), (ReferencedDataStoreId:MenuIds.SharedMenuObjects2), (ReferencedDataStoreItemId:CommandIds.Projects)]. This might be a result of other errors logged earlier.

Product Compatible and additional computed target framework versions.
.NET net5.0 is compatible.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net5.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.2.0 1,328 7/17/2022
1.0.3 1,281 6/23/2022
1.0.2 1,316 1/12/2022
1.0.1 1,322 1/12/2022
1.0.0 1,158 1/11/2022

This is a prerelease version of ExtendibleTreeStructure.