Uso del livello visivo con Windows Forms
Puoi usare le API di composizione di Windows Runtime (note anche come livello visivo) nelle tue app Windows Forms per creare esperienze moderne disponibili per gli utenti di Windows.
Il codice completo per questa esercitazione è disponibile in GitHub: esempio di Windows Forms HelloComposition.
Prerequisiti
L'API di hosting UWP presenta questi prerequisiti.
- Si presuppone che tu abbia familiarità con lo sviluppo di app con Windows Forms e la piattaforma UWP. Per altre info, vedere:
- .NET Framework 4.7.2 o versioni successive
- Windows 10 versione 1803 o successive
- Windows 10 SDK 17134 o versioni successive
Come usare le API di composizione in Windows Forms
In questa esercitazione creerai una semplice interfaccia utente Windows Forms e vi aggiungerai elementi di composizione animati. Vengono usati componenti di Windows Forms e di composizione semplici, ma il codice di interoperabilità mostrato è lo stesso, indipendentemente dalla complessità dei componenti. L'app completata ha un aspetto simile al seguente.
Creare un progetto Windows Forms
Il primo passaggio consiste nel creare il progetto dell'app Windows Forms, che include una definizione di applicazione e il modulo principale per l'interfaccia utente.
Per creare un nuovo progetto Applicazione Windows Form in Visual C# denominato HelloComposition:
- Apri Visual Studio e seleziona File>Nuovo>Progetto.
Verrà visualizzata la finestra di dialogo Nuovo progetto. - Nella categoria Installati espandi il nodo Visual C# e quindi seleziona Windows Desktop.
- Seleziona il modello App Windows Forms (.NET Framework).
- Immetti il nome HelloComposition, seleziona il framework .NET Framework 4.7.2 e quindi fai clic su OK.
Visual Studio creerà il progetto e aprirà la finestra di progettazione per la finestra dell'applicazione predefinita denominata Form1.cs.
Configurare il progetto per l'uso delle API di Windows Runtime
Per usare le API di Windows Runtime (WinRT) nella tua app Windows Forms, devi configurare il progetto di Visual Studio per l'accesso a Windows Runtime. Poiché inoltre le API di composizione usano ampiamente i vettori, devi aggiungere i riferimenti necessari per l'uso dei vettori.
Sono disponibili pacchetti NuGet per soddisfare entrambe queste esigenze. Installa le versioni più recenti di questi pacchetti per aggiungere al progetto i riferimenti necessari.
- Microsoft.Windows.SDK.Contracts (richiede il formato di gestione pacchetti predefinito impostato su PackageReference).
- System.Numerics.Vectors
Nota
Sebbene sia consigliabile usare i pacchetti NuGet per configurare il progetto, puoi aggiungere manualmente i riferimenti necessari. Per altre informazioni, vedi Migliorare un'applicazione desktop per Windows. La tabella seguente illustra i file a cui devi aggiungere i riferimenti.
file | Location |
---|---|
System.Runtime.WindowsRuntime | C:\Windows\Microsoft.NET\Framework\v4.0.30319 |
Windows.Foundation.UniversalApiContract.winmd | C:\Programmi (x86)\Windows Kits\10\References<versione sdk>\Windows.Foundation.UniversalApiContract<versione> |
Windows.Foundation.FoundationContract.winmd | C:\Programmi (x86)\Windows Kits\10\References<versione sdk>\Windows.Foundation.FoundationContract<versione> |
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:\Programmi (x86)\Reference Assemblies\Microsoft\FrameworkNETFramework\v4.7.2 |
Creare un controllo personalizzato per gestire l'interoperabilità
Per ospitare il contenuto creato con il livello visivo, devi creare un controllo personalizzato derivato da Control. Questo controllo ti consente di accedere a un handle di finestra, necessario per creare il contenitore per il contenuto del livello visivo.
Qui viene eseguita la maggior parte della configurazione per l'hosting delle API di composizione. In questo controllo usi PInvoke (Platform Invocation Services) e l'interoperabilità COM per portare le API di composizione nella tua app Windows Forms. Per altre informazioni su PInvoke e sull'interoperabilità COM, vedi Interoperabilità con codice non gestito.
Suggerimento
Se necessario, controlla il codice completo alla fine dell'esercitazione per assicurarti che tutto il codice sia nelle posizioni corrette man mano che procedi con l'esercitazione.
Aggiungi al progetto un nuovo file controllo personalizzato derivante da Control.
- In Esplora soluzioni fai clic con il pulsante destro del mouse sul progetto HelloComposition.
- Scegli Aggiungi>Nuovo elemento... dal menu di scelta rapida.
- Nella finestra di dialogo Aggiungi nuovo elemento seleziona Controllo personalizzato.
- Assegna al controllo il nome CompositionHost.cs e quindi fai clic su Aggiungi. CompositionHost.cs verrà aperto nella visualizzazione Progettazione.
Passa alla visualizzazione Codice per CompositionHost.cs e aggiungi alla classe il codice seguente.
// 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; } }
Aggiungi il codice al costruttore.
Nel costruttore devi chiamare i metodi InitializeCoreDispatcher e InitComposition. Questi metodi vengono creati nei passaggi successivi.
public CompositionHost() { InitializeComponent(); // Get the window handle. hwndHost = Handle; // Create dispatcher queue. dispatcherQueue = InitializeCoreDispatcher(); // Build Composition tree of content. InitComposition(hwndHost); }
Inizializza un thread con un CoreDispatcher. Il dispatcher di base è responsabile dell'elaborazione dei messaggi finestra e dell'invio di eventi per le API WinRT. Le nuove istanze di Compositor devono essere create in un thread che disponga di un CoreDispatcher.
- Crea un metodo denominato InitializeCoreDispatcher e aggiungi il codice per configurare la coda del dispatcher.
// 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; }
- La coda del dispatcher richiede una dichiarazione PInvoke. Posiziona questa dichiarazione alla fine del codice per la classe. Questo codice viene inserito in un'area per mantenere ordinato il codice della classe.
#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
La coda Dispatcher è ora pronta e puoi iniziare a inizializzare e creare contenuto di composizione.
Inizializza Compositor. Si tratta di una factory che crea un'ampia gamma di tipi nello spazio dei nomi Windows.UI.Composition, dal livello visivo al sistema degli effetti e al sistema di animazione. La classe Compositor gestisce anche la durata degli oggetti creati a partire dalla factory.
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 e ICompositionTarget richiedono importazioni COM. Posiziona questo codice dopo la classe CompositionHost, ma all'interno della dichiarazione dello spazio dei nomi.
#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
Creare un controllo personalizzato per ospitare elementi di composizione
È consigliabile inserire il codice che genera e gestisce gli elementi di composizione in un controllo separato derivante da CompositionHost. In questo modo il codice di interoperabilità creato nella classe CompositionHost rimane riutilizzabile.
Qui puoi creare un controllo personalizzato derivato da CompositionHost. Questo controllo viene aggiunto alla casella degli strumenti di Visual Studio in modo che tu possa aggiungerlo al modulo.
Aggiungi al progetto un nuovo file controllo personalizzato derivante da CompositionHost.
- In Esplora soluzioni fai clic con il pulsante destro del mouse sul progetto HelloComposition.
- Scegli Aggiungi>Nuovo elemento... dal menu di scelta rapida.
- Nella finestra di dialogo Aggiungi nuovo elemento seleziona Controllo personalizzato.
- Assegna al controllo il nome CompositionHostControl.cs e quindi fai clic su Aggiungi. CompositionHostControl.cs verrà aperto nella visualizzazione Progettazione.
Nel riquadro Proprietà della visualizzazione Progettazione per CompositionHostControl.cs imposta la proprietà BackColor su ControlLight.
L'impostazione del colore di sfondo è facoltativa. In questo caso viene eseguita tale impostazione in modo che il controllo personalizzato risalti rispetto allo sfondo del modulo.
Passa alla visualizzazione Codice per CompositionHostControl.cs e aggiorna la dichiarazione della classe in modo che derivi da CompositionHost.
class CompositionHostControl : CompositionHost
Aggiorna il costruttore per chiamare il costruttore di base.
public CompositionHostControl() : base() { }
Aggiungere elementi di composizione
Dopo aver definito l'infrastruttura, ora puoi aggiungere contenuto di composizione all'interfaccia utente dell'app.
Per questo esempio, aggiungi alla classe CompositionHostControl il codice per la creazione e l'animazione di un oggetto SpriteVisual semplice.
Aggiungi un elemento di composizione.
In CompositionHostControl.cs aggiungi questi metodi alla classe 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); }
Aggiungere il controllo al modulo
Ora che disponi di un controllo personalizzato in cui ospitare il contenuto di composizione, puoi aggiungerlo all'interfaccia utente dell'app. Qui devi aggiungere un'istanza del CompositionHostControl creato nel passaggio precedente. CompositionHostControl verrà aggiunto automaticamente alla casella degli strumenti di Visual Studio in Componenti nome progetto.
Nella visualizzazione Progettazione di Form1.CS aggiungi un pulsante all'interfaccia utente.
- Trascina un pulsante dalla casella degli strumenti a Form1. Posizionalo nell'angolo superiore sinistro del modulo. Vedi l'immagine all'inizio dell'esercitazione per verificare il posizionamento dei controlli.
- Nel riquadro Proprietà modifica l'impostazione della proprietà Text da button1 ad Add composition element.
- Ridimensiona il pulsante in modo che venga visualizzato tutto il testo.
Per altre informazioni, vedere Procedura: Aggiungere controlli a Windows Form.
Aggiungi un CompositionHostControl all'interfaccia utente.
- Trascina un CompositionHostControl dalla casella degli strumenti a Form1. Posizionalo a destra del pulsante.
- Ridimensiona CompositionHost in modo che riempia il resto del modulo.
Gestisci l'evento Click del pulsante.
- Nel riquadro Proprietà fai clic sul fulmine per passare alla visualizzazione Eventi.
- Nell'elenco degli eventi seleziona l'evento Click, digita Button_Clicke premi INVIO.
- In Form1.cs viene aggiunto questo codice:
private void Button_Click(object sender, EventArgs e) { }
Aggiungi al gestore dei clic del pulsante il codice per la creazione di nuovi elementi.
- In Form1.cs aggiungi il codice al gestore eventi Button_Click creato in precedenza. Questo codice chiama CompositionHostControl1.AddElement per creare un nuovo elemento con una dimensione e un offset generati in modo casuale. All'istanza di CompositionHostControl è stato assegnato automaticamente il nome compositionHostControl1 quando è stata trascinata nel modulo.
// 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); }
A questo punto puoi compilare ed eseguire l'app Windows Forms. Quando fai clic sul pulsante, dovresti visualizzare alcuni quadrati animati aggiunti all'interfaccia utente.
Passaggi successivi
Per un esempio più completo basato sulla stessa infrastruttura, vedi l'esempio di integrazione del livello visivo di Windows Forms in GitHub.
Risorse aggiuntive
- Introduzione a Windows Forms (.NET)
- Interoperabilità con codice non gestito (.NET)
- Iniziare a usare le app di Windows (piattaforma UWP)
- Migliorare un'applicazione desktop per Windows (piattaforma UWP)
- Spazio dei nomi Windows.UI.Composition (UWP)
Codice completo
Di seguito è riportato il codice completo per questa esercitazione.
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
}