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

Silverlight 报表查看器(使用 View Model (MVVM))

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (20投票s)

2010年10月24日

Ms-PL

3分钟阅读

viewsIcon

158730

downloadIcon

6219

使用 View Model (MVVM) 在 Silverlight 中查看 .rdlc 报表

在 Silverlight 应用程序中查看和打印报表

报表是Silverlight 业务线 (LOB) 应用程序的重要组成部分。虽然 Silverlight 4 确实提供了打印功能,但多页打印仍然具有挑战性。此外,许多企业已经投入了大量资源来学习使用 Visual Studio 中的报表设计器生成报表。

虽然有一些第三方控件可以在 Silverlight 中显示报表,但它们需要付费。此外,有些控件要求您使用完整的 Microsoft SQL Server Reporting Services (SSRS),这对于许多人来说可能不是一个选项。使用 Visual Studio 创建的 .rdlc 报表不需要 SSRS

我们在本文中演示的方法是由 Sushant Pandey 开发的。他在这里 描述了它。此实现的不同之处在于,我们将使用 行为使其完全符合 MVVM (在他的实现中,他使用代码隐藏)。

打印报表

我们将从我几个月前发布的 Simple Silverlight Configurator/Pivot (View Model/MVVM) 开始。

该应用程序允许用户更改性别、体重和年龄选择器,它会动态过滤人员列表。

该应用程序已得到增强,允许用户单击“显示报表查看器”按钮,报表将在弹出窗口中显示。

如果他们单击“打印 PDF 报表”,他们将在弹出窗口中看到一份 PDF 报表。

我实际上更喜欢 报表查看器,因为用户在等待报表呈现时会看到动画。

创建报表

第一步是向项目中添加一个 报表

该项目已经包含以下 Web 服务

[WebMethod]
public List<Person> SearchPeople(string Gender, int AgeHigh, int AgeLow,
    int WeightHigh, int WeightLow)
{
    List<Person> colPeople = new List<Person>();
    
    var result = from objPeople in People.GetPeople().AsQueryable()
                 where objPeople.Age <= AgeHigh
                 where objPeople.Age >= AgeLow
                 where objPeople.Weight <= WeightHigh
                 where objPeople.Weight >= WeightLow
                 select objPeople;
                 
    if (Gender != "All")
    {
        colPeople = (from finalresult in result
                     where finalresult.Gender == Gender
                     select finalresult).ToList();
    }
    else
    {
        colPeople = result.ToList();
    }
    
    return colPeople;
}

我们可以选择该 Web 服务作为报表的数据集。

设计报表后,我们将报表控件放置在 .aspx 页面上。

以下代码用于页面后面的代码,用于接受报表参数,并显示 报表查看器控件 (ShowReportViewer()),或呈现 .pdf 版本 (RenderReport())

public partial class Report : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        // If parameters are passed just render report
        if
            (
            Request.QueryString["Gender"] != null &&
            Request.QueryString["AgeHigh"] != null &&
            Request.QueryString["AgeLow"] != null &&
            Request.QueryString["WeightHigh"] != null &&
            Request.QueryString["WeightLow"] != null
            )
        {
            if (Request.QueryString["ShowReportViewer"] == "False")
            {
                RenderReport();
            }
            else
            {
                if (!Page.IsPostBack)
                {
                    ShowReportViewer(); 
                }
            }
        }
    }
    
    #region RenderReport
    private void RenderReport()
    {
        // CheckBox to see if there is any data
        if (LoadData().Rows.Count > 0)
        {
            LocalReport localReport = new LocalReport();
            localReport.ReportPath = Server.MapPath("~/Report1.rdlc");
            
            ReportDataSource reportDataSource = 
		new ReportDataSource("DataSet1", LoadData());
            localReport.DataSources.Add(reportDataSource);
            
            string reportType = "pdf";
            string mimeType = "application/pdf";
            string encoding;
            string fileNameExtension;
            
            //The DeviceInfo settings should be changed based on the reportType
            //http://msdn2.microsoft.com/en-us/library/ms155397.aspx
            string deviceInfo =
            "<DeviceInfo>" +
            " <OutputFormat>PDF</OutputFormat>" +
            " <PageWidth>8.5in</PageWidth>" +
            " <PageHeight>11in</PageHeight>" +
            " <MarginTop>0.5in</MarginTop>" +
            " <MarginLeft>1in</MarginLeft>" +
            " <MarginRight>1in</MarginRight>" +
            " <MarginBottom>0.5in</MarginBottom>" +
            "</DeviceInfo>";
            
            Warning[] warnings;
            string[] streams;
            byte[] renderedBytes;
            
            //Render the report
            renderedBytes = localReport.Render(
            reportType,
           deviceInfo,
           out mimeType,
           out encoding,
           out fileNameExtension,
           out streams,
           out warnings);
           
            //Clear the response stream and write the bytes to the outputstream
            //Set content-disposition to "attachment" 
            //so that user is prompted to take an action
            //on the file (open or save)
            Response.Clear();
            Response.ContentType = mimeType;
            //Response.AddHeader("content-disposition", 
		"attachment; filename=foo." + fileNameExtension);
            Response.BinaryWrite(renderedBytes);
            Response.End();
        }
        else
        {
            // There were no records returned
            Response.Clear();
            //Response.AddHeader("content-disposition", 
		"attachment; filename=foo." + fileNameExtension);
            Response.Write("No Data");
            Response.End();
        }
    }
    #endregion
    
    #region ShowReportViewer
    private void ShowReportViewer()
    {
        this.ReportViewer1.ProcessingMode = ProcessingMode.Local;
        this.ReportViewer1.LocalReport.ReportPath = Server.MapPath("~/Report1.rdlc");
        ReportViewer1.LocalReport.DataSources.Add(
           new ReportDataSource("DataSet1", LoadData()));
    }
    #endregion

以下方法在运行时为报表提供数据

#region LoadData
private DataTable LoadData()
{
    string Gender = Convert.ToString(Request.QueryString["Gender"]);
    int AgeHigh = Convert.ToInt32(Request.QueryString["AgeHigh"]);
    int AgeLow = Convert.ToInt32(Request.QueryString["AgeLow"]);
    int WeightHigh = Convert.ToInt32(Request.QueryString["WeightHigh"]);
    int WeightLow = Convert.ToInt32(Request.QueryString["WeightLow"]);
    
    var result = from objPeople in People.GetPeople().AsQueryable()
                 where objPeople.Age <= AgeHigh
                 where objPeople.Age >= AgeLow
                 where objPeople.Weight <= WeightHigh
                 where objPeople.Weight >= WeightLow
                 select objPeople;
                 
    if (Gender != "All")
    {
        result = from finalresult in result
                 where finalresult.Gender == Gender
                 select finalresult;
    }
    
    Utility objUtility = new Utility();
    DataTable dt = objUtility.LINQToDataTable(result);
    
    return dt.DefaultView.Table;
}
#endregion

请注意,它使用一个名为 LINQToDataTable 的类,该类将 Linq to SQL 查询转换为报表所需的 DataTable

另请注意,我们实际上并没有将参数传递给 报表查看器 控件。对于 .rdlc 报表,我们只需提供报表的数据。我们必须过滤 Linq 查询才能过滤报表。

设计报表时直接针对 Web 服务方法可能看起来很奇怪,但我们必须在代码隐藏中提供数据。您可以在此站点上找到有关报表查看器控件为何以这种方式设计的原因:http://www.gotreportviewer.com

Silverlight 项目

Silverlight 项目中,我们向 View Model 中添加了 ReportPDFURLReportViewerURL 属性。我们还添加了一个 SetReportUrls 方法,该方法在支持属性更改时触发

