Sdílet prostřednictvím


Step 2: Set up the event handlers

[ This article is for Windows 8.x and Windows Phone 8.x developers writing Windows Runtime apps. If you’re developing for Windows 10, see the latest documentation ]

To continue with setting up DirectX to display a view, let's connect handlers to events. This step builds on the code you already created for the basic flow of your DirectX app using C++ and the Windows Runtime APIs, in Step1: Create and initialize a view.

The code used in this guidance is taken from the DirectX App template in Microsoft Visual Studio 2013. You can find it in the files App.h, App.cpp, DeviceResources.h, and DeviceResources.cpp.

Instructions

In Create and initialize a view, you developed the Initialize and SetWindow methods on the view provider class, which are called by the app when it starts. These required methods attach the new view and window to the app, and map handlers to the Process Lifetime Management (PLM) events that your app supports. The code looks like this:

// The first method called when the IFrameworkView is being created.
void App::Initialize(CoreApplicationView^ applicationView)
{
    // Register event handlers for app lifecycle. This example includes Activated, so that we
    // can make the CoreWindow active and start rendering on the window.
    applicationView->Activated +=
        ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &App::OnActivated);

    CoreApplication::Suspending +=
        ref new EventHandler<SuspendingEventArgs^>(this, &App::OnSuspending);

    CoreApplication::Resuming +=
        ref new EventHandler<Platform::Object^>(this, &App::OnResuming);

    // At this point we have access to the device. 
    // We can create the device-dependent resources.
    m_deviceResources = std::make_shared<DeviceResources>();
}
// Called when the CoreWindow object is created (or re-created).
void App::SetWindow(CoreWindow^ window)
{
    window->SizeChanged += 
        ref new TypedEventHandler<CoreWindow^, WindowSizeChangedEventArgs^>(this, &App::OnWindowSizeChanged);

    window->VisibilityChanged +=
        ref new TypedEventHandler<CoreWindow^, VisibilityChangedEventArgs^>(this, &App::OnVisibilityChanged);

    window->Closed += 
        ref new TypedEventHandler<CoreWindow^, CoreWindowEventArgs^>(this, &App::OnWindowClosed);

    DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();

    currentDisplayInformation->DpiChanged +=
        ref new TypedEventHandler<DisplayInformation^, Object^>(this, &App::OnDpiChanged);

    currentDisplayInformation->OrientationChanged +=
        ref new TypedEventHandler<DisplayInformation^, Object^>(this, &App::OnOrientationChanged);

    DisplayInformation::DisplayContentsInvalidated +=
        ref new TypedEventHandler<DisplayInformation^, Object^>(this, &App::OnDisplayContentsInvalidated);

    // Disable all pointer visual feedback for better performance when touching.
    auto pointerVisualizationSettings = PointerVisualizationSettings::GetForCurrentView();
    pointerVisualizationSettings->IsContactFeedbackEnabled = false; 
    pointerVisualizationSettings->IsBarrelButtonFeedbackEnabled = false;

    m_deviceResources->SetWindow(window);
}

This maps to the set of events we defined in the header on your main app object. From the header file for your DirectX App template app (in this case, App.h):

// Application lifecycle event handlers.
        void OnActivated(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView, Windows::ApplicationModel::Activation::IActivatedEventArgs^ args);
        void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ args);
        void OnResuming(Platform::Object^ sender, Platform::Object^ args);

        // Window event handlers.
        void OnWindowSizeChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ args);
        void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args);
        void OnWindowClosed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CoreWindowEventArgs^ args);

        // Display properties event handlers.
        void OnDpiChanged(Windows::Graphics::Display::DisplayInformation^ sender, Platform::Object^ args);
        void OnOrientationChanged(Windows::Graphics::Display::DisplayInformation^ sender, Platform::Object^ args);
        void OnDisplayContentsInvalidated(Windows::Graphics::Display::DisplayInformation^ sender, Platform::Object^ args);

