-1

我知道这个问题已经被问过无数次了,但我不明白他们的问题是什么或如何效仿他们的例子。我确实找到了她的名字雷切尔,发布了一篇关于它的博客,但她的解释太简短了..

http://rachel53461.wordpress.com/2011/07/17/wpf-error-specified-element-is-already-the-logical-child-of-another-element-disconnect-it-first/

这是我在尝试遵循此处示例之前所拥有的:

<Window x:Class="Graph.View.MainView.Main"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:lc="http://schemas.devexpress.com/winfx/2008/xaml/layoutcontrol"
    Title="Main" Height="350" Width="525" 

    xmlns:dxdo="http://schemas.devexpress.com/winfx/2008/xaml/docking">

<DockPanel LastChildFill="True">
       <DockPanel>
        <Label  Content="{Binding ScreenContent}" Grid.Row="1" HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" VerticalContentAlignment="Stretch"/>
        </DockPanel>
    </DockPanel>

因为ScreenContent有一个合乎逻辑的父母我不能重用它。在尝试遵循 Rachel 的示例之后:

<Window x:Class="Graph.View.MainView.Main"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:lc="http://schemas.devexpress.com/winfx/2008/xaml/layoutcontrol"
        Title="Main" Height="350" Width="525" 
       >
    <Window.Resources>
        <Style     TargetType="{x:Type ContentControl}">
            <Setter Property="ContentTemplate"> 
                <Setter.Value>
                    <DataTemplate>
                        <DockPanel>
                            <Label   Content="{Binding ScreenContent}" Grid.Row="1" HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" VerticalContentAlignment="Stretch"/>
                        </DockPanel>
                    </DataTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>

    <DockPanel LastChildFill="True">            
        <Label Style="{StaticResource MyCustomContentControl}"/>
    </DockPanel>
</Window>

我该如何解决?它根本没有显示任何东西......谢谢。

4

3 回答 3

1

请回答我什么是ScreenContent财产……是字符串吗?还是一些 GUI 元素?

如果它是一个字符串,那么按照下面的解决方案...

还有一些概念你必须了解...

  1. Label里面Label是一个糟糕的UI设计。
  2. ContentControls例如LabelButton等当我们想要设置它们时遵循特定的 XAML 模式ControlTemplateDataTemplate
  3. 在您的情况下,您想要分配一个基于数据上下文的属性ScreenContent。所以DataTemplate方法是对的。

但是,这不会流向Label您的内部DataTemplate,因为外部Label(您已应用Style到的)未设置在其自己的Content属性上。

所以基本上 aContentControl.ContentTemplate只有在它和里面Content设置了一个 not null 的情况下( )作品作为所有项目的作品!ContentControlDataTemplateContentTemplateContentDataContext

注意{Binding}下面的表达式......这是不言自明的!

    <DockPanel LastChildFill="True">
        <DockPanel.Resources>
            <Style x:Key="MyCustomContentControl"
                   TargetType="{x:Type ContentControl}">
                    <Setter Property="ContentTemplate">
                        <Setter.Value>
                            <DataTemplate>
                                <DockPanel>
                                    <ContentPresenter
                                             Content="{Binding}"
                                             HorizontalAlignment="Stretch"
                                             VerticalAlignment="Stretch"/>
                                </DockPanel>
                            </DataTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </DockPanel.Resources>
        <Label Style="{StaticResource MyCustomContentControl}"
               Content="{Binding ScreenContent}" 
               HorizontalContentAlignment="Stretch"
               VerticalContentAlignment="Stretch">
        </Label>
    </DockPanel>

如果它是 UserControl,请按照以下解决方案...

您是否只分配一次(给给定的Label)?还是您试图将其分配为各种元素的内容?

如果它只分配一次,那么上面的解决方案应该可以工作。

但是,如果您打算将其分配为Content多个目标元素中的一个,那么您需要遵循Model/ViewModel方法。

  1. 您的所有 GUI 元素都应托管在 XAML 中。
  2. Code Behind 不应处理 GUI 元素。
  3. Code behind 仅适用于 GUI 元素的拷贝,即特定于 GUI (UserControl) 表示的字段的数据。

例如

示例 1...

