View Issue Details

IDProjectCategoryView StatusLast Update
0004636NoesisGUIStudiopublic2025-12-12 15:37
Reporterdstewart Assigned Tomaherne  
PrioritynormalSeverityminor 
Status resolvedResolutionfixed 
Product VersionStudio_Beta 
Target VersionStudio_BetaFixed in VersionStudio_Beta 
Summary0004636: No Ability To Delete Multiple Elements At Once
Description

Currently, in our ability to perform Element mutli-selection, we allow you to modify a wide range of things about them at once: their position on-Stage, their Properties in common, to Group them, and to Duplicate the entire multi-selection.

However, we currently do not offer the ability to Delete multi-selected Elements at once.


Repro Steps:

1) Create a new Studio Project featuring a MainPage.xaml

2) Introduce 4-5 Elements of any kind under the MainPage's RootGrid.

3) Either by holding [Ctrl]+clicking, or [Shift]+click, multiselect all of the Elements introduced in Step 2).

4) With all of the Elements selected, press the [Del] key on the keyboard.

Observe how no deletion occurs.

5) With all of the Elements selected, right-click on any of them, and from the right-click context menu, navigate to Edit --> Delete.

Observe how the Deletion function is greyed out and inactive.

Observe how the Duplicate function however is available.

In the ContextMenu's Layout section, observe how many more options can be applied to the multi-selection as a whole.

Expected Results: Deletions can be performed on multiple Elements at once, either from the [Del] keyboard shortcut, or via the context menu.

PlatformAny

Activities

maherne

maherne

2025-12-12 13:29

developer   ~0011612

The attached patch fixes this issue, by allowing you to Cut, Copy, or Paste single or mutli-selected tree items, as long as none of them are the root of a template or style scope. The paste command now has it's own CanPaste delegate, which only enables pasting when a single element tree item is selected.

4636_CanEdit.patch (3,216 bytes)   
Index: XamlDocument.cpp
===================================================================
--- XamlDocument.cpp	(revision 16441)
+++ XamlDocument.cpp	(working copy)
@@ -240,7 +240,7 @@
         MakeDelegate(this, &XamlDocument::Cut));
     mCopyCommand = MakePtr<DelegateCommand>(MakeDelegate(this, &XamlDocument::CanEdit),
         MakeDelegate(this, &XamlDocument::Copy));
