0

Issue how to print a xaml element

How to access printer and print an xaml element. A page choose from navigation view.

I am using winui-3 and c++20. Created a blank app

enter image description here

The idea is only to print my page not the hole window

enter image description here

Tried

I have tried to use PrintManager but it seem not to work with winui3. See source code. I am blank what to do now!

Source code

file: MainWindow.xaml

<?xml version="1.0" encoding="utf-8"?>
<Window
    x:Class="PrintingFrameworkElement.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:PrintingFrameworkElement"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Title="PrintingFrameworkElement">

    <StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
            <TextBlock Text="I should not be printed" Margin="10"/>
            <Button x:Name="myButton" Click="myButton_Click">Print</Button>
        </StackPanel>
        <NavigationView 
            x:Name="NavControl" 
            PaneDisplayMode="LeftCompact"
            IsSettingsVisible="False"
            ItemInvoked="OnNavigationViewItemInvoked">
            <NavigationView.MenuItems>
                <NavigationViewItem Content="Page 1" Icon="Page" Tag="PrintingFrameworkElement.PageOne"/>
            </NavigationView.MenuItems>
            <Frame x:Name="NavContent" Margin="0, 0, 0, 0">
                <!-- NavigationView Content that shpuold be printable-->
            </Frame>
        </NavigationView>
    </StackPanel>
</Window>

file: MainWindow.xaml.h

#pragma once

#include "MainWindow.g.h"

namespace winrt::PrintingFrameworkElement::implementation
{
    struct MainWindow : MainWindowT<MainWindow>
    {
        MainWindow()
        {
            // Xaml objects should not call InitializeComponent during construction.
            // See https://github.com/microsoft/cppwinrt/tree/master/nuget#initializecomponent
        }

        void myButton_Click(IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& args);

        void OnNavigationViewItemInvoked(winrt::Windows::Foundation::IInspectable const& /*sender*/, winrt::Microsoft::UI::Xaml::Controls::NavigationViewItemInvokedEventArgs const& e);
        void NavigateToPage(hstring const& pageName);
    };
}

namespace winrt::PrintingFrameworkElement::factory_implementation
{
    struct MainWindow : MainWindowT<MainWindow, implementation::MainWindow>
    {
    };
}

file: MainWindow.xaml.cpp

#include "pch.h"

#include "MainWindow.xaml.h"
#if __has_include("MainWindow.g.cpp")
#include "MainWindow.g.cpp"
#endif

#include <winrt/Microsoft.UI.Xaml.Printing.h>
#include <winrt/Microsoft.UI.Xaml.Media.Imaging.h>
//#include <winrt/Microsoft.UI.Xaml.Printing.PrintManager.h>
//#include <winrt/Windows.Graphics.Printing.h>

using namespace winrt;
using namespace Microsoft::UI::Xaml;

// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.

namespace winrt::PrintingFrameworkElement::implementation
{
    void MainWindow::myButton_Click(IInspectable const&, RoutedEventArgs const&)
    {
        // Do printing of the FrameworkElement here
        using namespace winrt::Microsoft::UI::Xaml;
        using namespace winrt::Microsoft::UI::Xaml::Printing;

        // Create PrintDocument
        PrintDocument printDoc = PrintDocument();

        // Create a XAML element to print
        auto content = NavContent().Content().as<FrameworkElement>();

        // FIXME: This is not working
        // Exception thrown at 0x00007FFBAD0BFB4C (KernelBase.dll) in PrintingFrameworkElement.exe: WinRT originate error - 0x80040155 : 'Interface not registered'.
        // Exception thrown at 0x00007FFBAD0BFB4C in PrintingFrameworkElement.exe: Microsoft C++ exception: winrt::hresult_error at memory location 0x000000F8A09D9DA8.
        //auto printManager = Windows::Graphics::Printing::PrintManager::GetForCurrentView();

        //// Register for PrintTaskRequested event
        //printManager.PrintTaskRequested([=](Windows::Graphics::Printing::PrintManager const&, Windows::Graphics::Printing::PrintTaskRequestedEventArgs const& args)
        //    {
        //        Windows::Graphics::Printing::PrintTask task = args.Request().CreatePrintTask(L"Print Document",
        //            [](Windows::Graphics::Printing::PrintTask const& sender, Windows::Graphics::Printing::PrintTaskSourceRequestedArgs const& e)
        //            {
        //                e.SetSource(sender.Source());
        //            });
        //    });

        // Start the print process
        //Windows::Graphics::Printing::PrintManager::ShowPrintUIAsync();


        // New approach


        printDoc.Paginate([](IInspectable const&, PaginateEventArgs const& args)
            {
                // Create custom print logic
            });

        printDoc.GetPreviewPage([](IInspectable const&, GetPreviewPageEventArgs const& args)
            {
                // Provide preview page logic
            });

        printDoc.AddPages([](IInspectable const&, AddPagesEventArgs const& args)
            {
                // Add content pages to print
            });
    }
    void MainWindow::OnNavigationViewItemInvoked(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::Controls::NavigationViewItemInvokedEventArgs const& e)
    {
        auto invokedItemContainer = e.InvokedItemContainer().as<winrt::Microsoft::UI::Xaml::Controls::NavigationViewItem>();
        auto tag = winrt::unbox_value_or<hstring>(invokedItemContainer.Tag(), L"");
        auto type = winrt::Windows::UI::Xaml::Interop::TypeName{ tag, winrt::Windows::UI::Xaml::Interop::TypeKind::Metadata };
        NavContent().Navigate(type);
    }
    void MainWindow::NavigateToPage(hstring const& pageName)
    {
        // Find the NavigationViewItem with the specified tag
        for (auto const& item : NavControl().MenuItems())
        {
            if (auto navItem = item.try_as<winrt::Microsoft::UI::Xaml::Controls::NavigationViewItem>())
            {
                if (winrt::unbox_value_or<hstring>(navItem.Tag(), L"") == pageName)
                {
                    // Set the selected item
                    NavControl().SelectedItem(navItem);
                    // Navigate to the page
                    auto type = winrt::Windows::UI::Xaml::Interop::TypeName{ pageName, winrt::Windows::UI::Xaml::Interop::TypeKind::Metadata };
                    NavContent().Navigate(type);
                    return;
                }
            }
        }
    }
}