假设您有一个TitleControl类似于粗斜体的 WPF,Label显示标题的文本。您持有DataContext这样TitleControl的对象,其中设置了一些标题文本。

然后在该ViewModel方法中,您应该创建一个实例TitleControlViewModel 作为...的一部分DataContext...类似这样...

YourDataContext.MyTitleControlViewModel = new TitleControlViewModel();

TitleControlViewModel类内部,我们应该有一个称为MyTitle字符串类型的公共属性。

YourDataContext.MyTitleControlViewModel.MyTitle = "My Title";

现在您的模板特定 XAML 应该如下所示...

    <DataTemplate x:Key="MyTitleControlDataTemplate">
         <local:TitleControl Title="{Binding MyTitle}"/>
    </DataTemplate>

你的主机面板应该是这样的......

    <ContentControl ToolTip="Title is shown here..." 
                    Content="{Binding MyTitleControlViewModel}"
                    Contenttemplate="{StatiocResource MyTitleControlDataTemplate}"/>

    <ContentControl ToolTip="Same title control is shown here also !!!"
                    Content="{Binding MyTitleControlViewModel}"
                    Contenttemplate="{StatiocResource MyTitleControlDataTemplate}"/>

因此,这样相同的标题控件似乎托管在上面的两个内容控件上。但是,如果您真的认为,有两个不同的实例TitleControl仅代表相同 的对象,MyTitleControlViewModel因此看起来像相同的控件!

谷歌了解数据模板和 MVVM 是如何结合在一起的。

于 2012-06-27T09:23:25.647 回答
0

UserControls(或任何其他类型的 UI 控件)不属于ViewModel

最好有一个要绑定的对象,并使用 aDataTemplate告诉 WPF 如何使用您的UserControl

例如,如果你有

ScreenModel ScreenContent { get; set; }

ScreenModel看起来像这样的自定义类在哪里

public class ScreenModel
{
    public string Name { get; set; }
    ...
}

然后你会使用这样的东西绑定到它:

<DockPanel LastChildFill="True">
    <DockPanel>
        <ContentControl Content="{Binding ScreenContent}" Grid.Row="1" HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" VerticalContentAlignment="Stretch"/>
    </DockPanel>
</DockPanel>

并使用 aDataTemplate告诉 WPF 如何绘制ScreenModel

<DataTemplate DataType="{x:Type models:ScreenModel}">
    <views:ScreenContentUserControl />
</DataTemplate>

或者

<DataTemplate DataType="{x:Type models:ScreenModel}">
    <Label Content="{Binding Name}" />
</DataTemplate>

因为您使用的是Template,所以 WPF 将在需要时创建 的新副本UserControl,并且不会尝试UserControl在多个位置使用相同的副本。

您的错误正在发生,因为您通过绑定多次添加相同的UserControl( ScreenContent) 。VisualTreeContent="{Binding ScreenContent}"

即使执行诸如切换选项卡之类的操作也可能会导致此错误,因为您将通过从选项卡切换来卸载所有 UI 对象,然后通过切换回来加载新的 UI 对象,但是您的ScreenContent用户控件已经将其父对象设置为旧对象不复存在。

于 2012-06-27T12:04:42.260 回答
0

如果您想重用ScreenContent(尽管它已经是其他元素的子元素),那么您必须首先克隆它并使用克隆的控件。

您可以通过首先使用序列化控件来克隆控件XamlWriter,然后通过使用反序列化它来创建新控件XamlReader,如下所示-

string screenContentXml = XamlWriter.Save(ScreenContent );

//Load it into a new object:
StringReader stringReader = new StringReader(screenContentXml );
XmlReader xmlReader = XmlReader.Create(stringReader);
UIElement screenContentClone = (UIElement)XamlReader.Load(xmlReader);

screenContentClone 在你的窗口中使用它。

但是,您可能会发现自己应用了变通方法来使其正常工作,因为使用时存在一些限制XamlWriter.Save(例如使用绑定) - XamlWriter.Save 的序列化限制

以下是一些其他的序列化方法 -

保留绑定的 XAML 序列化程序

XamlWriter 和绑定序列化

虽然您的设计看起来不像 AngelWPF 提到的那样正确,但您应该尝试重新设计您的窗口,您可能不需要做所有这些。

于 2012-06-27T09:45:35.617 回答