in WPF I need to have a collection of a collection of drawing objects

只谈情不闲聊 提交于 2019-12-02 05:04:11

Thank your for the improved code example. From that, it appears to me that you are going about your goal the wrong way entirely.

That is, you are trying to have a single ItemsControl object render all of your lines. But that's not how your data model is organized. Your data model has two completely different kinds of objects: LineArt objects, and the ObstacleArt object that contains LineArt objects.

Given that, it seems to me that a more appropriate approach would be to simply compose the MainWindowResource.Lines and MainWindowResource.Obstacles collections, and then use data templates to appropriately display these collections together.

Here is a new version of your XAML that shows what I mean:

<Window x:Class="POC_WPF_nestedDrawingObjects.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:c="clr-namespace:POC_WPF_nestedDrawingObjects"
        Title="MainWindow" Height="350" Width="525">

  <Window.Resources>
    <c:MainWindowResource x:Key="MainWindowResource"/>
    <Style x:Key="ContentCanvasStyle" TargetType="Canvas">
      <Setter Property="RenderTransformOrigin" Value="0,0"/>
    </Style>
    <DataTemplate DataType="{x:Type c:LineArt}">
      <Line
                X1="{Binding Path=AX}"
                Y1="{Binding Path=AY}"
                X2="{Binding Path=BX}"
                Y2="{Binding Path=BY}"
                Stroke="{Binding Path=LineColor}"
                StrokeThickness="{Binding Path=ScaledWeight}"
                StrokeEndLineCap="Round"
                StrokeStartLineCap="Round">
      </Line>
    </DataTemplate>
    <DataTemplate DataType="{x:Type c:ObstacleArt}">
      <ItemsControl ItemsSource="{Binding Lines, Mode=OneWay}">
        <ItemsControl.ItemsPanel>
          <ItemsPanelTemplate>
            <Canvas x:Name="ContentCanvas"
                        Style="{StaticResource ContentCanvasStyle}">
            </Canvas>
          </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.RenderTransform>
          <TransformGroup>
            <RotateTransform Angle="{Binding RotateAngle}"/>
            <TranslateTransform X="{Binding TranslateX}" Y="{Binding TranslateY}"/>
          </TransformGroup>
        </ItemsControl.RenderTransform>
      </ItemsControl>
    </DataTemplate>
  </Window.Resources>
  <Grid>
    <ItemsControl>
      <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
          <Canvas x:Name="ContentCanvas"
                  Style="{StaticResource ContentCanvasStyle}">
          </Canvas>
        </ItemsPanelTemplate>
      </ItemsControl.ItemsPanel>
      <ItemsControl.ItemsSource>
        <CompositeCollection>
          <CollectionContainer
              Collection="{Binding
                  Source={StaticResource MainWindowResource},
                  Path=Lines,
                  Mode=OneWay}"/>
          <CollectionContainer
              Collection="{Binding
                  Source={StaticResource MainWindowResource},
                  Path=Obstacles,
                  Mode=OneWay}"/>
        </CompositeCollection>
      </ItemsControl.ItemsSource>
    </ItemsControl>
  </Grid>
</Window>

The key here is the second DataTemplate, with a target type of ObstacleArt. This allows the main ItemsControl to display the individual ObstacleArt elements in the composite collection. Via the second data template, it does so by nesting an entirely new ItemsControl within for each ObstacleArt object, where that ItemsControl handles all of the rendering for the ObstacleArt object. Note that since the actual items in that nested ItemsControl object are themselves LineArt items, this winds up referring back to the DataTemplate for the LineArt type.

The above works without any changes at all to your code-behind. That said, it is my opinion that you would be better off making your classes inherit DependencyObject, and then make the bindable properties dependency properties. WPF does support INotifyPropertyChanged of course, but you have a lot of explicit property notification code in there that would just go away if you were using the dependency-property paradigm.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!