So you can write an app using XAML, WinJS, and DirectX. But is there another option? There is! And it's actually what all of the other more traditional options do under the covers. At the end of the day, some Composition content needs to be hooked up to a CoreWindow. The first step is to create a main
function that will start our CoreApplication
:
static int Main(string[] args)
{
CoreApplication.Run(/* Some IFrameworkViewSource here */);
return 0;
}
The next step is to implement the IFrameworkViewSource
interface. The IFrameworkViewSource
interface isn't that exciting, and it's mainly just a vehicle to create an IFrameworkView
which will actually contain your application. This is done so that you can choose which IFrameworkView
you want to show, or if you have some special way you want to initialize your object. Here is a simple implementation of an IFrameworkViewSource
: (You can also find another example here)
public sealed class MainViewFactory : IFrameworkViewSource
{
IFrameworkView IFrameworkViewSource.CreateView()
{
return new MainView();
}
static int Main(string[] args)
{
CoreApplication.Run(new MainViewFactory());
return 0;
}
}
Here we've moved our main to within the MainViewFactory
and passed in an instance of our factory. The CoreApplication will call our CreateView method, which will create our MainView
which implements IFrameworkView
. The job of our view will be to present our content as well as hold onto our CoreApplicationView
which will be given to us by the caller of our Initialize
method.
class MainView : IFrameworkView
{
void IFrameworkView.Initialize(CoreApplicationView view)
{
_view = view;
}
void IFrameworkView.SetWindow(CoreWindow window)
{
_window = window;
_compositor = new Compositor();
_root = _compositor.CreateContainerVisual();
_compositionTarget = _compositor.CreateTargetForCurrentView();
_compositionTarget.Root = _root;
_spriteVisual = _compositor.CreateSpriteVisual();
_spriteVisual.Size = new Vector2((float)_window.Bounds.Width, (float)_window.Bounds.Height);
_spriteVisual.Brush = _compositor.CreateColorBrush(Colors.Red);
_root.Children.InsertAtTop(_spriteVisual);
_window.SizeChanged += (s, a) =>
{
_spriteVisual.Size = new Vector2((float)_window.Bounds.Width, (float)_window.Bounds.Height);
};
}
void IFrameworkView.Load(string arg)
{
}
void IFrameworkView.Run()
{
_window.Activate();
_window.Dispatcher.ProcessEvents(CoreProcessEventOption.ProcessUntilQuit);
}
private CoreWindow _window;
private CoreApplicationView _view;
private Compositor _compositor;
private ContainerVisual _root;
private SpriteVisual _spriteVisual;
private CompositionTarget _compositionTarget;
}
In order to attach our composition content to our CoreWindow
and to the greater visual tree, we need to create a CompositionTarget
from our current CoreApplicationView
. Whatever we set as the root of our CompositionTarget
will now become the root of our visual tree for this CoreWindow
. All that's left is to activate our CoreWindow
and then to tell the CoreDispatcher
to start processing messages (in terms of a Win32k program, this is essentially our main window message loop). And that's the basis for all UWP applications under the hood. Instead of creating Composition content you could instead use DirectX to create a swapchain for our current view.