Assertion when removing an object from its parent's children collection
Posted: 29 Sep 2021, 00:20
I have a view with some basic controls. I want to have 2 versions of it so I can do a staged rollout with A/B testing. Version A throws a bunch of controls in a stack panel, and Version B organizes the same set of controls into a slightly different tree structure. My XAML file defines all of the controls using Version A and stubs out some empty containers that Version B uses. Once my page is loaded, I run some code which determines if we are showing A or B. For A, it will remove the Version B stub containers and for B it will remove the controls from the Version A stack panel and add them to the Version B containers (then remove the Version A stack panel entirely). I like this approach because I only need to define the controls 1 time in XAML and can put them in correct place + remove the excess containers for the other version at run-time. Below is the function I'm using for these 2 operations. The problem is that if I call TryFindAndChangeParent with a nullptr newParent (i.e., without adding it back), I get the following assertion failure when the function returns and the control (now with a ref-count of 0) is disposed of:
[NOESIS/E] Assertion failed: mTemplatedParent == 0, at FrameworkElement.cpp(1575)
FWIW all the controls I'm passing to these functions are inside a template and the code is running during the "Loaded" event for that ControlTemplate. I am aware that I could also use collapsed visibility to "remove" an item, but since these controls are meant for an entirely different version of the UI screen, I think it makes more sense to actually remove them.
Also, the C# equivalent of this code works without issue if I run it in Microsoft Blend.
Here is the callstack:
[NOESIS/E] Assertion failed: mTemplatedParent == 0, at FrameworkElement.cpp(1575)
Code: Select all
static bool TryFindAndChangeParent(FrameworkElement * root, const char * name, Panel * newParent)
{
if (!root)
return false;
Ptr<FrameworkElement> found(DynamicCast<FrameworkElement*>(root->FindName(name)));
if (!found)
return false;
Ptr<Panel> parent(DynamicCast<Panel*>(found->GetParent()));
if (!parent)
return false;
bool success = parent->GetChildren()->Remove(found);
if (success && newParent)
{
newParent->GetChildren()->Add(found);
}
return success;
}
static bool TryFindAndRemove(FrameworkElement * root, const char * name)
{
return TryFindAndChangeParent(root, name, nullptr);
}
Also, the C# equivalent of this code works without issue if I run it in Microsoft Blend.
Here is the callstack: