【问题标题】:ReportViewer in MVVM WPFMVVM WPF 中的报表查看器
【发布时间】:2016-06-17 15:21:26
【问题描述】:

我正在使用 Visual Studio 2015 构建一个 MVVM Light WPF 应用程序。该应用程序需要在本地显示一些 SQL Server Reporting Services 报告。

存在以下两种解决方案:

虽然第一个是 MVVM,但它将 UI 与视图模型混合在一起。第二个是纯代码隐藏。

这是第一个示例的建议:

WindowsFormsHost windowsFormsHost = new WindowsFormsHost();
reportViewer = new ReportViewer();
windowsFormsHost.Child = reportViewer;
this.Viewer = windowsFormsHost

请注意,ReportViewer 是一个 UI 控件。第二种解决方案使用代码隐藏文件:

private void ReportViewer_Load(object sender, EventArgs e)
{
   //...
}

有没有办法将本地 SSRS 报告嵌入到 WPF 应用程序中并遵循良好的 MVVM 实践?谢谢。

更新:无需狂热!如果需要一些代码隐藏,我可以接受。

【问题讨论】:

  • UI 关注点属于 UI。在代码隐藏中进行。 MVVM != 没有代码隐藏。
  • 哇,令人难以置信的是没有人回答这个问题。 ://
  • @Xam 我得到了这个工作,明天我在办公室时会发布答案。
  • 亚历克斯,那太棒了。提前致谢。
  • @Xam,请看下面的答案。

标签: c# wpf xaml mvvm reporting-services


【解决方案1】:

我们使用一个视图从ComboBox 中选择报告,并使用一个按钮来运行它。在视图模型中,我们将报告的ComboBox 绑定到报告名称和ID 的ObservableCollection。然后我们使用MVVM Light ToolkitMessaging 类来发送/接收“消息”。请注意,基本视图模型 MyAppViewModelBase 继承自 Light Toolkit 的 ViewModelBase,其中定义了 RaisePropertyChanged()

另外请注意,我们可以传递所选报告的 VM 而不是视图的 VM;这会更有效,但需要修改此代码。然后,我们将使用所有报告 VM 的基类,并在代码隐藏中使用模式匹配开关来选择要运行的报告。

这是视图模型的相关代码:

using GalaSoft.MvvmLight.Messaging;

public class ReportsViewModel : MyAppViewModelBase
{
    public ReportsViewModel()
    {
        // Register a listener that receives the enum of the 
        // report that's ready. The message it receives has 
        // name "SsrsReportReady" with handler SsrsReportReady.
        Messenger.Default.Register<Constants.Report>(this, "SsrsReportReady", SsrsReportReady);

        // Other logic...
    }

    // Bound to a button to run the selected report
    public ICommand RunReportRelayCommand =>
                new RelayCommand(RunReport);

    // Backing field for the selected report.
    private ReportViewModel _selectedReportVm;

    public ReportViewModel SelectedReportVm
    {
        get { return _selectedReportVm; }
        set
        {
            if (Equals(value, _selectedReportVm)) return;
            _selectedReportVm = value;

            // Built-in method from Light Toolkit to 
            // handle INotifyPropertyChanged
            RaisePropertyChanged();  
        }
    }

    private void RunReport()
    {
        // Send a message called "RunSSRSReport" with this VM attached as its data.
        Messenger.Default.Send(this, "RunSSRSReport");
    }

    // Handler for report-ready
    private void SsrsReportReady(Constants.Report obj)
    {
        ShowReport = true;
        IsRunReportButtonEnabled = true;
        RunReportButtonContent = Constants.BtnGenerateReport;

        // View uses Material Design's Expander control.
        // We expand/collapse sections of the view.
        ExpandReport = true;
        ExpandParameters = false;
    }
}

在视图的代码隐藏中:

using GalaSoft.MvvmLight.Messaging;

public partial class ReportsView : UserControl
{
    public ReportsView()
    {
        InitializeComponent();

        // Register a listener for the "RunSSRSReport" 
        // message, called from our viewmodel. Its 
        // handler is RunSsrsReport and its data type 
        // is ReportsViewModel.
        Messenger.Default.Register<ReportsViewModel>(this, "RunSSRSReport", RunSsrsReport);

        DataContext = new ReportsViewModel();
    }

    // Handler to run the selected report. 
    private void RunSsrsReport(ReportsViewModel obj)
    {
        // Basic validation
        if (obj.SelectedReportVm == null || obj.SelectedReportVm.Id.Equals(-1)) 
        {
            return;
        }

        // Ugly switch to run the correct report.
        // It can be re-written with pattern matching.
        switch (obj.SelectedReportVm.Id)
        {
            case (int)Constants.Report.ReportA:
                RunReportA(obj);
                break;
            case (int)Constants.Report.ReportB:
                RunReportB(obj);
                break;
            // other reports....
        }
    }   

    // Run the report using dataset and tableadapter.
    // Modify to use your code for running the report.
    private void RunReportA(ReportsViewModel reportsViewModel)
    {
        var dataSet = new ReportADataSet();
        dataSet.BeginInit();

        // We reference the ReportViewer control in XAML.
        ReportViewer.ProcessingMode = ProcessingMode.Local;
        ReportViewer.LocalReport.ShowDetailedSubreportMessages = true;
        ReportViewer.LocalReport.DataSources.Clear();
        var dataSource = new ReportDataSource
        {
            Name = "ReportA_DS",
            Value = dataSet.uspReportA  // Uses a stored proc
        };
        ReportViewer.LocalReport.DataSources.Add(dataSource);
        ReportViewer.LocalReport.ReportEmbeddedResource =
            "MyApp.Reports.ReportA.rdlc";
        dataSet.EndInit();
        new reportATableAdapter { ClearBeforeFill = true }
            .Fill(dataSet.uspReportA);

        // Send message back to viewmodel that the report is ready.
        Messenger.Default.Send(Constants.Report.ReportA, "SsrsReportReady");
    }
}

报告视图有一个名为ReportViewerWindowsFormsHost,在上面的代码隐藏中引用:

<WindowsFormsHost Width="Auto" Height="500">                   
    <rv:ReportViewer x:Name="ReportViewer" />
</WindowsFormsHost>

【讨论】:

  • 太棒了。我很感激你的回答。非常感谢!
猜你喜欢
  • 2014-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-30
  • 1970-01-01
  • 2016-09-18
相关资源
最近更新 更多