Использование визуального слоя с Windows Forms

Вы можете использовать API композиции среда выполнения Windows (также называемые Visual layer) в приложениях Windows Forms, чтобы создавать современные возможности, которые улучшают взаимодействие для пользователей Windows.

Полный код для этого руководства доступен на GitHub: Windows Forms пример HelloComposition.

Необходимые условия

Для использования хостинг API UWP требуются следующие предварительные условия.

Как использовать API композиции в Windows Forms

В этом руководстве вы создадите простой пользовательский интерфейс Windows Forms и добавьте в него анимированные элементы композиции. Компоненты Windows Forms и композиционные компоненты остаются простыми, но показанный код взаимодействия одинаков независимо от сложности компонентов. Завершенное приложение выглядит следующим образом.

Пользовательский интерфейс выполняющегося приложения

Создание проекта Windows Forms

Первым шагом является создание проекта приложения Windows Forms, который включает определение приложения и основную форму пользовательского интерфейса.

Чтобы создать проект приложения Windows Forms в Visual C# с именем HelloComposition:

  1. Откройте Visual Studio и выберите Файл>Создать>Проект.
    Откроется диалоговое окно "Новый проект ".
  2. В категории Installed разверните узел Visual C# и выберите Windows Desktop.
  3. Выберите шаблон приложения Windows Forms (.NET Framework).
  4. Введите имя HelloComposition, выберите Framework .NET Framework 4.7.2 и щелкните OK.

Visual Studio создает проект и открывает конструктор окна приложения по умолчанию с именем Form1.cs.

Настройка проекта для использования интерфейсов API среды выполнения Windows

Чтобы использовать API среда выполнения Windows (WinRT) в приложении Windows Forms, необходимо настроить проект Visual Studio для доступа к среда выполнения Windows. Кроме того, векторы широко используются API композиции, поэтому необходимо добавить ссылки, необходимые для использования векторов.

Пакеты NuGet доступны для решения обоих этих потребностей. Установите последние версии этих пакетов, чтобы добавить необходимые ссылки на проект.

Note

Хотя мы рекомендуем использовать пакеты NuGet для настройки проекта, вы можете добавить необходимые ссылки вручную. Для получения дополнительной информации см. Улучшение рабочего стола приложения Windows. В следующей таблице показаны файлы, к которым необходимо добавить ссылки.

File Местоположение
System.Runtime.WindowsRuntime C:\Windows\Microsoft.NET\Framework\v4.0.30319
Windows.Foundation.UniversalApiContract.winmd C:\Program Files (x86)\Windows Kits\10\References<sdk version>\Windows. Foundation.UniversalApiContract<version>
Windows.Foundation.FoundationContract.winmd C:\Program Files (x86)\Windows Kits\10\References<sdk version>\Windows. Foundation.FoundationContract<version>
System.Numerics.Vectors.dll C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Numerics.Vectors\v4.0_4.0.0.0__b03f5f7f11d50a3a
System.Numerics.dll C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.7.2

Создание пользовательского элемента управления для управления взаимодействием

Чтобы разместить содержимое, созданное с помощью визуального слоя, создайте пользовательский элемент управления, производный от Control. Этот элемент управления предоставляет доступ к дескриптору окна, который требуется для создания контейнера для содержимого визуального слоя.

Здесь выполняется большая часть конфигурации для развертывания API композиции. В этом элементе управления используются службы Platform Invoke(PInvoke) и COM Interop для добавления API композиции в приложение Windows Forms. Дополнительные сведения о PInvoke и COM-взаимодействии см. в разделе " Взаимодействие с неуправляемыми кодами".

Подсказка

