绑定的形状.将项路径到ItemsControl

本文关键字:路径 ItemsControl 绑定 | 更新日期: 2023-09-27 17:54:55

我一直在试图找出如何将ObservableCollection<FrameworkElements>绑定到ItemsControl。我有一个现有的项目,严重依赖于代码背后和画布的没有绑定,我试图更新使用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>

我所经历的问题是,路径从来没有绘制。任何建议在哪里我错了,从哪里开始调试过程?

绑定的形状.将项路径到ItemsControl

你的视图模型应该包含一个路径的抽象表示,例如

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
});

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

一个更好的实现是有一个ObservableCollection<string>包含路径data, AKA的东西,实际上定义了路径的形状,然后绑定这个到你的路径。

<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;}

然后将您的Path绑定到它们

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