首页 > 解决方案 > 画布上的 MVVM WPF 图像

问题描述

我有一个允许您在屏幕上创建对象的代码,有一个按钮面板,单击您在画布上创建图像/对象的按钮,我无法将另一个图像放置在 Canvas 中,以便可以将多个图像要显示,链接到以前创建的问题:WPF C# Display objects (2d Map)

                    <Thumb.Template>
                        <ControlTemplate TargetType="Thumb">
                            <Canvas>
                                <Image x:Name="injWell" Source="/Resources/injectionWell.png" 
                                          HorizontalAlignment="Center" VerticalAlignment="Center"
                                          Width="40" Height="40"
                                          Stretch="Fill" StretchDirection="Both" IsHitTestVisible="False"/>

                                <Image x:Name="injWellNot" Source="/Resources/injectionWellNot.png" 
                                          HorizontalAlignment="Center" VerticalAlignment="Center"
                                          Width="40" Height="40"
                                          Stretch="Fill" StretchDirection="Both" IsHitTestVisible="False"/>

                                <TextBlock Canvas.Top="-20" Canvas.Left="-40" Width="100" 
                                          TextAlignment="Center" Text="{Binding Name}" FontWeight="Bold"
                                          IsHitTestVisible="False"
                                          Visibility="{Binding DataContext.ShowNames, 
                                          RelativeSource={RelativeSource FindAncestor, AncestorType=Window},
                                          Converter={StaticResource BoolToVisibilityConverter}}"/>

                                <TextBlock Canvas.Left="30" Canvas.Top="10"
                                           Text="{Binding X, StringFormat='{}X = {0}'}"
                                           IsHitTestVisible="False"
                                           Visibility="Collapsed" x:Name="XText"/>

                                <TextBlock Canvas.Left="30" Canvas.Top="25"
                                           Text="{Binding Y, StringFormat='{}Y = {0}'}"
                                           IsHitTestVisible="False"
                                           Visibility="Collapsed" x:Name="YText"/>
                            </Canvas>

                            <ControlTemplate.Triggers>
                                <Trigger Property="IsDragging" Value="True">
                                    <Setter TargetName="injWell" Property="Source" Value="/Resources/injectionWell.png"/>
                                    <Setter TargetName="injWellNot" Property="Source" Value="/Resources/injectionWellNot.png"/>
                                </Trigger>
                                <DataTrigger Binding="{Binding DataContext.ShowAllCoordinates, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" Value="True">
                                    <Setter TargetName="XText" Property="Visibility" Value="Visible"/>
                                    <Setter TargetName="YText" Property="Visibility" Value="Visible"/>
                                </DataTrigger>
                                <MultiDataTrigger>
                                    <MultiDataTrigger.Conditions>
                                        <Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}" Value="True"/>
                                        <Condition Binding="{Binding DataContext.ShowCurrentCoordinates, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" Value="True"/>
                                    </MultiDataTrigger.Conditions>
                                    <Setter TargetName="XText" Property="Visibility" Value="Visible"/>
                                    <Setter TargetName="YText" Property="Visibility" Value="Visible"/>
                                </MultiDataTrigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Thumb.Template>

                </Thumb>
            </DataTemplate> 

标签: c#wpfvisual-studioxamlmvvm

解决方案


这里要实现的关键是您需要呈现项目列表,而在 MVVM 中,您可以使用 ItemsControl 来完成。(您也可以使用 ListView,但它们实现了您几乎肯定不会想要的附加功能,例如项目选择等)。最终,您希望所有图形对象都显示在 Canvas 上,因此您需要覆盖 ItemsPanel 属性并将其中一个放在 ItemsPanelTemplate 中。然后每个元素都需要定位在 Canvas 上,因此您需要设置 ItemContainerStyle 并在那里设置 Canvas.Left 和 Canvas.Top 属性(一个常见的错误是在元素本身上执行此操作,但它们会被放入一个容器,所以你必须这样做)。将所有这些放在一起,您将拥有如下所示的内容:

<ItemsControl ItemsSource="{Binding MyGraphicsViewModels}">

    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>

    <ItemsControl.ItemContainerStyle>
        <Style TargetType="{x:Type ContentPresenter}">
            <Setter Property="Canvas.Left" Value="{Binding X}" />
            <Setter Property="Canvas.Top" Value="{Binding Y}" />
        </Style>
    </ItemsControl.ItemContainerStyle>

</ItemsControl>

因此,MyGraphicsViewModels 通常是您创建的某个基类(例如 BaseGraphicsViewModel)的视图模型中的列表,然后您将其子类化为您想要绘制的所有不同类型的图形项。最后一个难题是添加 DataTemplates 以指定您希望每个视图模型类型如何在视图中表示:

    <DataTemplate DataType="{x:Type vm:DerivedGraphicsObjectViewModel}">
            <Rectangle Fill="Blue" Width="64" Height="64" />
    </DataTemplate>

有关使用触发器而不是 DataTemplates 的更全面的示例,请查看我过去对这个 SO 问题的回答。


推荐阅读