При необходимости сверьтесь с полным кодом в конце руководства, чтобы убедиться в том, что весь код добавлен в соответствующе места при работе с этим руководством.

  1. Добавьте новый файл пользовательского управления в проект, производный от Элемента управления.

    • В обозревателе решений щелкните проект HelloComposition правой кнопкой мыши.
    • В контекстном меню выберите "Добавить>новый элемент"....
    • В диалоговом окне "Добавить новый элемент" выберите "Настраиваемый элемент управления".
    • Присвойте элементу управления CompositionHost.cs, а затем нажмите кнопку "Добавить". CompositionHost.cs откроется в режиме проектирования.
  2. Перейдите в представление кода для CompositionHost.cs и добавьте следующий код в класс.

    // Add
    // using Windows.UI.Composition;
    
    IntPtr hwndHost;
    object dispatcherQueue;
    protected ContainerVisual containerVisual;
    protected Compositor compositor;
    
    private ICompositionTarget compositionTarget;
    
    public Visual Child
    {
        set
        {
            if (compositor == null)
            {
                InitComposition(hwndHost);
            }
            compositionTarget.Root = value;
        }
    }
    
  3. Добавьте код в конструктор.

    В конструкторе вызывается метод InitializeCoreDispatcher и InitComposition . Эти методы создаются на следующих шагах.

    public CompositionHost()
    {
        InitializeComponent();
    
        // Get the window handle.
        hwndHost = Handle;
    
        // Create dispatcher queue.
        dispatcherQueue = InitializeCoreDispatcher();
    
        // Build Composition tree of content.
        InitComposition(hwndHost);
    }
    
  4. Инициализируйте поток с CoreDispatcher. Основной диспетчер отвечает за обработку сообщений окна и отправку событий для API WinRT. Новые экземпляры Compositor должны быть созданы в потоке, который имеет CoreDispatcher.

    • Создайте метод с именем InitializeCoreDispatcher и добавьте код для настройки очереди диспетчера.
    // Add
    // using System.Runtime.InteropServices;
    
    private object InitializeCoreDispatcher()
    {
        DispatcherQueueOptions options = new DispatcherQueueOptions();
        options.apartmentType = DISPATCHERQUEUE_THREAD_APARTMENTTYPE.DQTAT_COM_STA;
        options.threadType = DISPATCHERQUEUE_THREAD_TYPE.DQTYPE_THREAD_CURRENT;
        options.dwSize = Marshal.SizeOf(typeof(DispatcherQueueOptions));
    
        object queue = null;
        CreateDispatcherQueueController(options, out queue);
        return queue;
    }
    
    • Очередь диспетчера требует объявления PInvoke. Поместите это объявление в конце кода для класса. (Мы помещаем этот код в регион, чтобы сохранить код класса в аккуратном виде.)
    #region PInvoke declarations
    
    //typedef enum DISPATCHERQUEUE_THREAD_APARTMENTTYPE
    //{
    //    DQTAT_COM_NONE,
    //    DQTAT_COM_ASTA,
    //    DQTAT_COM_STA
    //};
    internal enum DISPATCHERQUEUE_THREAD_APARTMENTTYPE
    {
        DQTAT_COM_NONE = 0,
        DQTAT_COM_ASTA = 1,
        DQTAT_COM_STA = 2
    };
    
    //typedef enum DISPATCHERQUEUE_THREAD_TYPE
    //{
    //    DQTYPE_THREAD_DEDICATED,
    //    DQTYPE_THREAD_CURRENT
    //};
    internal enum DISPATCHERQUEUE_THREAD_TYPE
    {
        DQTYPE_THREAD_DEDICATED = 1,
        DQTYPE_THREAD_CURRENT = 2,
    };
    
    //struct DispatcherQueueOptions
    //{
    //    DWORD dwSize;
    //    DISPATCHERQUEUE_THREAD_TYPE threadType;
    //    DISPATCHERQUEUE_THREAD_APARTMENTTYPE apartmentType;
    //};
    [StructLayout(LayoutKind.Sequential)]
    internal struct DispatcherQueueOptions
    {
        public int dwSize;
    
        [MarshalAs(UnmanagedType.I4)]
        public DISPATCHERQUEUE_THREAD_TYPE threadType;
    
        [MarshalAs(UnmanagedType.I4)]
        public DISPATCHERQUEUE_THREAD_APARTMENTTYPE apartmentType;
    };
    
    //HRESULT CreateDispatcherQueueController(
    //  DispatcherQueueOptions options,
    //  ABI::Windows::System::IDispatcherQueueController** dispatcherQueueController
    //);
    [DllImport("coremessaging.dll", EntryPoint = "CreateDispatcherQueueController", CharSet = CharSet.Unicode)]
    internal static extern IntPtr CreateDispatcherQueueController(DispatcherQueueOptions options,
                                            [MarshalAs(UnmanagedType.IUnknown)]
                                            out object dispatcherQueueController);
    
    #endregion PInvoke declarations
    

    Теперь у вас есть очередь диспетчера, готовая для инициализации и создания композиционного содержимого.

  5. Инициализируйте Compositor. Compositor — это фабрика, которая создает различные типы в пространстве имен Windows.UI.Composition, охватывающем визуальный слой, систему эффектов и систему анимации. Класс Compositor также управляет жизненным циклом объектов, созданных фабрикой.

    private void InitComposition(IntPtr hwndHost)
    {
        ICompositorDesktopInterop interop;
    
        compositor = new Compositor();
        object iunknown = compositor as object;
        interop = (ICompositorDesktopInterop)iunknown;
        IntPtr raw;
        interop.CreateDesktopWindowTarget(hwndHost, true, out raw);
    
        object rawObject = Marshal.GetObjectForIUnknown(raw);
        compositionTarget = (ICompositionTarget)rawObject;
    
        if (raw == null) { throw new Exception("QI Failed"); }
    
        containerVisual = compositor.CreateContainerVisual();
        Child = containerVisual;
    }
    
    • Для ICompositorDesktopInterop и ICompositionTarget требуются импорты COM. Поместите этот код после класса CompositionHost , но внутри объявления пространства имен.
    #region COM Interop
    
    /*
    #undef INTERFACE
    #define INTERFACE ICompositorDesktopInterop
        DECLARE_INTERFACE_IID_(ICompositorDesktopInterop, IUnknown, "29E691FA-4567-4DCA-B319-D0F207EB6807")
        {
            IFACEMETHOD(CreateDesktopWindowTarget)(
                _In_ HWND hwndTarget,
                _In_ BOOL isTopmost,
                _COM_Outptr_ IDesktopWindowTarget * *result
                ) PURE;
        };
    */
    [ComImport]
    [Guid("29E691FA-4567-4DCA-B319-D0F207EB6807")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface ICompositorDesktopInterop
    {
        void CreateDesktopWindowTarget(IntPtr hwndTarget, bool isTopmost, out IntPtr test);
    }
    
    //[contract(Windows.Foundation.UniversalApiContract, 2.0)]
    //[exclusiveto(Windows.UI.Composition.CompositionTarget)]
    //[uuid(A1BEA8BA - D726 - 4663 - 8129 - 6B5E7927FFA6)]
    //interface ICompositionTarget : IInspectable
    //{
    //    [propget] HRESULT Root([out] [retval] Windows.UI.Composition.Visual** value);
    //    [propput] HRESULT Root([in] Windows.UI.Composition.Visual* value);
    //}
    
    [ComImport]
    [Guid("A1BEA8BA-D726-4663-8129-6B5E7927FFA6")]
    [InterfaceType(ComInterfaceType.InterfaceIsIInspectable)]
    public interface ICompositionTarget
    {
        Windows.UI.Composition.Visual Root
        {
            get;
            set;
        }
    }
    
    #endregion COM Interop
    

Создание пользовательского элемента управления для размещения элементов композиции

Рекомендуется поместить код, который создает и управляет элементами композиции в отдельном элементе управления, наследуемом от CompositionHost. Это позволяет повторно использовать код взаимодействия, созданный в классе CompositionHost.

Здесь создается пользовательский элемент управления, производный от CompositionHost. Этот элемент управления добавляется в панель элементов Visual Studio, чтобы ее можно было добавить в форму.

  1. Добавьте новый пользовательский файл элемента управления в проект, производный от CompositionHost.

    • В обозревателе решений щелкните проект HelloComposition правой кнопкой мыши.
    • В контекстном меню выберите "Добавить>новый элемент"....
    • В диалоговом окне "Добавить новый элемент" выберите "Настраиваемый элемент управления".
    • Присвойте элементу управления CompositionHostControl.cs и нажмите кнопку "Добавить". CompositionHostControl.cs откроется в режиме конструктора.
  2. В области свойств для представления конструктора CompositionHostControl.cs задайте для свойства BackColor значение ControlLight.

    Настройка цвета фона является необязательным. Мы делаем это здесь, чтобы вы могли видеть настраиваемый элемент управления в фоновом режиме формы.

  3. Перейдите в представление кода для CompositionHostControl.cs и обновите объявление класса, чтобы унаследовать его от CompositionHost.

    class CompositionHostControl : CompositionHost
    
  4. Обновите конструктор, чтобы вызвать базовый конструктор.

    public CompositionHostControl() : base()
    {
    
    }
    

Добавление элементов композиции

Благодаря инфраструктуре теперь можно добавить содержимое композиции в пользовательский интерфейс приложения.

В этом примере вы добавляете код в класс CompositionHostControl, который создает и анимирует простой SpriteVisual.

  1. Добавьте элемент композиции.

    В CompositionHostControl.cs добавьте эти методы в класс CompositionHostControl.

    // Add
    // using Windows.UI.Composition;
    
    public void AddElement(float size, float offsetX, float offsetY)
    {
        var visual = compositor.CreateSpriteVisual();
        visual.Size = new Vector2(size, size); // Requires references
        visual.Brush = compositor.CreateColorBrush(GetRandomColor());
        visual.Offset = new Vector3(offsetX, offsetY, 0);
        containerVisual.Children.InsertAtTop(visual);
    
        AnimateSquare(visual, 3);
    }
    
    private void AnimateSquare(SpriteVisual visual, int delay)
    {
        float offsetX = (float)(visual.Offset.X);
        Vector3KeyFrameAnimation animation = compositor.CreateVector3KeyFrameAnimation();
        float bottom = Height - visual.Size.Y;
        animation.InsertKeyFrame(1f, new Vector3(offsetX, bottom, 0f));
        animation.Duration = TimeSpan.FromSeconds(2);
        animation.DelayTime = TimeSpan.FromSeconds(delay);
        visual.StartAnimation("Offset", animation);
    }
    
    private Windows.UI.Color GetRandomColor()
    {
        Random random = new Random();
        byte r = (byte)random.Next(0, 255);
        byte g = (byte)random.Next(0, 255);
        byte b = (byte)random.Next(0, 255);
        return Windows.UI.Color.FromArgb(255, r, g, b);
    }
    

Добавление элемента управления в форму

Теперь, когда у вас есть пользовательский элемент управления для размещения содержимого Composition, вы можете добавить его в пользовательский интерфейс приложения. Здесь вы добавите экземпляр объекта CompositionHostControl, созданного на предыдущем шаге. CompositionHostControl автоматически добавляется в панель элементов Visual Studio в разделе project name Components.

  1. В режиме конструктора Form1.CS добавьте кнопку в пользовательский интерфейс.

    • Перетащите кнопку из панели элементов в Form1. Поместите его в левый верхний угол формы. (См. изображение в начале руководства, чтобы проверить размещение элементов управления.)
    • В области "Свойства" измените свойство Text с button1 на "Добавить элемент композиции".
    • Измените размер кнопки таким образом, чтобы отображались все тексты.

    (Дополнительные сведения см. в разделе How to: Add Controls to Windows Forms.)

  2. Добавьте CompositionHostControl в пользовательский интерфейс.

    • Перетащите элемент CompositionHostControl из панели инструментов на Form1. Поместите его справа от кнопки.
    • Измените размер объекта CompositionHost, чтобы заполнить оставшуюся часть формы.
  3. Обработка события нажатия кнопки.

    • В области "Свойства" щелкните молнию, чтобы перейти в представление "События".
    • В списке событий выберите событие Click, введите Button_Click и нажмите Enter.
    • Этот код добавляется в Form1.cs:
    private void Button_Click(object sender, EventArgs e)
    {
    
    }
    
  4. Добавьте код в обработчик нажатия кнопки для создания новых элементов.

    • В Form1.cs добавьте код в созданный ранее обработчик событий Button_Click . Этот код вызывает CompositionHostControl1.AddElement для создания нового элемента со случайным образом созданным размером и смещением. (Экземпляр CompositionHostControl был автоматически назван compositionHostControl1 при перетаскивании его на форму.)
    // Add
    // using System;
    
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        Random random = new Random();
        float size = random.Next(50, 150);
        float offsetX = random.Next(0, (int)(compositionHostControl1.Width - size));
        float offsetY = random.Next(0, (int)(compositionHostControl1.Height/2 - size));
        compositionHostControl1.AddElement(size, offsetX, offsetY);
    }
    

