【问题标题】:Multiple dataTemplates in ItemsControl and CanvasItemsControl 和 Canvas 中的多个数据模板
【发布时间】:2018-09-27 13:12:03
【问题描述】:

我试图在画布上显示一些框(我自己的 userControl 在它自己的名为 singleNodeControl 的 xaml 文件中定义)并将它们与线连接(普通 xaml Line 元素绑定到 LineToParent 类)

这两项都存储在视图模型中的绑定列表中,该列表为<UserControl> 类型。这两个类(框和线)都扩展了 UserControl 类,因此我可以将它们存储到单个绑定列表(canvasNodeSourceList)中

SingleNodeControl 类包含 .cs 文件中的代码以及 .xaml 文件中的模板。

LineToParent 类仅包含 .cs 代码,我在其中存储 X1、X2、Y1、Y2 坐标以便以后绑定它们。

带有 itemsControl 的 xaml 看起来。我认为如果 canvasNodeSourceList 中的项目是 LineToParent 类型,它将使用下面的模板,否则它将使用存储在 singleNodeControl xaml 文件中的模板(更多如下)。

但似乎没有使用 line 的 dataTemplate。 SingleNodeCONtrols 被绘制,但没有线条。我缺少什么模板?甚至可以在外部文件中定义一些模板,在项目控制中定义一些模板吗?

我只是想显示一些可以通过线连接的框(需要在 xaml 定义中定义,因为它们将有多个内部元素)。

<ItemsControl x:Name="content" ItemsSource="{Binding canvasNodeSourceList}">                    
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate >
            <Canvas x:Name="contentCanvas" Background="White" Width="{Binding Width}" Height="{Binding Height}"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>                   
    <ItemsControl.Resources>
    <DataTemplate DataType="{x:Type slider:LineToParent}">
              <!--<Line X1="100" Y1="100" X2="10000" Y2="10000" StrokeThickness="5" Stroke="RED"></Line>-->
            <Line X1="{Binding leftPos1}" Y1="{Binding topPos1}" X2="{Binding leftPos2}" Y2="{Binding topPos2}" StrokeThickness="5" Stroke="Black"></Line>
        </DataTemplate>

    </ItemsControl.Resources>                  
</ItemsControl>

SingleNodeControl xaml 文件

<UserControl x:Class="WHS_qa.View.SingleNodeControl"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:WHS_qa.View"
         mc:Ignorable="d"              
         >
<Grid>
    <Border BorderBrush="Black" BorderThickness="2">
        <StackPanel Name="NodeStackPanel">


        </StackPanel>
    </Border>

</Grid>

我还尝试将 itemsControl 修改为如下所示(将 itemsControl.Resource 更改为 itemsControl.itemTemplate)并显示测试行(包含所有 singleNodeControl 元素)但输出充满错误

<ItemsControl x:Name="content" ItemsSource="{Binding canvasNodeSourceList}">                    
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate >
            <Canvas x:Name="contentCanvas" Background="White" Width="{Binding Width}" Height="{Binding Height}"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>                   
    <ItemsControl.ItemTemplate>
    <DataTemplate DataType="{x:Type slider:LineToParent}">
              <Line X1="100" Y1="100" X2="10000" Y2="10000" StrokeThickness="5" Stroke="RED"></Line>
            <!--<Line X1="{Binding leftPos1}" Y1="{Binding topPos1}" X2="{Binding leftPos2}" Y2="{Binding topPos2}" StrokeThickness="5" Stroke="Black"></Line>-->
        </DataTemplate>

    </ItemsControl.ItemTemplate>                  
</ItemsControl>

输出错误

