C# 如何从WPF中的可视树中分离
我正试图从C# 如何从WPF中的可视树中分离,c#,wpf,xaml,visualtreehelper,inlineuicontainer,C#,Wpf,Xaml,Visualtreehelper,Inlineuicontainer,我正试图从InlineUIContainer中正确删除UIElement,以便在另一个面板中使用它,但程序不断崩溃,并显示以下消息:“指定的Visual已是另一个Visual的子项或CompositionTarget的根。” 我创建了一个小应用程序来说明我的痛苦。在这个程序中,一旦Randy的按钮被他的女朋友杀死\删除,他仍然不会离开他的父母,我发现他的父母是UIElementIsland。然后,任何将Randy添加为其他任何事物的子对象的尝试都会导致应用程序崩溃(启示录按钮证明了我的观点:)。
InlineUIContainer
中正确删除UIElement
,以便在另一个面板中使用它,但程序不断崩溃,并显示以下消息:“指定的Visual已是另一个Visual的子项或CompositionTarget的根。”
我创建了一个小应用程序来说明我的痛苦。在这个程序中,一旦Randy的按钮被他的女朋友杀死\删除,他仍然不会离开他的父母,我发现他的父母是UIElementIsland
。然后,任何将Randy添加为其他任何事物的子对象的尝试都会导致应用程序崩溃(启示录按钮证明了我的观点:)。在删除Randy之前\之后,您可以单击查看Randy的父母,注意到他小时候一直处于UIElementIsland
的管理之下,如果他与外界疏远,那么整个问题\启示录应该可以避免
这是一个有趣的应用程序,所以复制和编译,即使只是为了好玩!如有任何帮助/想法,将不胜感激
C部分:
现在你可以适当地杀死兰迪,并将他添加到UIElement天堂(在StackPanel
):
谢谢大家。这很有趣,但也很吵。如果你的演示很短,你会得到更快的答案 您可以简单地隐藏/显示它,而不是删除/添加视觉效果:
void deleteRandy_Click(object sender, RoutedEventArgs e) =>
randy.Visibility = Visibility.Hidden;
void end_Click(object sender, RoutedEventArgs e) =>
randy.Visibility = Visibility.Visible;
这样,您就不会以不可恢复的方式玩可视化树了。如果确实要删除UI元素,然后添加新的元素,则可以使用MVVM+数据模板或
x:Shared=False
资源删除可视化父元素似乎没有帮助:
private void end_Click(object sender, RoutedEventArgs e)
{
IDisposable disp = VisualTreeHelper.GetParent(randy) as IDisposable;
if (disp != null)
disp.Dispose();
DependencyObject parent = VisualTreeHelper.GetParent(randy);
if (parent == null)
MessageBox.Show("No parent");
// If randy is removed properly, this would not crash the application.
StackPanel s = new StackPanel();
s.Children.Add(randy);
}
因此,您可以创建一个新的按钮
:
public MainWindow()
{
InitializeComponent();
randy_container.Child = CreateRandyButton();
}
private void end_Click(object sender, RoutedEventArgs e)
{
StackPanel s = new StackPanel();
s.Children.Add(CreateRandyButton());
}
private Button CreateRandyButton()
{
Button button = new Button { Name = "randy", Content = "I am a Randy, the button", ToolTip = "Meet Randy" };
button.Click += randy_Click;
return button;
}
…或者按照@Sinatr的建议将其隐藏。我找到了一个解决方法,以防父对象仍然是
UIElementIsland
。由于它实现了IDisposable
,因此可以通过以下方式清除其子项:
var parent = VisualTreeHelper.GetParent(element);
if (parent is IDisposable uiElementIsland)
{
uiElementIsland.Dispose();
}
这不太好,但很管用。“给它加点调料,让它变得有趣”在这里是弄巧成拙的。我认为您还必须从其父容器(即段落)中删除InlineUiContainer。我不知道为什么,但我的代码中有一个扩展方法可以做到这一点,因为我在几个月前遇到了同样的问题。下次我会赔礼道歉的。谢谢你,克莱门斯没用。刚才在@LennartNote处尝试过,您仍然可以编辑您的问题…是的,它仍然崩溃,但消息已更改为“指定的元素已经是另一个元素的逻辑子元素。请先断开它。”。我将看看如何解决这样做时它不会崩溃的问题:s.Children.Add(CreateRandyButton());嘿干得好!!!我从
InlineUIContainer
派生,并调用removelogicchild()
。以及您关于Dispose()
的建议。它成功了。谢谢!听起来不错,但这只是一个演示。我想使用richtextbox中的逻辑。
void deleteRandy_Click(object sender, RoutedEventArgs e) =>
randy.Visibility = Visibility.Hidden;
void end_Click(object sender, RoutedEventArgs e) =>
randy.Visibility = Visibility.Visible;
private void end_Click(object sender, RoutedEventArgs e)
{
IDisposable disp = VisualTreeHelper.GetParent(randy) as IDisposable;
if (disp != null)
disp.Dispose();
DependencyObject parent = VisualTreeHelper.GetParent(randy);
if (parent == null)
MessageBox.Show("No parent");
// If randy is removed properly, this would not crash the application.
StackPanel s = new StackPanel();
s.Children.Add(randy);
}
public MainWindow()
{
InitializeComponent();
randy_container.Child = CreateRandyButton();
}
private void end_Click(object sender, RoutedEventArgs e)
{
StackPanel s = new StackPanel();
s.Children.Add(CreateRandyButton());
}
private Button CreateRandyButton()
{
Button button = new Button { Name = "randy", Content = "I am a Randy, the button", ToolTip = "Meet Randy" };
button.Click += randy_Click;
return button;
}
var parent = VisualTreeHelper.GetParent(element);
if (parent is IDisposable uiElementIsland)
{
uiElementIsland.Dispose();
}