c# - WPF Canvas Children Bind ObservableCollection 可以包含不同形状和 TextBlocks 的 ViewModel 吗?

标签 c# wpf canvas mvvm data-binding

我正在尝试创建一个 WPF Canvas 控件,它可以绘制形状、曲线和文本 block ,选择和删除它们,所以我能想到的最好方法是使用 MVVM 将 View 模型列表与 Canvas Children 绑定(bind)。

但是,Canvas Children 不能直接绑定(bind)。所以我有点卡住了。浏览了互联网,但没有找到直接的答案。我发现有人建议使用以下方法来实现绑定(bind) Canvas Children,但我无法理解 ViewModels“节点”是什么类型,以及如何将不同的 Shapes、Curves 和 TextBlocks 转换为节点。

任何帮助将不胜感激。提前致谢。

<ItemsControl ItemsSource="{Binding Path=Nodes}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemContainerStyle>
        <Style TargetType="ContentPresenter">
            <Setter Property="Canvas.Left" Value="{Binding Path=XPos}" />
            <Setter Property="Canvas.Top" Value="{Binding Path=YPos}" />
        </Style>
    </ItemsControl.ItemContainerStyle>
</ItemsControl>

最佳答案

你的 View 模型应该包含一个基类 Node定义 XPosYPos特定节点类型的属性和派生类,例如TextNodeShapeNode :

public class Node
{
    public double XPos { get; set; }
    public double YPos { get; set; }
}

public class TextNode : Node
{
    public string Text { get; set; }
}

public class ShapeNode : Node
{
    public Geometry Geometry { get; set; }
    public Brush Stroke { get; set; }
    public Brush Fill { get; set; }
}

public class ViewModel
{
    public ObservableCollection<Node> Nodes { get; } = new ObservableCollection<Node>();
}

在 XAML 中,您将为特定节点类型添加 DataTemplate,如下所示。见Data Templating Overview有关详细信息,请参阅 MSDN 上的文章。
<ItemsControl ItemsSource="{Binding Path=Nodes}">
    <ItemsControl.Resources>
        <DataTemplate DataType="{x:Type local:TextNode}">
            <TextBlock Text="{Binding Text}"/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type local:ShapeNode}">
            <Path Data="{Binding Geometry}" Stroke="{Binding Stroke}" Fill="{Binding Fill}"/>
        </DataTemplate>
    </ItemsControl.Resources>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemContainerStyle>
        <Style TargetType="ContentPresenter">
            <Setter Property="Canvas.Left" Value="{Binding Path=XPos}" />
            <Setter Property="Canvas.Top" Value="{Binding Path=YPos}" />
        </Style>
    </ItemsControl.ItemContainerStyle>
</ItemsControl>

您现在可以将不同的节点添加到主视图模型类的实例,并将窗口的 DataContext 设置为该实例:
public MainWindow()
{
    InitializeComponent();

    var vm = new ViewModel();

    vm.Nodes.Add(new TextNode
    {
        XPos = 50,
        YPos = 100,
        Text = "Hello, World."
    });

    vm.Nodes.Add(new ShapeNode
    {
        XPos = 100,
        YPos = 200,
        Geometry = new EllipseGeometry { RadiusX = 50, RadiusY = 50 },
        Fill = Brushes.Red
    });

    DataContext = vm;
}

如果您希望您的 View 对节点的属性更改使用react,Node 类应该实现 INotifyPropertyChanged 接口(interface)。

如果项目应该是可选择的,则应将 ItemsControl 替换为 ListBox。 ItemContainerStyle 的 TargetType 将是 ListBoxItem,您将绑定(bind)它的 IsSelected属性到您的 Node 类上的适当属性。

关于c# - WPF Canvas Children Bind ObservableCollection 可以包含不同形状和 TextBlocks 的 ViewModel 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39074981/

相关文章:

c# - 保持前端 Angular 5 和后端 Web API 代码分离的简单方法?

WPF 功能区 RibbonCommand 替换为 ICommand

wpf - RichTextBox 并在插入符号位置插入

c# - 后台传输服务/请求

c# - 从 WinForms 中的项目文件夹获取图像路径

mysql - 在十字路口 : Choice Between MySQL vs MSSQL -> Importance: Reporting

jquery - iPhone 上的 HTML5 Canvas 在 touchstart/mousedown 事件上突出显示

javascript - 为什么 chrome 很难在 Canvas 上显示大量图像,而其他浏览器却不能?

c# - 带有 slider 绑定(bind)的 TranslateTransform 不起作用

c# - 如何从表名指定为 SqlParameter 的表中进行选择?