I need to temporarily show some UIElement in FlowDocument. I encapsulate it in BlockUIContainer but I don't see how it can be disconnected from BlockUICOntainer when I don't need it anymore. There's no Remove method. Below code shows that - it ends with exception
System.InvalidOperationException: 'Specified element is already the logical child of another element. Disconnect it first.'
E.g.
<Grid x:Name="Grid1">
<RichTextBox x:Name="rtb"/>
</Grid>
public MainWindow() {
InitializeComponent();
Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e) {
var c2 = new WrapPanel();
// Imagine adding lots of controls into c2 ...
rtb.Document.Blocks.Add(new BlockUIContainer(c2));
var bc = (BlockUIContainer)c2.Parent;
((FlowDocument)(bc).Parent).Blocks.Remove(bc);
Grid1.Children.Add(c2); // Exception. Here I want to move that c2 elsewhere in logical tree but I don't know how to disconnect it
}
Sure, I could recreate c2 but that's not nice. Or I see I could call internal RemoveLogicalChild but that also seems hacky. How WPF expects this is done?
Thank you
You have to properly disconnect the element and its child elements from the visual tree. The XAML rules don't allow multiple references to UIElemnts
in the tree. References are not tracked, which means there are no aliases of a single instance. Each UIElement
element must be an individual instance.
You can decide to create new instances or properly clear the association:
var c2 = new WrapPanel();
rtb.Document.Blocks.Add(new BlockUIContainer(c2));
var bc = (BlockUIContainer) c2.Parent;
rtb.Document.Blocks.Remove(bc);
// Remove parent association
bc.Child = null;
// Update the subtree/template association
c2.UpdateLayout();
Grid1.Children.Add(c2);