ItemsControl仅显示每个对象的第一个Item

问题描述 投票:0回答:1

我有一个问题是将一系列线条绘制到画布中。谷歌向我展示了几个来源,但我找不到真正的解决方案。我希望你们有一个暗示我。

我的结构如下:

public class CanvasLine
{
    public Double X1 { get; set; }
    public Double X2 { get; set; }
    public Double Y1 { get; set; }
    public Double Y2 { get; set; }
    public Brush StrokeColor { get; set; }
    public Double StrokeThickness { get; set; }
    public DoubleCollection StrokeDashArray { get; set; }
}

public class CanvasObject
{
    public String Name { get; set; }
    public ObservableCollection<CanvasLine> CanvasLines { get; set; }
}

public class ViewModel
{
    ...
    public ObservableCollection<CanvasObject> CanvasObjects;
    ...
}

XAML:

<Window x:Class="XXX.Views.MainWindow"
    xmlns:vm="clr-namespace:XXX.Viewmodels"
    xmlns:converter="clr-namespace:XXX.Converter"
    Title="XXX" Height="480" Width="640">
<Window.DataContext>
    <vm:ViewModel/>
</Window.DataContext>
<Grid>
    <ItemsControl Grid.Column="1" Grid.Row="2" Margin="0" ItemsSource="{Binding CanvasObjects, UpdateSourceTrigger=PropertyChanged}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Line DataContext="{Binding CanvasLines}" Stroke="{Binding StrokeColor}" StrokeDashArray="{Binding StrokeDashArray}" StrokeThickness="{Binding StrokeThickness}">
                    <Line.X1>
                        <MultiBinding Converter="{StaticResource MultiplicationConverter}">
                            <Binding Path="X1"/>
                            <Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=Canvas}"/>
                        </MultiBinding>
                    </Line.X1>
                    <Line.X2>
                        <MultiBinding Converter="{StaticResource MultiplicationConverter}">
                            <Binding Path="X2"/>
                            <Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=Canvas}"/>
                        </MultiBinding>
                    </Line.X2>
                    <Line.Y1>
                        <MultiBinding Converter="{StaticResource MultiplicationConverter}">
                            <Binding Path="Y1"/>
                            <Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=Canvas}"/>
                        </MultiBinding>
                    </Line.Y1>
                    <Line.Y2>
                        <MultiBinding Converter="{StaticResource MultiplicationConverter}">
                            <Binding Path="Y2"/>
                            <Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=Canvas}"/>
                        </MultiBinding>
                    </Line.Y2>
                </Line>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Grid>

这是为了演示,我可能删除了太多。

我的问题是在画布上只显示每个CanvasLine的第一个CanvasObject。如果我放弃CanvasObjectDataContext="{Binding CanvasLines}"并直接将ItemsControl绑定到ObservableCollection<CanvasLine>,但是在接下来的步骤中我需要添加更多的对象并且我试图避免一个巨大的行列表以保持某种类型对象结构。

由于我对这个MVVM Binding的东西很陌生,我很高兴你想分享的任何想法。

问候。

c# .net wpf data-binding
1个回答
1
投票

您不能在DataTemplate中绑定Line的DataContext。它确实已经包含对相应集合元素的引用。

你真正需要的是嵌套的ItemsControls,一个用于CanvasObjects集合的外部,以及一个用于CanvasLines的内部的:

<ItemsControl ItemsSource="{Binding CanvasObjects}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <ItemsControl ItemsSource="{Binding CanvasLines}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Canvas/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Line Stroke="{Binding StrokeColor}"
                              StrokeDashArray="{Binding StrokeDashArray}"
                              StrokeThickness="{Binding StrokeThickness}">
                            ...
                        </Line>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

由于您显然是以相对坐标绘制线条,因此我建议您进行以下更改。而不是X1,Y1,X2,Y2让CanvasLine有两个点,P1和P2:

public class CanvasLine
{
    public Point P1 { get; set; }
    public Point P2 { get; set; }
    public Brush Stroke { get; set; }
    public double StrokeThickness { get; set; }
    public DoubleCollection StrokeDashArray { get; set; }
}

现在让你的XAML使用带有LineGeometry而不是Line的Path。然后将Transform属性分配给外部ItemsControl资源中的相应ScaleTransform:

<ItemsControl ItemsSource="{Binding CanvasObjects}">
    <ItemsControl.Resources>
        <ScaleTransform x:Key="lineTransform"
            ScaleX="{Binding ActualWidth,
                     RelativeSource={RelativeSource AncestorType=ItemsControl}}"
            ScaleY="{Binding ActualHeight,
                     RelativeSource={RelativeSource AncestorType=ItemsControl}}"/>
    </ItemsControl.Resources>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <ItemsControl ItemsSource="{Binding CanvasLines}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Canvas/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Path Stroke="{Binding Stroke}"
                              StrokeDashArray="{Binding StrokeDashArray}"
                              StrokeThickness="{Binding StrokeThickness}">
                            <Path.Data>
                                <LineGeometry
                                    Transform="{StaticResource lineTransform}"
                                    StartPoint="{Binding P1}"
                                    EndPoint="{Binding P2}"/>
                            </Path.Data>
                        </Path>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>
© www.soinside.com 2019 - 2024. All rights reserved.