public static async void DuplicateItem(this InteractiveScene scene, IObject3D sourceItem = null) { if (sourceItem == null) { if (scene.HasSelection) { sourceItem = scene.SelectedItem; } } if (sourceItem != null) { // Copy selected item IObject3D newItem = await Task.Run(() => { if (sourceItem != null) { if (sourceItem is SelectionGroupObject3D) { // the selection is a group of objects that need to be copied var copyList = sourceItem.Children.ToList(); scene.SelectedItem = null; foreach (var item in copyList) { var clonedItem = item.Clone(); // make the name unique var newName = agg_basics.GetNonCollidingName(item.Name, scene.DescendantsAndSelf().Select((d) => d.Name)); clonedItem.Name = newName; // add it to the scene scene.Children.Add(clonedItem); // add it to the selection scene.AddToSelection(clonedItem); } } else // the selection can be cloned easily { var clonedItem = sourceItem.Clone(); // make the name unique var newName = agg_basics.GetNonCollidingName(sourceItem.Name, scene.DescendantsAndSelf().Select((d) => d.Name)); clonedItem.Name = newName; // More useful if it creates the part in the exact position and then the user can move it. // Consistent with other software as well. LBB 2017-12-02 //PlatingHelper.MoveToOpenPositionRelativeGroup(clonedItem, Scene.Children); return(clonedItem); } } return(null); }); // it might come back null due to threading if (newItem != null) { scene.InsertNewItem(newItem); } } }