Теперь вы можете создать и запустить приложение Windows Forms. Щелкнув кнопку, вы увидите анимированные квадраты, добавленные в пользовательский интерфейс.

Дальнейшие действия

Более полный пример, который строится на той же инфраструктуре, см. в примере интеграции Windows Forms visual layer integration в GitHub.

Дополнительные ресурсы

Полный код

Ниже приведен полный код для этого руководства.

Form1.cs

using System;
using System.Windows.Forms;

namespace HelloComposition
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, EventArgs e)
        {
            Random random = new Random();
            float size = random.Next(50, 150);
            float offsetX = random.Next(0, (int)(compositionHostControl1.Width - size));
            float offsetY = random.Next(0, (int)(compositionHostControl1.Height/2 - size));
            compositionHostControl1.AddElement(size, offsetX, offsetY);
        }
    }
}

CompositionHostControl.cs

using System;
using System.Numerics;
using Windows.UI.Composition;

namespace HelloComposition
{
    class CompositionHostControl : CompositionHost
    {
        public CompositionHostControl() : base()
        {

        }

        public void AddElement(float size, float offsetX, float offsetY)
        {
            var visual = compositor.CreateSpriteVisual();
            visual.Size = new Vector2(size, size); // Requires references
            visual.Brush = compositor.CreateColorBrush(GetRandomColor());
            visual.Offset = new Vector3(offsetX, offsetY, 0);
            containerVisual.Children.InsertAtTop(visual);

            AnimateSquare(visual, 3);
        }

