将WPF画布子元素绑定到ObservableCollection

16

在我的WPF应用程序中,我有一个Canvas画布,在其中进行一些绘图。以前我是在代码后台处理绘图,但现在我已经将所有内容都分解到了一个ViewModel中。这给我带来了一些挑战...

我有几个InkPresenter对象,包含Strokes笔划。以前,我在代码后台将它们作为子元素添加到Canvas中,就像这样:

// Build an InkPresenter: 
var someInkPresenter = BuildInkPresenter(..); 
//_myCanvas is the <Canvas> I want to display it in: 
_myCanvas.Children.Add(someInkPresenter); 

现在 - 不要在包含 _myCanvas 的 XAML 的代码后台中构建 InkPresenter,我需要以不同的方式进行。我想要做的是创建一个 InkPresenter 并将其添加到集合中:

public ObservableCollection<InkPresenter> Drawings;

我的问题现在是如何将Canvas绑定到这个ObservableCollection,并且当添加到集合中时显示InkPresenters。我能否使用数据绑定来实现这一点?

2个回答

23

我认为您可以使用 ItemsControlItemsPanelTemplate 实现此功能。像这样:

<ItemsControl ItemsSource="{Binding YourCollection}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

要了解更多有关这种方法的信息,请参考 Dr.WPF:ItemsControl: A to Z (P is for Panel)


谢谢!听起来很合理。我会看一下的! - stiank81
2
这通常是您采取的方法,但在这种情况下,您可能会遇到问题,因为InkPresenter将不像在代码中添加它们时一样成为Canvas的直接子元素。相反,可视树将在每个InkPresenter项目周围注入一个额外的ContentPresenter。要使此方法起作用,您应该查看从每个InkPresenter中提取实际数据(笔画)并将这些数据的集合存储在VM中。然后,您可以创建一个自定义ItemsControl,覆盖GetContainerForItemOverride以返回一个InkPresenter。 - John Bowen
无法同意你的看法,John...它是一个ItemsControl。它使用UIElement作为默认容器... - Anvaka
1
Anvaka - 不是的。如果你在 Reflector 或 Snoop 中查看 ItemsControl 的实例,你会发现它使用 ContentPresenter(它确实从 UIElement 派生)作为默认容器。即使它使用了基本的 UIElement,它仍然修改了 Stian 原始的 Canvas 可视树。 - John Bowen
3
约翰,我之前已尝试过在发表不同意见之前进行了解 :). InkPresenter是Canvas的直接子级。如果将UIElement添加到显式ItemsControl实例(而不是像ListBox这样的派生类实例)的Items集合中,它将成为项面板的直接子级。如果添加非UI元素,则会被包装在ContentPresenter内。请查看此帖子末尾的表格http://drwpf.com/blog/2008/03/25/itemscontrol-i-is-for-item-container。 - Anvaka

20

Anvaka提出的解决方案很好,但正如John Bowen所指出的那样,如果你想要将你的项目实际绑定到Canvas附加属性中,你需要了解更多。

以下是一个示例,说明如何绑定到Canvas.Left和Canvas.Top:

<ItemsControl ItemsSource="{Binding YourCollection}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemContainerStyle>
        <Style TargetType="ContentPresenter">
            <Setter Property="Canvas.Left" Value="{Binding YourModelLeft}" />
            <Setter Property="Canvas.Top" Value="{Binding YourModelTop}" />
        </Style>
    </ItemsControl.ItemContainerStyle>
</ItemsControl>

顺便说一下,我在这篇问题上找到了解决方案。在尝试了Anvaka的建议后,绑定没有起作用。

希望这能帮助其他寻找同样答案的人。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接