Search code examples
uwpc++-winrt

Where does the ScrollViewer come from?


There is a simple Page (MainPage.xaml)

<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Button x:Name="Button" Content="Button"/>
</Page>

and the Page class is as follow

struct MainPage : PageT<MainPage>
{
  inline static uint32_t SEQ = 0;
  void Dump(FrameworkElement fwk)
  {
    printf("= %ws\n",get_class_name(fwk).data());
    if(fwk.Parent())
      Dump(fwk.Parent().as<FrameworkElement>());
  }  
  MainPage()
  {
    try
    {
      Application::LoadComponent(*this,Uri(L"ms-appx:///MainPage.xaml"));      
      FindName(L"Button").as<UIElement>().LosingFocus([&](IInspectable sender, LosingFocusEventArgs const& args){
        printf("%03d Button::LosingFocus\n",SEQ++);
        if (args.NewFocusedElement())
        {
          printf("  %ws %ws\n",
            get_class_name(args.OldFocusedElement()).data(),
            get_class_name(args.NewFocusedElement()).data());
          Dump(args.NewFocusedElement().as<FrameworkElement>());
        }
        else if (args.OldFocusedElement())
          printf("  %ws null\n",
            get_class_name(args.OldFocusedElement()).data());
        else
          printf("  null null\n");
      });
    }
    catch(hresult_error e)
    {
      printf("MainPage 0x%x %ws\n",int32_t(e.code()),e.message().data());
    }
  }
  hstring GetRuntimeClassName() const override
  {
    return L"MainPage";
  }
};

When the Button is losing focus the output is as follow

000 Button::LosingFocus
  Windows.UI.Xaml.Controls.Button Windows.UI.Xaml.Controls.ScrollViewer
= Windows.UI.Xaml.Controls.ScrollViewer

It seems UWP is trying to refocus to a ScrollViewer which I find nowhere for it. Is it a synthesized one? Many thanks!


Solution

  • Where does the ScrollViewer come from?

    During the testing, it only occurs there is on other control could be focused, and the ScrollViewer should be the visual container that use to render control, And you could find the Button with visual tree helper from the ScrollViewer. And you could use the following code to find the root parent of Button is ScrollViewer.

    public static DependencyObject FindParent(DependencyObject dp)
    {
        DependencyObject parent = null;
        DependencyObject currParent;
        currParent = VisualTreeHelper.GetParent(dp);
    
        do
        {
            parent = currParent;
            // find the next parent
            currParent = VisualTreeHelper.GetParent(currParent);
    
        } while (currParent != null);
    
        return (parent);
    }
    

    Usage

    var parent = FindParent(button);