private void SetReportUrls()
{
    // Set the Report URLs
    ReportViewerURL = String.Format("{0}Gender={1}&AgeHigh={2}&AgeLow={3}&
			WeightHigh={4}&WeightLow={5}&ShowReportViewer=True",
            GetBaseAddress(), Gender, AgeHigh.ToString(), AgeLow.ToString(), 
			WeightHigh.ToString(), WeightLow.ToString());

    ReportPDFURL = String.Format("{0}Gender={1}&AgeHigh={2}&AgeLow={3}&
			WeightHigh={4}&WeightLow={5}&ShowReportViewer=False",
        GetBaseAddress(), Gender, AgeHigh.ToString(), AgeLow.ToString(), 
			WeightHigh.ToString(), WeightLow.ToString());
} 

我们创建了以下 Behavior,它将打开 HTML 弹出窗口

namespace Behaviors
{
    [System.ComponentModel.Description("Opens an HTML Window")]
    public class HTMLPopupWindow : TargetedTriggerAction<Button>, INotifyPropertyChanged
    {
        #region PopupURL
        public static readonly DependencyProperty PopupURLProperty = 
				DependencyProperty.Register("PopupURL",
            typeof(string), typeof(HTMLPopupWindow), null);
        public string PopupURL
        {
            get
            {
                return (string)base.GetValue(PopupURLProperty);
            }
            set
            {
                base.SetValue(PopupURLProperty, value);
                this.NotifyPropertyChanged("PopupURL");
            }
        }
        #endregion

        #region PopupWidth
        public static readonly DependencyProperty PopupWidthProperty = 
				DependencyProperty.Register("PopupWidth",
            typeof(int), typeof(HTMLPopupWindow), null);
        public int PopupWidth
        {
            get
            {
                return (int)base.GetValue(PopupWidthProperty);
            }
            set
            {
                base.SetValue(PopupWidthProperty, value);
                this.NotifyPropertyChanged("PopupWidth");
            }
        }
        #endregion

        #region PopupHeight
        public static readonly DependencyProperty PopupHeightProperty = 
				DependencyProperty.Register("PopupHeight",
            typeof(int), typeof(HTMLPopupWindow), null);
        public int PopupHeight
        {
            get
            {
                return (int)base.GetValue(PopupHeightProperty);
            }
            set
            {
                base.SetValue(PopupHeightProperty, value);
                this.NotifyPropertyChanged("PopupHeight");
            }
        }
        #endregion

        protected override void OnAttached()
        {
            base.OnAttached();
        }

        protected override void Invoke(object parameter)
        {
            if (true == HtmlPage.IsPopupWindowAllowed)
            {
                System.Text.StringBuilder codeToRun = new System.Text.StringBuilder();
                codeToRun.Append("window.open(");
                codeToRun.Append("\"");
                codeToRun.Append(string.Format("{0}", PopupURL));
                codeToRun.Append("\",");
                codeToRun.Append("\"");
                codeToRun.Append("\",");
                codeToRun.Append("\"");
                codeToRun.Append("width=" + PopupWidth.ToString() + 
				",height=" + PopupHeight.ToString());
                codeToRun.Append(",scrollbars=yes,menubar=no,toolbar=no,resizable=yes");
                codeToRun.Append("\");");
                try
                {
                    HtmlPage.Window.Eval(codeToRun.ToString());
                }
                catch
                {
                    MessageBox.Show("You must enable popups to view reports. 
			Safari browser is not supported.",
                        	"Error", MessageBoxButton.OK);
                }
            }
            else
            {
                MessageBox.Show("You must enable popups to view reports. 
			Safari browser is not supported.",
                    	"Error", MessageBoxButton.OK);
            }
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
        }

        // Utility

        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
        #endregion
    }
}

接下来,我们向 View 添加按钮。

我们向 按钮添加 HTMLPopupWindow Behavior

然后,我们将 PopupURL 绑定到 View Model 中的相应属性,并设置其他参数。

实际上并未在 Silverlight 中打印

此实现的关键在于我们实际上并未在 Silverlight "内部" 打印。但是,最终用户很可能不会在意。他们将拥有所需的功能。作为开发人员,此方法应该允许您以合理的价格提供专业的解决方案。

部署

您将需要使用 ASP.NET 4.0,并在显示报表的 Web 服务器上安装 Microsoft Report Viewer 2010 Redistributable Package

历史

  • 2010 年 10 月 24 日:初始发布
© . All rights reserved.