System.Windows.Data Error: 26 : ItemTemplate and ItemTemplateSelector are ignored for items already of the ItemsControl's container type; Type='LineToParent'
System.Windows.Data Error: 26 : ItemTemplate and ItemTemplateSelector are ignored for items already of the ItemsControl's container type; Type='SingleNodeControl'
System.Windows.Data Error: 26 : ItemTemplate and ItemTemplateSelector are ignored for items already of the ItemsControl's container type; Type='LineToParent'
System.Windows.Data Error: 26 : ItemTemplate and ItemTemplateSelector are ignored for items already of the ItemsControl's container type; Type='SingleNodeControl'
System.Windows.Data Error: 26 : ItemTemplate and ItemTemplateSelector are ignored for items already of the ItemsControl's container type; Type='LineToParent'
System.Windows.Data Error: 26 : ItemTemplate and ItemTemplateSelector are ignored for items already of the ItemsControl's container type; Type='SingleNodeControl'
System.Windows.Data Error: 26 : ItemTemplate and ItemTemplateSelector are ignored for items already of the ItemsControl's container type; Type='LineToParent'

【问题讨论】:

  • 视图模型中的项目集合不应包含 UI 元素。相反,集合应该包含数据项,DataTemplates 中的元素绑定到这些数据项(如this example)。
  • @Clemens 感谢您的提示,我知道这一点,但我无法想象如何将这种方法与我的 SingleNodeControl 一起使用。它类似于多个元素的容器(img、标签、texbox 等)。我如何为这些子元素填充数据而不在代码中创建它?
  • 您的项目集合可能是IEnumerable&lt;object&gt;,即包含任何内容。然后为不同的项目类型声明不同的 DataTemplates。
  • 克莱门斯是对的。去看看链接上的例子。每种类型的元素都应该是它自己的类型,具有该元素所需的任何属性。将它们放在绑定到 UI 的 ObservableCollection 中,并使用 DataTemplates 为每种元素类型创建 UI。
  • 您的台词可能在那里,但都在画布中的0,0。 ItemsControl 将每个项目包装在&lt;ContentPresenter&gt; 中,您需要在ItemsContainerStyle 中绑定位置,以便将定位应用于ContentPresenter,而不是应用于该标记内的元素。我在很久以前写过a blog post,并附上了一些视觉示例,这样您就可以看到实际渲染的内容。也许这有助于解释它?

标签: c# wpf xaml mvvm datatemplate


【解决方案1】:

当您根据类型进行样式设置时,您不需要项目模板。这是因为您的模板将基于数据类型。
但是,您确实需要将放入 items 控件的 itemssource 中的所有数据类型的数据模板。

此示例在 itemscontrol 事物中执行画布,模板化出各种对象:

https://1drv.ms/u/s!AmPvL3r385QhgooJ94uO6PopIDs4lQ

 <ItemsControl x:Name="ic" ItemsSource="{Binding Items}"
                      Background="{StaticResource bgroundImage}">
            <ItemsControl.Resources>
                <DataTemplate DataType="{x:Type local:RectangleVM}">
                    <Rectangle Stroke="Green" Fill="White" 
                               Width="{Binding Width,Mode=TwoWay}"
                               Height="{Binding Height,Mode=TwoWay}"/>
                </DataTemplate>
                <DataTemplate DataType="{x:Type local:CircleVM}" >
                    <StackPanel>
                        <Ellipse Stroke="Red" Fill="White" 
                                 Width="{Binding EllipseWidth}" 
                                 Height="{Binding EllipseHeight}"
                                 />
                    </StackPanel>
                </DataTemplate>
                <DataTemplate DataType="{x:Type local:TextBoxVM}">
                    <TextBox Text="{Binding TbText}"/>
                </DataTemplate>
            </ItemsControl.Resources>
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas Name="TheCanvas"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemContainerStyle>
                <Style TargetType="ContentPresenter">
                    <Setter Property="Canvas.Top" Value="{Binding Top}"/>
                    <Setter Property="Canvas.Left" Value="{Binding Left}"/>
                </Style>
            </ItemsControl.ItemContainerStyle>
        </ItemsControl>

您可能还希望在项目容器上绑定 canvas.left 和 canvas.top。

该示例中显示的所有类型都完全不同。如果您有类似的项目,您可以对其中的大部分或部分项目使用基类,即使您提供子类型也会被识别。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-15
    • 2012-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多