WPF PrintDialog: How to Enable and Detect Selected Page Print Feature?

Jane Jie Chen 506 Reputation points
2025-03-14T18:51:12.8066667+00:00

Our WPF application targets .NET 4.8.

The WPF application can generate run report which include 12 pages.

run report allows print. So far there is no option, and it always prints all 12 pages.

we like to add feature to allow select page numbers and only print those selected pages.

we follow the link:

https://www.thomasclaudiushuber.com/2009/11/24/wpf-printing-how-to-print-a-pagerange-with-wpfs-printdialog-that-means-the-user-can-select-specific-pages-and-only-these-pages-are-printed/

we can select page ranges and print selected page range such as 2-4 pages with following code.

we also like to allow select separated page number and print selected pages.

we know we can set PrintDialog.SelectedPagesEnabled = true.

but we do not know how to detect that PrintDialog selects "Selected Pages" option.

Is there code example to show us how to? Thx!


private async Task PrintReport()

{

PrintDialog printDialog = new PrintDialog();

printDialog.UserPageRangeEnabled = true;

if ( printDialog.ShowDialog() == false )

            return;
```   **if (printDialog.PageRangeSelection == PageRangeSelection.UserPages)**

```go
                    {

                        DocumentPaginator paginator = new PageRangeDocumentPaginator(

                                         DocumentSource.DocumentPaginator,

                                         printDialog.PageRange);

                        //following line get: Fixed page cannot contain another fixed page.

                        //printDialog.PrintDocument(paginator, "PrintReport");

                        for (int pageNumber = Convert.ToInt32(printDialog.PageRange.PageFrom); pageNumber <= Convert.ToInt32(printDialog.PageRange.PageTo); pageNumber++)

                        {

                            printDialog.PrintVisual(paginator.GetPage(pageNumber).Visual, "PrintReport");

                        }

                    }

                    else

                    {

                        printDialog.PrintDocument(DocumentSource.DocumentPaginator, "PrintReport");

                    }
```}

public class PageRangeDocumentPaginator : DocumentPaginator

```swift
{

    private int _startIndex;

    private int _endIndex;

    private DocumentPaginator _paginator;

    public PageRangeDocumentPaginator(DocumentPaginator paginator, PageRange pageRange)

    {

        _startIndex = pageRange.PageFrom - 1;

        _endIndex = pageRange.PageTo - 1;

        _paginator = paginator;

        // Adjust the _endIndex

        _endIndex = Math.Min(_endIndex, _paginator.PageCount - 1);

    }

    //public override DocumentPage GetPage(int pageNumber)

    //{

    //    // Just return the page from the original

    //    // paginator by using the "startIndex"

    //    return _paginator.GetPage(pageNumber + _startIndex);

    //}

    public override DocumentPage GetPage(int pageNumber)

    {

         return _paginator.GetPage(pageNumber - 1);

    }

    public override bool IsPageCountValid

    {

        get { return true; }

    }

    public override int PageCount

    {

        get

        {

            if (_startIndex > _paginator.PageCount - 1)

                return 0;

            if (_startIndex > _endIndex)

                return 0;

            return _endIndex - _startIndex + 1;

        }

    }

    public override Size PageSize

    {

        get { return _paginator.PageSize; }

        set { _paginator.PageSize = value; }

    }

    public override IDocumentPaginatorSource Source

    {

        get { return _paginator.Source; }

    }

}
Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,853 questions
0 comments No comments
{count} votes

Accepted answer
  1. Hongrui Yu-MSFT 5,255 Reputation points Microsoft External Staff
    2025-03-17T09:43:04.05+00:00

    Hi, @Jane Jie Chen. Welcome to Microsoft Q&A. 

    You could refer to the following methods to achieve the effect you want.

    Its core: You could get a VisualBrush through new VisualBrush(paginator.GetPage(pageNumber).Visual), which could be bound to <Rectangle Fill="{Binding VisualBrush}"></Rectangle> for display and printing.

    Create a window to select which pages to print (1. Red border represents selection 2. Click to cancel or select).

    PreviewResultWindow.xaml

        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="4*"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <ScrollViewer   VerticalScrollBarVisibility="Visible" >
            <ItemsControl x:Name="PreViewDataControl"  >
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Button Margin="10" Width="200" Height="150" Click="Button_Click">
                            <Button.Content>
                                <Rectangle Width="200" Height="150" Fill="{Binding PageVisualBrush}"></Rectangle>
                            </Button.Content>
                            <Button.Style>
                                <Style TargetType="Button">
                                    <Setter Property="BorderBrush" Value="Transparent" />
                                    <Setter Property="BorderThickness" Value="0" />
                                    <Style.Triggers>
                                            <!-- Triggered by the check property of DataContext -->
                                        <DataTrigger Binding="{Binding Check}" Value="True">
                                            <Setter Property="BorderBrush" Value="Red" />
                                            <Setter Property="BorderThickness" Value="2" />
                                        </DataTrigger>
                                    </Style.Triggers>
                                </Style>
                            </Button.Style>
                        </Button>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
            </ScrollViewer>
            <Button Grid.Column="1" Content="Confirm" Height="70" Click="Button_Click_1"></Button>
        </Grid>
    

    PreviewResultWindow.xaml.cs

        public partial class PreviewResultWindow : Window
        {
            public PreviewResultWindow()
            {
                InitializeComponent();
            }
    
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                var previewDocument = ((sender as Button).DataContext as PreViewDocument);
                previewDocument.Check = !previewDocument.Check;
            }
    
            private void Button_Click_1(object sender, RoutedEventArgs e)
            {
                this.Close();
            }
        }
    

    Provide binding data for PreviewResultWindow.xaml. PreViewDocument.cs

        public class PreViewDocument : INotifyPropertyChanged
        {
    
            private VisualBrush pageVisualBrush;
            public VisualBrush PageVisualBrush { get { return pageVisualBrush; } set { pageVisualBrush = value; OnPropertyChanged(nameof(PageVisualBrush)); } }
    
            public bool check;
            public bool Check { get { return check; } set { check = value; OnPropertyChanged(nameof(Check)); } }
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected void OnPropertyChanged(string propertyName)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    

    MainWindow.xaml

        <Grid x:Name="MyGrid" Loaded="OnLoaded">
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="6*"/>
            </Grid.RowDefinitions>
            <Button Content="Print" Click="PrintButtonClick"  Margin="10" HorizontalAlignment="Left" Width="75"></Button>
            <DocumentViewer x:Name="viewer" Grid.Row="1"/>
        </Grid>
    

    MainWindow.xaml.cs

        public partial class MainWindow : Window
        {
            private FixedDocument _fixedDocument;
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void OnLoaded(object sender, RoutedEventArgs e)
            {
                // Load the FixedDocument
                var document = new XpsDocument("InputFile.xps", FileAccess.Read);
                var sequence = document.GetFixedDocumentSequence();
                _fixedDocument = sequence.References[0].GetDocument(false);
    
                // Assign it to the viewer
                viewer.Document = _fixedDocument.DocumentPaginator.Source;
            }
    
            private async Task PrintReport()
            {
    
                PrintDialog printDialog = new PrintDialog();
                printDialog.UserPageRangeEnabled = true;
    
                if (printDialog.ShowDialog() == false)
                    return;
    
                //-----------------Solution 1: Print without using PageRangeDocumentPaginator.cs--------------------------
                DocumentPaginator paginator = _fixedDocument.DocumentPaginator;
                ObservableCollection<PreViewDocument> previewDocuments = new ObservableCollection<PreViewDocument>();
    
    
                //Pre-print results
    			//Select All
                for (int pageNumber = 0; pageNumber <= paginator.PageCount - 1; pageNumber++)
                {
                    var previewDocument = new PreViewDocument() { PageVisualBrush = new VisualBrush(paginator.GetPage(pageNumber).Visual), Check = true };
                    previewDocuments.Add(previewDocument);
                }
    			//Range selection
                if (printDialog.PageRangeSelection == PageRangeSelection.UserPages)
                {
                    for (int pageNumber = 0; pageNumber < paginator.PageCount; pageNumber++)
                    {
                        if (pageNumber >= Convert.ToInt32(printDialog.PageRange.PageFrom) - 1 && pageNumber <= Convert.ToInt32(printDialog.PageRange.PageTo) - 1)
                        {
                            continue;
                        }
                        previewDocuments[pageNumber].Check = false;
                    }
                }
    
    
                ConfirmPrintData(previewDocuments);
                var visualBrushs = previewDocuments.Where(p => p.Check == true).Select(p => p.PageVisualBrush).ToList();
    
    
                ExecutePrint(printDialog, visualBrushs);
    
                //--------------------Solution 2: Print using PageRangeDocumentPaginator.cs-----------------------------
                //if (printDialog.PageRangeSelection == PageRangeSelection.UserPages)
                //{
                //    DocumentPaginator paginator = new PageRangeDocumentPaginator(_fixedDocument.DocumentPaginator, printDialog.PageRange);
                //    ObservableCollection<PreViewDocument> previewDocuments = new ObservableCollection<PreViewDocument>();
                //    for (int pageNumber = Convert.ToInt32(printDialog.PageRange.PageFrom); pageNumber <= Convert.ToInt32(printDialog.PageRange.PageTo); pageNumber++)
                //    {
                //        var previewDocument = new PreViewDocument() { PageVisualBrush = new VisualBrush(paginator.GetPage(pageNumber).Visual), Check = true };
                //        previewDocuments.Add(previewDocument);
                //    }
                //    ConfirmPrintData(previewDocuments);
    
                //    var visualBrushs = previewDocuments.Where(p => p.Check == true).Select(p => p.PageVisualBrush).ToList();
                //    ExecutePrint(printDialog, visualBrushs);
                //}
                //else
                //{
                //    printDialog.PrintDocument(_fixedDocument.DocumentPaginator, "PrintReport");
    
                //}
    
                MessageBox.Show("Printing completed");
            }
    
            public void ConfirmPrintData(ObservableCollection<PreViewDocument> previewDocuments)
            {
                PreviewResultWindow previewResultWindow = new PreviewResultWindow();
                previewResultWindow.PreViewDataControl.ItemsSource = previewDocuments;
                previewResultWindow.ShowDialog();
    
            }
    
            private async void PrintButtonClick(object sender, RoutedEventArgs e)
            {
                await PrintReport();
            }
    
            public void ExecutePrint(PrintDialog printDialog,List<VisualBrush> visualBrushes)
            {
                FixedDocument fixedDocument = new FixedDocument();
    
                foreach (var visualBrush in visualBrushes)
                {
                    FixedPage page = new FixedPage();
                    page.Width = printDialog.PrintableAreaWidth;
                    page.Height = printDialog.PrintableAreaHeight;
    
                    // VisualBrush as rectangle content
                    Rectangle rect = new Rectangle
                    {
                        Width = page.Width,
                        Height = page.Height,
                        Fill = visualBrush
                    };
    
                    // Add to FixedPage
                    page.Children.Add(rect);
    
                    // Adding PageContent to FixedDocument
                    PageContent pageContent = new PageContent();
                    ((IAddChild)pageContent).AddChild(page);
                    fixedDocument.Pages.Add(pageContent);
                }
    
                // Printing FixedDocument
                printDialog.PrintDocument(fixedDocument.DocumentPaginator, "Print Report");
            }
    }
    

    In the above code, VisualBrush uses ExecutePrint() to print; VisualBrush uses ConfirmPrintData() to open the PreviewResultWindow.xaml dialog box to display data and let the user select the print result. You could adjust the PreviewResultWindow according to your own preferences to make the selection in a certain way.


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.