In this code, you have a handler for view activation: OnActivated. It's called when an app activates the view; that is, when the app view is active in the foreground of the display. In this sample, our code simply activates the associated CoreWindow instance. We have handlers for the PLM suspend and resume events: OnSuspending and OnResuming.

We also have handlers for window visibility and size change events:

  • OnVisibilityChanged is called when the app's main window moves from foreground to background, and vice versa.
  • OnWindowSizeChanged is called when the app's view (window) changes size.
  • OnWindowClosed is called when the user closes the window.

And we have handlers for some display events:

  • OnDpiChanged is called when the display DPI is changed through either the classic Desktop display settings or the new scaling plateau settings for Windows Store apps.
  • OnOrientationChanged is called when the display orientation changes from landscape to portrait, and vice versa. This is an important event to handle.
  • OnDisplayContentsInvalidated is called when the Direct3D graphics device is lost or changed.

Now, you implement these handlers.

First, you define the view activation event handler, OnActivated.

void App::OnActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args)
{
    // Run() won't start until the CoreWindow is activated.
    CoreWindow::GetForCurrentThread()->Activate();
}

As mentioned earlier, you're simply activating the window that the app provided to the instance of the view provider. You can extend this method to generate a splash screen using the SplashScreen object provided by IActivatedEventArgs.SplashScreen, if you're feeling creative.

Now, you define the basic behaviors when OnSuspending and OnResuming are called by the suspend and resume PLM events respectively.

void App::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args)
{
    // Save app state asynchronously after requesting a deferral. Holding a deferral
    // indicates that the application is busy performing suspending operations. Be
    // aware that a deferral may not be held indefinitely. After about five seconds,
    // the app will be forced to exit.
    SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral();

    create_task([this, deferral]()
    {
        m_deviceResources->Trim();

        // Insert your code here.

        deferral->Complete();
    });
}
 
void App::OnResuming(Platform::Object^ sender, Platform::Object^ args)
{
    // Restore any data or state that was unloaded on suspend. By default, data
    // and state are persisted when resuming from suspend. Note that this event
    // does not occur if the app was previously terminated.

    // Insert your code here.
}

Next, you write the code for window's event handlers: OnWindowSizeChanged, OnVisibilityChanged, and OnWindowClosed. (We'll look at what happens in the device resources methods in Step 3: Connect the DirectX swap chain.)

void App::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ args)
{
    m_deviceResources->UpdateForWindowSizeChange();
    m_main->CreateWindowSizeDependentResources();
}
void App::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args)
{
    m_windowVisible = args->Visible;
}

void App::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args)
{
    m_windowClosed = true;
}
void App::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args)
{
    m_windowClosed = true;
}

In OnWindowSizeChanged, you must provide code that will recreate your DirectX swap chain's display size when the window is resized. In this example, you create a private method UpdateForWindowSizeChange, as called in the code earlier. The template's version of this is found in DeviceResources.cpp, in the DeviceResources class implementation.

You must update the graphics resources when the size changes. Add a method like this to your view provider class (or, in this case, its parent class):

void DeviceResources::UpdateForWindowSizeChange()
{
    DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();

    if (m_swapChainPanel == nullptr && (
            m_window->Bounds.Width  != m_outputSize.Width ||
            m_window->Bounds.Height != m_outputSize.Height
        ) || m_swapChainPanel != nullptr && (
            m_swapChainPanel->ActualWidth != m_outputSize.Width ||
            m_swapChainPanel->ActualHeight != m_outputSize.Height
        ) || m_orientation != currentDisplayInformation->CurrentOrientation)

    {
        CreateWindowSizeDependentResources();
    }
}

CreateWindowSizeDependentResources is discussed in Step 3: Connect the DirectX swap chain.

Previous step

Create and initialize a view

Next step

Connect the DirectX swap chain

How to set up your DirectX Windows Store app to display a view

Complete code for a DirectX Windows Store app