C# 如何使用ContentTemplate避免;指定的元素已经是另一个元素的逻辑子元素。“先断开它的连接”;错误

C# 如何使用ContentTemplate避免;指定的元素已经是另一个元素的逻辑子元素。“先断开它的连接”;错误,c#,.net,wpf,devexpress,C#,.net,Wpf,Devexpress,我知道这个问题被问了无数次,但我不明白他们的问题是什么,也不知道如何效仿他们。 我确实找到了她的名字Rachel,她在博客上写了这个名字,但是她的解释太简短了 以下是我在尝试遵循以下示例之前所做的: <Window x:Class="Graph.View.MainView.Main" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.micro

我知道这个问题被问了无数次,但我不明白他们的问题是什么,也不知道如何效仿他们。 我确实找到了她的名字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" 

    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
属性。。。是绳子吗?还是一些GUI元素

如果是字符串,则按照下面的解决方案进行操作…

还有一些你必须理解的概念

  • Label
    内部
    Label
    是一个糟糕的UI设计
  • 内容控件
    标签
    按钮
    等。当我们想要设置它们的
    控制模板
    数据模板
    时,遵循特定的XAML模式
  • 在本例中,您希望分配一个基于数据上下文的属性
    ScreenContent
    。因此,
    DataTemplate
    方法是正确的
  • 但是,这不会流到
    数据模板内的
    标签
    ,因为外部
    标签
    (您已将
    样式
    应用到该标签)本身的
    内容
    属性未设置

    因此基本上是
    ContentControl.ContentTemplate
    只有在
    ContentControl
    上和
    DataTemplate
    ContentTemplate
    )内设置了非空
    Content
    的情况下才能工作
    Content
    作为所有项目的
    DataContext

    注意下面的
    {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>
    
    你的主机面板应该是这样的

        <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的组合方式。

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

    您可以先使用
    XamlWriter
    对控件进行序列化,然后使用
    XamlReader
    对其进行反序列化,从而克隆控件,类似于-

    在窗口中使用此
    screenContentClone

    但是,您可能会发现自己正在应用变通方法以使其正常工作,因为在使用
    XamlWriter.Save
    (与绑定类似)时存在一些限制

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

    尽管您的设计不像AngelWPF提到的那样正确,您应该尝试重新设计您的窗口,并且您可能不需要这样做。

    用户控件(或任何其他类型的UI控件)不属于
    视图模型

    最好有一个绑定到的对象,并使用
    DataTemplate
    告诉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>
    

    
    
    由于您使用的是
    模板
    ,WPF将在需要时创建
    用户控件
    的新副本,并且不会尝试在多个位置使用相同的
    用户控件

    发生错误的原因是您通过
    Content=“{Binding ScreenContent}”
    绑定多次向
    VisualTree
    添加相同的
    UserControl
    ScreenContent


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

    如果要将其用作该键的静态资源,至少应设置
    。这不起作用:(ScreenContent是一个用户控件。我将它分配给一个标签内容,我认为这样做是可以的,但当然我不能重用该用户控件(screen)还有。我还以为这个方法会奏效!是的,但两种情况都不同。但假设你有一个选项卡式用户控件。在主选项卡中,你有一个EmployeeUserControl实例,只要你在第二个选项卡中没有另一个EmployeeUserControl实例,实际上它不会让你创建一个新的EmployeeUserControl来执行操作作为第二个选项卡。我想我知道问题是什么,但不知道如何解决它。我基本上是将构成屏幕的部分代码复制到Subscreen视图中。我删除了绑定,因为它将显示静态数据。但我一时兴起,决定重用我拥有的ViewModel。当我使用ViewModel时,即使SubscreennView没有任何逻辑父级。因此,这里的ViewModel是原因,为什么?我不知道。我认为您在做一些根本错误的事情!
    ViewModel
    ContentControls
    DataTemplate
    提供的原因完全相同,以便在多个实例中显示类似的控件。您能提供您的答案吗urce code?@Lewsterin您已将此问题标记为DevXPress!您是否使用任何DevXPress控件?如何使用?更简单的方法是使用另一个UserControl。我希望重用视图,以便随时可以制作小屏幕。这一限制很糟糕。无论如何,谢谢。我认为这里没有任何限制!
    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>
    
    <DataTemplate DataType="{x:Type models:ScreenModel}">
        <views:ScreenContentUserControl />
    </DataTemplate>
    
    <DataTemplate DataType="{x:Type models:ScreenModel}">
        <Label Content="{Binding Name}" />
    </DataTemplate>