        private void AnimateSquare(SpriteVisual visual, int delay)
        {
            float offsetX = (float)(visual.Offset.X);
            Vector3KeyFrameAnimation animation = compositor.CreateVector3KeyFrameAnimation();
            float bottom = Height - visual.Size.Y;
            animation.InsertKeyFrame(1f, new Vector3(offsetX, bottom, 0f));
            animation.Duration = TimeSpan.FromSeconds(2);
            animation.DelayTime = TimeSpan.FromSeconds(delay);
            visual.StartAnimation("Offset", animation);
        }

        private Windows.UI.Color GetRandomColor()
        {
            Random random = new Random();
            byte r = (byte)random.Next(0, 255);
            byte g = (byte)random.Next(0, 255);
            byte b = (byte)random.Next(0, 255);
            return Windows.UI.Color.FromArgb(255, r, g, b);
        }
    }
}

CompositionHost.cs

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Windows.UI.Composition;

namespace HelloComposition
{
    public partial class CompositionHost : Control
    {
        IntPtr hwndHost;
        object dispatcherQueue;
        protected ContainerVisual containerVisual;
        protected Compositor compositor;
        private ICompositionTarget compositionTarget;

        public Visual Child
        {
            set
            {
                if (compositor == null)
                {
                    InitComposition(hwndHost);
                }
                compositionTarget.Root = value;
            }
        }

