HwndHost is not clipped inside ScrollViewer

I created a simple white control with a black border derived from HwndHost (named LightGrid) and added it to ScrollViewer along with some other controls (replaced with “…”) as shown below:

<ScrollViewer HorizontalScrollBarVisibility="Disabled">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            ...
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            ...
        </Grid.RowDefinitions>
        ...
        <Border Grid.Row="6" Grid.ColumnSpan="2" Visibility="Visible" Height="200">
            <nc:LightGrid />
        </Border>
    </Grid>
</ScrollViewer>

It looks correctly in the lower scroll position, and it even can scroll inside ScrollViewer (it moves when I move the scroll bar), but when scrolled, it is not clipped so it obscures other controls:

It looks correctly in the lower scroll position image

There is some solution in the internet based on handling ScrollChangedEvent and manipulation with window region via SetWindowRgn Win32 function. It looks a bit scary and probably in practice it can produce some specific effects, so we should avoid using HwndHost inside ScrollViewer.

Below I provided all the source code of HwndHost based control, it uses some MFC control CHybridCtrl internally:

#pragma once

#include "GridCtrl.h"

using namespace System;
using namespace System::Windows;
using namespace System::Windows::Interop;
using namespace System::Runtime::InteropServices;

namespace NativeControls
{
    public ref class LightGrid : public HwndHost //,IKeyboardInputSink 
    {
    public:

    protected:

        virtual HandleRef BuildWindowCore(HandleRef hwndParent) override;

        virtual void DestroyWindowCore(HandleRef hwnd) override;

        //virtual void OnWindowPositionChanged(Rect rcBoundingBox) override;

    private:

        CHybridCtrl * pGrid = nullptr;
    };

}
#include "stdafx.h"
#include "LightGrid.h"
#include "resource.h"

namespace NativeControls
{
    HandleRef LightGrid::BuildWindowCore(HandleRef hwndParent)
    {
        pGrid = new CHybridCtrl();

        //pGrid->SetStyles(SharedObjects::GetStyles());

        //pGrid->SetTool(ID_EDIT_CELL_SELECT_TOOL);

        HWND hParent = (HWND)hwndParent.Handle.ToPointer();
        
        if (!pGrid->CreateEx(0, WS_CHILD | WS_VISIBLE | WS_BORDER,
            hParent, 1000))
        {
            throw gcnew InvalidOperationException("Can not create CHybridCtrl.");
        }

        return HandleRef(this, IntPtr(pGrid->m_hWnd));
    }

    void LightGrid::DestroyWindowCore(HandleRef hwnd)
    {
        // hwnd will be disposed for us

        delete pGrid;
    }

    //void LightGrid::OnWindowPositionChanged(Rect rcBoundingBox)
    //{
    //    CRect rc(rcBoundingBox.Left, rcBoundingBox.Top, rcBoundingBox.Right, rcBoundingBox.Bottom);
    //    
    //    pGrid->MoveWindow(&rc);
    //}
}

Leave a Reply

Your email address will not be published.