ScrollViewer 从哪里来?

Where does the ScrollViewer come from?

有一个简单的页面(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>

页面class如下

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";
  }
};

当 Button 失去焦点时输出如下

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

似乎 UWP 正试图重新聚焦到 ScrollViewer,但我找不到它的位置。是合成的吗?非常感谢!

Where does the ScrollViewer come from?

在测试过程中,只出现在其他控件上可以被聚焦,ScrollViewer应该是用来呈现控件的可视容器,你可以从中找到带有可视化树助手的按钮ScrollViewer。您可以使用以下代码找到 Button 的根父项是 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);
}

用法

var parent = FindParent(button);