Updated 2

What s working

  • Getting HWND for active window
// file: MainWindow.xaml.cpp
...
#include <Printmanagerinterop.h>
...
// Manually define CLSID_PrintManager
DEFINE_GUID(CLSID_PrintManager, 0x92788047, 0x3b5e, 0x41c7, 0x86, 0x2e, 0x4c, 0xd3, 0x0d, 0x45, 0xa3, 0x10);
...
    void printFrameworkElement(FrameworkElement const& element)
    {
        using namespace winrt::Windows::Graphics::Printing;
        using namespace Windows::Graphics::Printing;
        using namespace winrt::Microsoft::UI::Xaml::Printing;

        // Retrieve the window handle (HWND) of the current WinUI 3 window.
        // @see https://learn.microsoft.com/en-us/windows/apps/develop/ui-input/retrieve-hwnd
        auto windowNative{ this->m_inner.as<::IWindowNative>() };
        HWND hWnd{ nullptr };
        windowNative->get_WindowHandle(&hWnd);

        if (!hWnd)
        {
            OutputDebugStringW(L"Failed to retrieve the window handle of the current WinUI 3 window.");
            return;
        }

        // Initialize COM library
        HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
        if (FAILED(hr))
        {
            OutputDebugString(L"Failed to initialize COM library.\n");
            return;
        }

        // Create an instance of IPrintManagerInterop
        com_ptr<IPrintManagerInterop> printManagerInterop;
        hr = CoCreateInstance(CLSID_PrintManager, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(printManagerInterop.put()));
        if (FAILED(hr))
        {
            OutputDebugString(L"Failed to create instance of IPrintManagerInterop.\n");
            return;
        }



        // Register for the PrintTaskRequested event
        printManager.PrintTaskRequested({ this, &MainWindow::OnPrintTaskRequested });
    }

Failed to create instance of IPrintManagerInterop. Thinking the problem could be with CLSID_PrintManager!

Download source code

https://github.com/Tirsvad/stackoverflow_79283567

5
  • 1
    You can use the GetForWindow method to get the PrintManager for the specified window. Refer to the Doc:Print from your app Commented Dec 16, 2024 at 5:52
  • @Jeaninez-MSFT Tried something like printManagerInterop->GetForWindow(hWnd, __uuidof(IPrintManagerInterop), printManager); // comes with error But still I do not know how to handle print in winui3 c++ Commented Dec 18, 2024 at 5:20
  • Whether have you refered to the Doc:Print from your app The topic describes how to print from a Windows app. Commented Dec 19, 2024 at 3:09
  • @Jeaninez-MSFT A I am using c++ lots of the documentation is in C3 which I do not know how to translate to c++. Some of the methods requires other attribues and so on... Commented Dec 24, 2024 at 23:26
  • Try to use CLSID_PrintManagerInterop instead of CLSID_PrintManager. Commented Dec 25, 2024 at 2:48

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.