New to Telerik Reporting? Download free 30-day trial

How to Customize the WPF Report Viewer

Environment

Product Progress® Telerik® Reporting
Report Viewer WPF

Description

The article explains how to customize the appearance of the WPF Report Viewer

Suggested Workarounds

We'll demonstrate two approaches of using custom commands by the WPF Report Viewer, each one of them executed by clicking a dedicated button on the report viewer's toolbar. In our demo we'll modify the report viewer template for the Office 2019 theme, which by default is located at (TelerikReporting_Installation_Folder)\Wpf\Themes\Office2019\Telerik.ReportViewer.Wpf.xaml. Make sure you merge the resource dictionaries from the XAML files rather than from the default Telerik.ReportViewer.Wpf.Themes assembly. See the article section Setting Customizable Implicit Style for the WPF Report Viewer Example for details. The reason is that we need to modify the XAML files to add new controls and functionality to the viewer.

Let's add two new buttons to the viewer's markup, as shown below::

<ResourceDictionary
    ...
    xmlns:local="clr-namespace:CSharp.NetFramework.WpfIntegrationDemo"> <!-- The namespace for the custom RoutedUICommand -->
    ...
    <!-- Office2019 -->
      ...
    <Style TargetType="telerikReporting:ReportViewer">
        ...
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="telerikReporting:ReportViewer">
                    <Grid x:Name="LayoutRoot">
                        <Border Background="{TemplateBinding Background}"
                    BorderBrush="{TemplateBinding BorderBrush}"
                    BorderThickness="{TemplateBinding BorderThickness}">
                            <Grid Margin="{TemplateBinding Padding}">
                                ...
                                <!-- Toolbar -->
                                <telerikNav:RadToolBar Grid.Row="0" Margin="0">
                                    ...
                                    <telerikNav:RadToolBarSeparator />

                                    <!-- the new Buttons in the ReportViewer's Toolbar -->
                                    <Button x:Name="CustomCommandAButton" Command="{Binding Path=MyCommand, RelativeSource={RelativeSource AncestorType=Window}}">Main Window Command</Button>
                                    <Button x:Name="CustomCommandBButton" Command="local:CustomReportViewerCommands.MyCommand" CommandParameter="Param AAA">RoutedUICommand</Button>

                                    <telerikNav:RadToolBarSeparator />
                                    ...
                                </telerikNav:RadToolBar>
                                ...
                            </Grid>
                        </Border>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>
  1. You may bind the custom control to a property of the main window "Window1" hosting the ReportViewer - the CustomCommandAButton button "Main Window Command" in the above example. Here is how the code behind related to the new custom functionality may look like:
namespace CSharp.NetFramework.WpfIntegrationDemo
{
    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
    using Telerik.Windows.Controls;

    public partial class Window1 : Window
    {

        ...

        public Window1()
        {
            this.InitializeComponent();

            MyCommand = new DelegateCommand(OnMyCommandExecuted);
        }

        private void OnMyCommandExecuted(object obj)
        {
            // YOUR CUSTOM CODE HERE
        }

        public DelegateCommand MyCommand { get; set; }

        ...
}
}

The main drawback of this approach is that you couple the viewer's template with the particular window Window1, which in most cases is not desired.

  1. The better approach is to use the RoutedUICommand. This is applied to the second custom button CustomCommandBButton "RoutedUICommand" in the example. Note that you may easily send parameters with this approach. Here is the sample code for the CustomReportViewerCommands class. Note that in the XAML you need to register the Namespace of the class:
namespace CSharp.NetFramework.WpfIntegrationDemo
{
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;

    public static class CustomReportViewerCommands
    {
        public static RoutedUICommand MyCommand { get; private set; }

        static CustomReportViewerCommands()
        {
            MyCommand = new RoutedUICommand("MyCommand", "MyCommand", typeof(Button));
            var binding = new CommandBinding(MyCommand, OnMyCommandExecuted);
            CommandManager.RegisterClassCommandBinding(typeof(Button), binding);
        }

        private static void OnMyCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
        // YOUR CUSTOM CODE HERE. You may get the command parameter value from 'e.Parameter'
        }
    }
}

You need to implement the proper logic to replace the placeholders denoted with "// YOUR CUSTOM CODE HERE" depending on the exact requirements.

In this article