In this post I demonstrate how the methods of a DocumentViewer class may be invoked via MVVM / WPF in order to modify the way an embedded PowerPoint presentation is displayed.
Step 1: Create a new WPF application
Step 2: Create the Main Window view
Just a simple view to house the DocumentViewer control and a button with which to tell it to launch the PowerPoint presentation.
We will fill in the various command binding a bit later.
<Window x:Class="DocumentView.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:DocumentView"
mc:Ignorable="d"
WindowState="{Binding WindowState, Mode=TwoWay}"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<DocumentViewer
Grid.Row="0"
Document="{Binding FixedFixedDocumentSequence}"
Name="DocumentViewPowerPoint"
VerticalAlignment="Top"
HorizontalAlignment="Left" />
<Button
Grid.Row="1"
Command="{Binding Command}"
Width="70" Height="30" Content="Press" />
</Grid>
</Window>
Step 3: Add the event handling classes
EventArgs.cs
using System;
namespace DocumentView
{
public class EventArgs<T> : EventArgs
{
public EventArgs(T value)
{
Value = value;
}
public T Value { get; private set; }
}
}
EventRaiser.cs
using System;
namespace DocumentView
{
public static class EventRaiser
{
public static void Raise(this EventHandler handler, object sender)
{
if (handler != null)
{
handler(sender, EventArgs.Empty);
}
}
public static void Raise<T>(this EventHandler<EventArgs<T>> handler, object sender, T value)
{
if (handler != null)
{
handler(sender, new EventArgs<T>(value));
}
}
public static void Raise<T>(this EventHandler<T> handler, object sender, T value) where T : EventArgs
{
if (handler != null)
{
handler(sender, value);
}
}
public static void Raise<T>(this EventHandler<EventArgs<T>> handler, object sender, EventArgs<T> value)
{
if (handler != null)
{
handler(sender, value);
}
}
}
}
RelayCommand.cs
using System;
using System.Windows.Input;
namespace DocumentView
{
public class RelayCommand<T> : ICommand
{
private readonly Predicate<T> _canExecute;
private readonly Action<T> _execute;
public RelayCommand(Action<T> execute)
: this(execute, null)
{
_execute = execute;
}
public RelayCommand(Action<T> execute, Predicate<T> canExecute)
{
if (execute == null)
{
throw new ArgumentNullException("execute");
}
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute((T)parameter);
}
public void Execute(object parameter)
{
_execute((T)parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
public class RelayCommand : ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _execute;
public RelayCommand(Action<object> execute)
: this(execute, null)
{
_execute = execute;
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
{
throw new ArgumentNullException("execute");
}
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
// Ensures WPF commanding infrastructure asks all RelayCommand objects whether their
// associated views should be enabled whenever a command is invoked
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
CanExecuteChangedInternal += value;
}
remove
{
CommandManager.RequerySuggested -= value;
CanExecuteChangedInternal -= value;
}
}
private event EventHandler CanExecuteChangedInternal;
public void RaiseCanExecuteChanged()
{
CanExecuteChangedInternal.Raise(this);
}
}
}
Step 4: Create the ViewModel classes
MainWindowViewModel.cs
using System;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Xps.Packaging;
using Microsoft.Office.Core;
using Microsoft.Office.Interop.PowerPoint;
using Application = Microsoft.Office.Interop.PowerPoint.Application;
using System.Windows.Documents;
using System.Windows.Input;
namespace DocumentView
{
public class MainWindowViewModel : ViewModelBase
{
private ICommand _command;
private DocumentViewer _documentViewer;
public DocumentViewer DocumentViewer
{
get
{
return _documentViewer;
}
set
{
_documentViewer = value;
OnPropertyChanged("DocumentViewer");
}
}
private IDocumentPaginatorSource _fixedDocumentSequence;
public IDocumentPaginatorSource FixedFixedDocumentSequence
{
get
{
return _fixedDocumentSequence;
}
set
{
_fixedDocumentSequence = value;
OnPropertyChanged("DocViewer");
}
}
public ICommand Command
{
get
{
return _command ?? (_command = new RelayCommand(
x =>
{
DocumentViewer = MainWindow.GetInstance();
const string powerPointFile = @"c:\temp\ppt.pptx";
var xpsFile = Path.GetTempPath() + Guid.NewGuid() + ".xps";
var xpsDocument = ConvertPowerPointToXps(powerPointFile, xpsFile);
FixedFixedDocumentSequence = xpsDocument.GetFixedDocumentSequence();
DocumentViewer.Document = FixedFixedDocumentSequence;
DocumentViewer.GoToPage(1);
DocumentViewer.FitToMaxPagesAcross(1);
WindowState = WindowState.Maximized;
DocumentViewer.FitToMaxPagesAcross(1);
}));
}
}
private WindowState _windowState;
public WindowState WindowState
{
get
{
return _windowState;
}
set
{
_windowState = value;
base.OnPropertyChanged("WindowState");
}
}
public MainWindowViewModel()
{
FixedFixedDocumentSequence = null;
WindowState = WindowState.Maximized;
}
private static XpsDocument ConvertPowerPointToXps(string pptFilename, string xpsFilename)
{
var pptApp = new Application();
var presentation = pptApp.Presentations.Open(pptFilename, MsoTriState.msoTrue, MsoTriState.msoFalse,
MsoTriState.msoFalse);
try
{
presentation.ExportAsFixedFormat(xpsFilename, PpFixedFormatType.ppFixedFormatTypeXPS);
}
catch (Exception ex)
{
MessageBox.Show("Failed to export to XPS format: " + ex);
}
finally
{
presentation.Close();
pptApp.Quit();
}
return new XpsDocument(xpsFilename, FileAccess.Read);
}
}
}
ViewModelBase.cs
using System.ComponentModel;
namespace DocumentView
{
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
Step 5: Add the references
Office
Microsoft.Office.Interop.PowerPoint
Reach Framework
Step 6: Update MainWindow.xaml.cs
using System.Windows.Controls;
namespace DocumentView
{
public partial class MainWindow
{
private static DocumentViewer _docViewer;
public MainWindow()
{
InitializeComponent();
_docViewer = DocumentViewPowerPoint;
}
public static DocumentViewer GetInstance()
{
return _docViewer;
}
}
}
Step 7: Run the code
On building and running the app we see the empty DocumentViewer control as shown:
Pressing the button converts the PowerPoint into xps file format and the view property is applied so that the whole slide id displayed completely:
Download sample Visual Studio 2015 project from here: