在 WPF 图像控件之上绘制

Draw Ontop Of Image Control In WPF

我正在努力将旧的 WinForms 项目移植到 WPF,但遇到了障碍。在这个旧的 WinForms 项目中,我使用每秒绘制图像的图片控件。除此之外,我还覆盖了控件 'Paint' 事件,以便在图像已设置后在图像顶部绘制自定义内容。

例如我的代码流程是这样的:

private void timer1_Tick(object sender, System.EventArgs e)
{
    pictureBox1.Load("some/image/path");
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
    var g = e.Graphics;
    // do custom drawing on top of the picture here..
}

WPF 不提供直接的 'Paint' 事件,所以我不确定我应该如何将其正确移植到 WPF 并仍然保持 MVVM 模式。

所以我的问题是:

我的意图是保持传统的 MVVM 模式,但仍然能够在图像加载后绘制到图像上。所有绘图都是从应用程序内部完成的,没有用户与绘图交互。我基本上是在地图图像上实时绘制带有兴趣点的地图。地图是静态的,没有像 Google 的图块那样分成几块,所以我直接从磁盘加载没有问题。

好吧,经过大量的修改,我想出了一个适合我需要的方法。使用 canvas 控件并将其公开到我的视图模型,我可以将各种对象绘制到 canvas 以复制绘图的 WinForm 样式。

因此,对于寻找类似解决方法的其他人,我推荐 canvas 控件。

在干净的 MVVM 方法中,您可以使用带有 Canvas 作为 ItemsPanel 的 ItemsControl 和 ItemTemplate 中的路径控件。 Path 控件绑定到一组适当的视图模型属性,这些属性定义绘图的视觉外观。

<ItemsControl ItemsSource="{Binding Drawings}">
    <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>

视图模型可能是这样的:

public class Drawing
{
    public Geometry Geometry { get; set; }
    public Brush Fill { get; set; }
    public Brush Stroke { get; set; }
    public double StrokeThickness { get; set; }
}

public class ViewModel
{
    public ObservableCollection<Drawing> Drawings { get; set; }
}

可以像下面这样使用。

public MainWindow()
{
    InitializeComponent();

    var vm = new ViewModel();
    vm.Drawings = new ObservableCollection<Drawing>();
    vm.Drawings.Add(new Drawing
        {
            Geometry = new EllipseGeometry(new Point(100, 100), 50, 30),
            Fill = Brushes.LightBlue,
            Stroke = Brushes.Blue,
            StrokeThickness = 2
        });
    vm.Drawings.Add(new Drawing
    {
        Geometry = new RectangleGeometry(new Rect(50, 150, 100, 60)),
        Fill = Brushes.LightGreen,
        Stroke = Brushes.Green,
        StrokeThickness = 2
    });

    DataContext = vm;
}