65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET MVC 和 XAML Web 应用中的服务器端、数据驱动图像渲染

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.75/5 (8投票s)

2010年8月22日

CPOL

5分钟阅读

viewsIcon

36202

本文介绍使用数据绑定的 XAML 进行服务器端图像渲染。您将能够渲染 WPF 控件并使用此技术创建数据绑定的图像可视化。

背景

我只想介绍一下我在 ASP.NET MVC 之上实现的 XamlAsyncController 实现,它将允许您使用 XAML 进行服务器端图像渲染。这使您能够动态生成数据绑定的图像。因此,这将使您能够捕捉到绑定到控制器传递的视图数据或视图模型的 XAML 用户控件的快照,从而根据视图数据/模型生成图像。

如何做到这一点?相关的源代码(查找上面的链接)包含一个 XamlAsyncController 实现和一个相关的 ViewEngine,以使在 ASP.NET MVC 中完成整个任务更加容易。

让我们通过一个例子来更好地说明这一点。

如何从控制器中将带数据绑定的 XAML 渲染为图像?

现在,让我们看看如何在您自己的 ASP.NET 应用程序中使用 XamlAsyncController 实现带数据绑定的 XAML 图像渲染。

让我们看一个简单的场景。让我们从控制器传递一些数据,将 TextBlock 绑定到该数据,然后将其渲染为图像。因此,从客户端 HTML 中,当您有一个类似 <image src="/Home/ShowMessage" /> 的 URL 时,应该会显示 TextBlock 图像。这就是您需要做的。

1 – 让您的 Controller 继承自 XamlAsyncController,并添加一个用于提供图像的异步操作

您需要从您的 ASP.NET MVC 项目创建对 MvcXamlController.Lib.dll 的引用(参见上面的下载)。

如果您查看 HomeController,您会发现 HomeController 继承自 XamlAsyncController,这是一个我实现的自定义 abstract 控制器,它继承自 ASP.NET MVC 2 中已有的 AsyncController(如果您不熟悉异步控制器,阅读有关使用异步控制器)。您只需在 ShowMessageAsync 中调用 StartRendering() 方法,并在 ShowMessageCompleted 中返回 XamlView()

[HandleError]
public class HomeController : XamlAsyncController
{
    public void ShowMessageAsync()
    {
        ViewData["Message"] = "Welcome from Xaml in MVC";
        StartRendering();
    }

    public ActionResult ShowMessageCompleted()
    {
        return XamlView();
    }
}    

2 – 将您的 XAML 文件添加到路径 /Visualizations/{Controller}/{Action}.xaml

一旦您的控制器有了一个如上所示用于提供图像的操作,下一步就是添加一个 XAML 文件。在此之前,它应该位于 /Visualizations/{Controller}/{Action}.xaml 路径下(这相当于在 /Views/{Controller}/{Action}.aspx 路径下添加一个 View)。

题外话: 这会有点棘手。首先,您需要将 WindowsBasePresentationUIPresentationCore DLL 添加到您的 ASP.NET MVC 项目中,这在演示项目中已经完成了。然后,您需要手动将 XAML 文件从其他地方复制到所需路径,因为当您尝试在 ASP.NET MVC 项目中添加新项时,Visual Studio 的“添加新项”对话框不会显示 XAML 文件。

看看我是如何将 ShowMessage.xaml 放在 Visualizations\Home 文件夹下的。

image

这样就完成了。XamlAsyncController 足够智能,可以通过约定从 /Visualizations/{Controller}/{Action}.xaml 位置获取 XAML 文件并将其渲染为图像。当然,在您的 XAML 中,您可以绑定到 ViewData。让我们看看我们的 ShowMessage.xaml

<UserControl x:Class="MvcXamlController.Demo.Visualizations.Home.ShowMessage"
        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"
        Margin="1" Padding="2" Width="300" Height="60"
        mc:Ignorable="d">
    <Grid>
        <Border BorderBrush="Gray" BorderThickness="2"
                Background="WhiteSmoke" CornerRadius="5" Padding="4">
            <StackPanel>
            <TextBlock Text="I am a WPF control rendered as image"/>
            <TextBlock Text="{Binding Message}"/>
            </StackPanel>
        </Border>
    </Grid>
</UserControl>

可以看到,我们将 TextBlockText 属性绑定到我们拥有的 ViewData 中的 Message(好吧,我们之间有一些管道。该库将为 ViewData 设置一个动态包装器作为视图的数据上下文,因此您可以这样绑定)。因此,从客户端 HTML 中,当您有一个类似 <image src="/Home/ShowMessage" /> 的 URL 时,您实际上会在那里看到 TextBlock 渲染的图像,其中包含您从控制器传递的数据作为文本。