        public CompositionHost()
        {
            // Get the window handle.
            hwndHost = Handle;

            // Create dispatcher queue.
            dispatcherQueue = InitializeCoreDispatcher();

            // Build Composition tree of content.
            InitComposition(hwndHost);
        }

        private object InitializeCoreDispatcher()
        {
            DispatcherQueueOptions options = new DispatcherQueueOptions();
            options.apartmentType = DISPATCHERQUEUE_THREAD_APARTMENTTYPE.DQTAT_COM_STA;
            options.threadType = DISPATCHERQUEUE_THREAD_TYPE.DQTYPE_THREAD_CURRENT;
            options.dwSize = Marshal.SizeOf(typeof(DispatcherQueueOptions));

            object queue = null;
            CreateDispatcherQueueController(options, out queue);
            return queue;
        }

        private void InitComposition(IntPtr hwndHost)
        {
            ICompositorDesktopInterop interop;

            compositor = new Compositor();
            object iunknown = compositor as object;
            interop = (ICompositorDesktopInterop)iunknown;
            IntPtr raw;
            interop.CreateDesktopWindowTarget(hwndHost, true, out raw);

            object rawObject = Marshal.GetObjectForIUnknown(raw);
            compositionTarget = (ICompositionTarget)rawObject;

            if (raw == null) { throw new Exception("QI Failed"); }

            containerVisual = compositor.CreateContainerVisual();
            Child = containerVisual;
        }

