在MVVM中将XAML转换为PNG

时间:2018-04-06 14:18:45

标签: c# wpf xaml

如何执行XAML转换(例如整个网格或视图框)到png文件?

我需要从ViewModel级别执行此操作。

Link to the example function我无法在ViewModel中调用,因为我无法访问该对象。

有一种简单而愉快的方式吗?

3 个答案:

答案 0 :(得分:1)

视图将负责根据您链接的答案实际导出您在屏幕上看到的元素。

视图模型应该初始化操作。它可以通过多种不同方式实现。

一种选择是使用事件聚合器或信使向视图发送松散耦合的事件或消息。有关主题的更多信息,请参阅以下博文:http://blog.magnusmontin.net/2014/02/28/using-the-event-aggregator-pattern-to-communicate-between-view-models/

另一个选择是使用对视图的宽松引用注入视图模型。该视图实现了一个接口,并使用构造函数注入或属性注入将自身注入到视图模型中,例如:

public interface IExport
{
    void Export(string filename);
}

public partial class MainWindow : Window, IExport
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new ViewModel(this);
    }

    public void Export(string filename)
    {
        //export...
    }
}

public class ViewModel
{
    private readonly IExport _export;

    public ViewModel(IExport export)
    {
        _export = export;
    }

    public void DoExport()
    {
        //...
        _export.Export("pic.png");
    }
}

这样,视图模型只知道并且在接口上有depdenceny。它不依赖于视图,在单元测试中,您可以轻松提供IExport接口的模拟实现。

视图模型将永远不会有任何对要导出的实际元素的访问权限。这些都属于观点。

答案 1 :(得分:0)

你需要像Interaction这样的东西 - 一种让VM从视图中获取内容的方法。如果您不想为此安装全新的框架,只需使用Func属性:

您的虚拟机:

public Func<string, Bitmap> GetBitmapOfElement {get;set;}
...

//in some command
 var bmp = GetBitmapOfElement("elementName");

然后,在您的视图中,您已为该属性指定了一些内容:

ViewModel.GetBitmapOfElement = elementName =>
{
   var uiElement = FindElementByName(elementName); // this part you have figure out or just always use the same element

  return ExportToPng(FrameworkElement element); // this is the function form the link form your answer modified to return the bitmap instead of saving it to file
}

如果您需要异步,只需将属性类型更改为Func<string, Task<Bitmap>>并在视图中指定异步功能

答案 2 :(得分:0)

依赖属性怎么样?考虑以下用于传递数据的类(数据可能是流或您想要的任何内容):

public class Requester
{
    public event Action DataRequested;

    public object Data { get; set; }

    public void RequestData() => DataRequested?.Invoke();
}

然后创建一个usercontrol并注册请求者类型的依赖项属性

public partial class MyUserControl : UserControl
{
    public static readonly DependencyProperty RequesterProperty
        = DependencyProperty.Register("Requester", typeof(Requester), typeof(MainWindow),
            new PropertyMetadata(default(Requester), OnRequesterChanged));

    public MyUserControl()
    {
        InitializeComponent();
    }

    public Requester Requester
    {
        get => (Requester) GetValue(RequesterProperty);
        set => SetValue(RequesterProperty, value);
    }

    private static void OnRequesterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        => ((Requester) e.NewValue).DataRequested += ((MyUserControl) d).OnDataRequested;

    private void OnDataRequested()
    {
        Requester.Data = "XD";
    }
}

你的视图模型看起来像这样:

public class MainWindowViewModel
{
    public Requester Requester { get; } = new Requester();

    public void RequestData() => Requester.RequestData();
}

在XAML中,您只需将控件的依赖项属性绑定到视图模型中的属性:

<Window x:Class="Test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Test"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:MainWindowViewModel/>
    </Window.DataContext>
    <Grid>
        <local:MyUserControl Requester="{Binding Requester}"/>
    </Grid>
</Window>