我使用FlipView
控件并在ItemTemplate
内部,我创建了自定义RichTextBlock,其Elements
属性创建为Run
元素的集合。然而,它有效,我有时会收到异常" WinRT信息:元素已经是另一个元素的孩子。" 我真的不明白为什么。
有人可以解释一下为什么会这样吗?
模型(包含测试数据)
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 (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
是依赖属性,更改在此处捕获:
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);
}
}
}
}
结论
在我chat中与Romasz的讨论中得出的简短结论。
每次触发事件时,您都要清除内容,然后重新使用Run元素填充它。在后面它可能相当复杂 - 也许是一些动画,转换等等,我也不确定这是不是异步制作 - 如果是这样的话,可能会出现元素仍有父节点而你试图重用的情况它。考虑更好的事情,每次使用UI元素填充它并不是一个好主意 - 使用这些UI元素创建数据模板并将其内容绑定到某种集合。
因此必须在OnElementsChanged中动态创建所有元素。
答案 0 :(得分:1)
您的程序似乎有时会尝试将 Run 元素作为另一个控件的子元素,而它已经有一个父元素,而UI元素只能有一个父元素。
在这种情况下,请考虑对您的应用进行少量更改:
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);
}
}
}
}
当然要完成这项工作,您需要将所有IList<Run>
更改为IList<string>
。
这将确保每个 Run 元素都是没有父元素的新元素。