        protected override void OnPaint(PaintEventArgs pe)
        {
            base.OnPaint(pe);
        }

        #region PInvoke declarations

        //typedef enum DISPATCHERQUEUE_THREAD_APARTMENTTYPE
        //{
        //    DQTAT_COM_NONE,
        //    DQTAT_COM_ASTA,
        //    DQTAT_COM_STA
        //};
        internal enum DISPATCHERQUEUE_THREAD_APARTMENTTYPE
        {
            DQTAT_COM_NONE = 0,
            DQTAT_COM_ASTA = 1,
            DQTAT_COM_STA = 2
        };

        //typedef enum DISPATCHERQUEUE_THREAD_TYPE
        //{
        //    DQTYPE_THREAD_DEDICATED,
        //    DQTYPE_THREAD_CURRENT
        //};
        internal enum DISPATCHERQUEUE_THREAD_TYPE
        {
            DQTYPE_THREAD_DEDICATED = 1,
            DQTYPE_THREAD_CURRENT = 2,
        };

        //struct DispatcherQueueOptions
        //{
        //    DWORD dwSize;
        //    DISPATCHERQUEUE_THREAD_TYPE threadType;
        //    DISPATCHERQUEUE_THREAD_APARTMENTTYPE apartmentType;
        //};
        [StructLayout(LayoutKind.Sequential)]
        internal struct DispatcherQueueOptions
        {
            public int dwSize;

            [MarshalAs(UnmanagedType.I4)]
            public DISPATCHERQUEUE_THREAD_TYPE threadType;

            [MarshalAs(UnmanagedType.I4)]
            public DISPATCHERQUEUE_THREAD_APARTMENTTYPE apartmentType;
        };

        //HRESULT CreateDispatcherQueueController(
        //  DispatcherQueueOptions options,
        //  ABI::Windows::System::IDispatcherQueueController** dispatcherQueueController
        //);
        [DllImport("coremessaging.dll", EntryPoint = "CreateDispatcherQueueController", CharSet = CharSet.Unicode)]
        internal static extern IntPtr CreateDispatcherQueueController(DispatcherQueueOptions options,
                                                 [MarshalAs(UnmanagedType.IUnknown)]
                                        out object dispatcherQueueController);

        #endregion PInvoke declarations
    }

    #region COM Interop

    /*
    #undef INTERFACE
    #define INTERFACE ICompositorDesktopInterop
        DECLARE_INTERFACE_IID_(ICompositorDesktopInterop, IUnknown, "29E691FA-4567-4DCA-B319-D0F207EB6807")
        {
            IFACEMETHOD(CreateDesktopWindowTarget)(
                _In_ HWND hwndTarget,
                _In_ BOOL isTopmost,
                _COM_Outptr_ IDesktopWindowTarget * *result
                ) PURE;
        };
    */
    [ComImport]
    [Guid("29E691FA-4567-4DCA-B319-D0F207EB6807")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface ICompositorDesktopInterop
    {
        void CreateDesktopWindowTarget(IntPtr hwndTarget, bool isTopmost, out IntPtr test);
    }

    //[contract(Windows.Foundation.UniversalApiContract, 2.0)]
    //[exclusiveto(Windows.UI.Composition.CompositionTarget)]
    //[uuid(A1BEA8BA - D726 - 4663 - 8129 - 6B5E7927FFA6)]
    //interface ICompositionTarget : IInspectable
    //{
    //    [propget] HRESULT Root([out] [retval] Windows.UI.Composition.Visual** value);
    //    [propput] HRESULT Root([in] Windows.UI.Composition.Visual* value);
    //}

    [ComImport]
    [Guid("A1BEA8BA-D726-4663-8129-6B5E7927FFA6")]
    [InterfaceType(ComInterfaceType.InterfaceIsIInspectable)]
    public interface ICompositionTarget
    {
        Windows.UI.Composition.Visual Root
        {
            get;
            set;
        }
    }
    #endregion COM Interop
}