将Shapes.Path项绑定到ItemsControl

时间:2015-06-10 17:39:52

标签: c# wpf mvvm prism

我一直试图弄清楚如何将ObservableCollection<FrameworkElements>绑定到ItemsControl。我有一个现有的项目,它严重依赖于后面的代码和canvas没有绑定,我试图更新以使用mvvm和prism。

ObservableCollection将填充许多Path项。它们是由我使用的外部库生成的。当我手动操作画布本身时,库正常运行。

以下是ViewModel的代码片段:

    ObservableCollection<FrameworkElement> _items;
    ObservableCollection<FrameworkElement> Items
    {
        get { return _items; }
        set
        {
            _items = value;
            this.NotifyPropertyChanged("Items");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

支持XAML

    <ItemsControl ItemsSource="{Binding Items}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas x:Name="canvas" IsItemsHost="True">
                        <Canvas.Background>
                            <SolidColorBrush Color="White" Opacity="100"/>
                        </Canvas.Background>

                    </Canvas>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Path/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

我遇到的问题是Path永远不会画画。关于我哪里出错以及从哪里开始调试过程的任何建议?

2 个答案:

答案 0 :(得分:1)

您的视图模型应包含Path的抽象表示,例如

public class PathData
{
    public Geometry Geometry { get; set; }
    public Brush Fill { get; set; }
    public Brush Stroke { get; set; }
    public double StrokeThickness { get; set; }
    // ... probably more Stroke-related properties
}

如果你现在有一个PathData对象的集合,比如

public ObservableCollection<PathData> Paths { get; set; }

您的ItemsControl可以有一个ItemsTemplate,如下所示:

<ItemsControl ItemsSource="{Binding Paths}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Path Data="{Binding Geometry}" Fill="{Binding Fill}"
                  Stroke="{Binding Stroke}" StrokeThickness="{Binding StrokeThickness}"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

您现在可以像这样添加PathData实例:

Paths.Add(new PathData
{
    Geometry = new RectangleGeometry(new Rect(100, 100, 100, 100)),
    Fill = Brushes.AliceBlue,
    Stroke = Brushes.Red,
    StrokeThickness = 2
});

答案 1 :(得分:0)

ObservableCollection<FrameworkElement>是的,你可以到此为止。那不是MVVM。此外,您将项目模板定义为(空白,我猜你可以说)路径对象。您不会将它绑定到您在可观察集合中抛出的路径的属性。

更好的实施方法是让ObservableCollection<string>包含路径 数据 ,AKA the stuff that actually defines the path's shape,然后绑定走你的路。

<ItemsControl ItemsSource="{Binding Items}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas x:Name="canvas" IsItemsHost="True" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Path Data="{Binding}"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

如果您在运行时使用过Snoop检查UI,那么您已经看到有很多Path对象,但它们都有空数据。

另外,如果您使用血腥画布作为路径形状,则需要在路径上设置Canvas.LeftCanvas.Top附加属性。真正的MVVM英雄将如此定义模型

public PathData{
    public double Left {get;set;}
    public double Top {get;set;}
    public string Data {get;set;}
}

然后在ViewModel中公开这些

public ObservableCollection<PathData> Items {get;private set;}

然后将您的路径绑定到他们

<ItemsControl.ItemTemplate>
    <DataTemplate>
        <Path Canvas.Left="{Binding Left}"
              Canvas.Top="{Binding Top}"
              Data="{Binding Data}"/>
    </DataTemplate>
</ItemsControl.ItemTemplate>