Reputation: 1794
I use FlipView
control and inside ItemTemplate
I have custom RichTextBlock with Elements
property created like collection of Run
elements. It works, however, sometimes I am receiving exception "WinRT information: Element is already the child of another element." And I really don't understand why.
Could somebody please explain me why it is happening?
Sample - http://1drv.ms/1yZM8a5
Model (contains test data)
public class Page
{
public Page()
{
Data = new List<Run>();
Data.Add(new Run { Text = "1" });
Data.Add(new Run { Text = "2" });
Data.Add(new Run { Text = "3" });
Data.Add(new Run { Text = "4" });
Data.Add(new Run { Text = "5" });
}
public IList<Run> Data { get; set; }
}
ViewModel (collection of pages for FlipView)
public ObservableCollection<Page> Pages { get; set; }
// test data
Pages = new ObservableCollection<Page>();
Pages.Add(new Page()); // etc
XAML
<FlipView ItemsSource="{Binding Pages}">
<FlipView.ItemTemplate>
<DataTemplate>
<local:ExtendedRichTextBlock Elements="{Binding Data}" />
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
ExtendedRichTextBlock
Elements
is dependency property and changes are caught here:
private static void OnElementsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ExtendedRichTextBlock sender = d as ExtendedRichTextBlock;
if (sender != null)
{
sender.Content.Blocks.Clear();
var x = e.NewValue as IList<Run>;
if (x != null)
{
foreach (var item in x)
{
var p = new Paragraph();
p.Inlines.Add(item); // WinRT information: Element is already the child of another element.
sender.Content.Blocks.Add(p);
}
}
}
}
Conclusion
Just short conclusion from my discussion with Romasz in this chat.
Every time the event is fired you are clearing content and then populating it reusing Run elements. In the behind it may be quite complex - maybe some animations, transitions and so on, I'm also not sure if this is not made asynchronously - if so there may be situation when elements still have a parent and you try to reuse it. Consider better thing, populating every time with UI elements it's not a good idea - make your datatemlate with those UI elements and bind their content to some kind of collection.
So all elements must be created on the fly in OnElementsChanged.
Upvotes: 1
Views: 186
Reputation: 29792
It seems that your program sometimes tries to make Run element a child of another control, while it already has a parent and UI elemnts can have only one parent.
In this case consider little change in your app:
private static void OnElementsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ExtendedRichTextBlock sender = d as ExtendedRichTextBlock;
if (sender != null)
{
sender.Content.Blocks.Clear();
var x = e.NewValue as IList<string>;
if (x != null)
{
foreach (var item in x)
{
var p = new Paragraph();
p.Inlines.Add(new Run { Text = item }); // WinRT information: Element is already the child of another element.
sender.Content.Blocks.Add(p);
}
}
}
}
Of course to make this work you need to change all IList<Run>
to IList<string>
.
This would ensure that every Run element is a new one without parent.
Upvotes: 1