-    mPasteCommand = MakePtr<DelegateCommand>(MakeDelegate(this, &XamlDocument::CanEdit),
+    mPasteCommand = MakePtr<DelegateCommand>(MakeDelegate(this, &XamlDocument::CanPaste),
         MakeDelegate(this, &XamlDocument::Paste));
     mPasteAsTextCommand = MakePtr<DelegateCommand>(MakeDelegate(this, &XamlDocument::CanPasteAsText),
         MakeDelegate(this, &XamlDocument::PasteAsText));
@@ -3102,40 +3102,42 @@
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 bool XamlDocument::CanEdit(Noesis::BaseComponent*)
 {
-    if (!HasOneElementSelected(nullptr))
-    {
-        return false;
-    }
     Scope* scope = GetCurrentScope();
     if (scope == nullptr)
     {
         return false;
     }
+
     Vector<DocumentObjectTreeItem*, 1> selection;
     scope->GatherSelectedNodesByType(DocumentObjectType_Element, selection);
-    NS_ASSERT(selection.Size() == 1);
     if (selection.Empty())
     {
         return false;
     }
 
-    // Don't allow pasting in non-element tree items
-    ElementTreeItem* selectedItem = DynamicCast<ElementTreeItem*>(selection.Back());
-    if (selectedItem == nullptr)
+    if (scope->GetType() == ScopeType_Style || scope->GetType() == ScopeType_Template)
     {
-        return false;
+        for (uint32_t i = 0; i < selection.Size(); i++)
+        {
+            ElementTreeItem* treeItem = DynamicCast<ElementTreeItem*>(selection[i]);
+            if (treeItem != nullptr && scope->GetRoot() == treeItem)
+            {
+                return false;
+            }
+        }
     }
 
-    // Don't allow Edit commands on the Style or Template scope root
-    if (!Helper::IsType<FrameworkElement>(selectedItem->GetScopeElement()))
-    {
-        return false;
-    }
-
     return true;
 }
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
+bool XamlDocument::CanPaste(Noesis::BaseComponent*)
+{
+    return HasOneElementSelected(nullptr);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
 bool XamlDocument::CanPasteAsText(Noesis::BaseComponent*)
 {
     String text = Clipboard::Get();
Index: XamlDocument.h
===================================================================
--- XamlDocument.h	(revision 16441)
+++ XamlDocument.h	(working copy)
@@ -486,6 +486,7 @@
     bool TryPasteXAML(const char* text, Noesis::NodeObject* node);
     Noesis::Ptr<Noesis::NodeObject> ValidateXAML(const char* text);
     bool CanEdit(Noesis::BaseComponent*);
+    bool CanPaste(Noesis::BaseComponent*);
     bool CanPasteAsText(Noesis::BaseComponent*);
     void PasteAsText(Noesis::BaseComponent*);
     void DeleteElement(Noesis::BaseComponent*);
4636_CanEdit.patch (3,216 bytes)   
maherne

maherne

2025-12-12 14:24

developer   ~0011614

The attached patch adds a check to XamlDocument::CanPatch, to check if the user is in a style scope, and return false if so.

4636_CanEdit_2.patch (3,240 bytes)   
Index: XamlDocument.cpp
===================================================================
--- XamlDocument.cpp	(revision 16441)
+++ XamlDocument.cpp	(working copy)
@@ -240,7 +240,7 @@
         MakeDelegate(this, &XamlDocument::Cut));
     mCopyCommand = MakePtr<DelegateCommand>(MakeDelegate(this, &XamlDocument::CanEdit),
         MakeDelegate(this, &XamlDocument::Copy));
-    mPasteCommand = MakePtr<DelegateCommand>(MakeDelegate(this, &XamlDocument::CanEdit),
+    mPasteCommand = MakePtr<DelegateCommand>(MakeDelegate(this, &XamlDocument::CanPaste),
         MakeDelegate(this, &XamlDocument::Paste));
     mPasteAsTextCommand = MakePtr<DelegateCommand>(MakeDelegate(this, &XamlDocument::CanPasteAsText),
         MakeDelegate(this, &XamlDocument::PasteAsText));
@@ -3102,37 +3102,44 @@
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 bool XamlDocument::CanEdit(Noesis::BaseComponent*)
 {
-    if (!HasOneElementSelected(nullptr))
-    {
-        return false;
-    }
     Scope* scope = GetCurrentScope();
     if (scope == nullptr)
     {
         return false;
     }
+
     Vector<DocumentObjectTreeItem*, 1> selection;
     scope->GatherSelectedNodesByType(DocumentObjectType_Element, selection);
-    NS_ASSERT(selection.Size() == 1);
     if (selection.Empty())
     {
         return false;
     }
 
-    // Don't allow pasting in non-element tree items
-    ElementTreeItem* selectedItem = DynamicCast<ElementTreeItem*>(selection.Back());
-    if (selectedItem == nullptr)
+    if (scope->GetType() == ScopeType_Style || scope->GetType() == ScopeType_Template)
     {
-        return false;
+        for (uint32_t i = 0; i < selection.Size(); i++)
+        {
+            ElementTreeItem* treeItem = DynamicCast<ElementTreeItem*>(selection[i]);
+            if (treeItem != nullptr && scope->GetRoot() == treeItem)
+            {
+                return false;
+            }
+        }
     }
 
-    // Don't allow Edit commands on the Style or Template scope root
-    if (!Helper::IsType<FrameworkElement>(selectedItem->GetScopeElement()))
+    return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+bool XamlDocument::CanPaste(Noesis::BaseComponent*)
+{
+    Scope* scope = GetCurrentScope();
+    if (scope != nullptr && scope->GetType() == ScopeType_Style)
     {
         return false;
     }
 
-    return true;
+    return HasOneElementSelected(nullptr);
 }
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
Index: XamlDocument.h
===================================================================
--- XamlDocument.h	(revision 16441)
+++ XamlDocument.h	(working copy)
@@ -486,6 +486,7 @@
     bool TryPasteXAML(const char* text, Noesis::NodeObject* node);
     Noesis::Ptr<Noesis::NodeObject> ValidateXAML(const char* text);
     bool CanEdit(Noesis::BaseComponent*);
+    bool CanPaste(Noesis::BaseComponent*);
     bool CanPasteAsText(Noesis::BaseComponent*);
     void PasteAsText(Noesis::BaseComponent*);
     void DeleteElement(Noesis::BaseComponent*);
4636_CanEdit_2.patch (3,240 bytes)   

Issue History

Date Modified Username Field Change
2025-12-11 12:15 dstewart New Issue
2025-12-11 12:36 jsantos Assigned To => dfranjic
2025-12-11 12:36 jsantos Status new => assigned
2025-12-11 12:36 jsantos Target Version => Studio_Beta
2025-12-11 17:36 dfranjic Assigned To dfranjic => maherne
2025-12-12 13:29 maherne Note Added: 0011612
2025-12-12 13:29 maherne File Added: 4636_CanEdit.patch
2025-12-12 13:29 maherne Assigned To maherne => dfranjic
2025-12-12 14:24 maherne Note Added: 0011614
2025-12-12 14:24 maherne File Added: 4636_CanEdit_2.patch
2025-12-12 15:36 maherne Assigned To dfranjic => maherne
2025-12-12 15:37 maherne Status assigned => resolved
2025-12-12 15:37 maherne Resolution open => fixed
2025-12-12 15:37 maherne Fixed in Version => Studio_Beta