进一步

所以,总结一下,对于使用 XAML 进行服务器端图像渲染,您需要

  1. 让您的 Controller 继承自 XamlAsyncController,并添加一个用于提供图像的异步操作
  2. 将您的 XAML 文件添加到 /Visualizations/{Controller}/{Action}.xaml 路径下

该库还支持您直接渲染 WPF 控件,而无需像上面那样保留一个单独的 XAML 视图。现在,让我们看看如何直接渲染普通的 WPF 控件——一个按钮控件和一个仪表盘控件,它们基于您从控制器传递的给定用户值。

image

在此示例中,我使用的仪表盘控件 XAML 是 Codeproject 作者 Evelyn 开发的 Xaml 仪表盘控件 – 功劳归 Evelyn。

看看控制器如何渲染按钮图像和仪表盘图像,在显示的 HTML 页面中。

public class VisualsController : XamlAsyncController
    {
        //Pass view data to Xaml for Guage Control
        public void GuageAsync()
        {
            ViewData["Score"]=200d;
            ViewData["Title"] = "Hello";
            StartRendering();
        }

        public ActionResult GuageCompleted()
        {
            return XamlView();
        }

        //Pass view data to Xaml for Button control
        public void ButtonAsync()
        {
            StartRendering(()=>new Button() { Content="Hello",Height=30, Width=100 });
        }

        public ActionResult ButtonCompleted()
        {
            return XamlView();
        }
     }

我们在这里传递的值(例如 ScoreTitle 等)可以非常轻松地成为您从控制器操作的 Get/Post 请求中获得的数据。不过,现在,让我们保持简单。所以,这是 HTML 页面中的代码。

<h2>Xaml in ASP.NET MVC Demos</h2>
    <h3>Simple Button</h3>
     <image src="/Visuals/Button" />
    <h3>Gauge</h3>
     <image src="/Visuals/Guage" />

这是我们的仪表盘控件的 XAML 定义。注意我们拥有的数据绑定语法,它将 DialTextCurrentValue 绑定到我们从控制器传递的 viewdata

<UserControl x:Class="MvcXamlController.Demo.Visualizations.Dashboard.Guage"
        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:controls="clr-namespace:MvcXamlController.Controls;
		assembly=MvcXamlController.Controls"
        Width="300" Height="300"
        mc:Ignorable="d">
    <Grid>
        <controls:CircularGaugeControl x:Name="myGauge1"
                                        Radius="150"
                                        ScaleRadius="110"
                                        ScaleStartAngle="120"
                                        ScaleSweepAngle="300"
                                        PointerLength="85"
                                        PointerCapRadius="35"
                                        MinValue="0"
                                        MaxValue="1000"
                                        MajorDivisionsCount="10"
                                        MinorDivisionsCount="5"
                                        CurrentValue="{Binding Score}"
                                        ResetPointerOnStartUp="True"
                                        ImageSize="40,50"
                                        RangeIndicatorThickness="8"
                                        RangeIndicatorRadius="120"
                                        RangeIndicatorLightRadius="10"
                                        RangeIndicatorLightOffset="80"
                                        ScaleLabelRadius="90"
                                        ScaleLabelSize="40,20"
                                        ScaleLabelFontSize="10"
                                        ScaleLabelForeground="LightGray"
                                        MajorTickSize="10,3"
                                        MinorTickSize="3,1"
                                        MajorTickColor="LightGray"
                                        MinorTickColor="LightGray"
                                        ImageOffset="-50"
                                        GaugeBackgroundColor="Black"
                                        PointerThickness ="16"
                                        OptimalRangeStartValue="300"
                                        OptimalRangeEndValue="700"
                                        DialTextOffset="40"
                                        DialText="{Binding Title}"
                                        DialTextColor="Black"
                                        >

        </controls:CircularGaugeControl>
    </Grid>
</UserControl>	

所以,就到这里。我们探索了

  1. 如何使用自定义 XAML 视图渲染图像
  2. 如何直接从 WPF 控件渲染图像

请查看相关代码(包含演示和 XamlAsyncController 库),如果您需要,我将在后续帖子中解释 XamlAsyncController 的实际实现以及相关的 ViewEngine。 

祝您服务器端 XAML 图像渲染愉快。最后,别忘了查看我的 .NET 博客,这里有一些有趣的链接: 

© . All rights reserved.