private void RenderFeaturesChanged(object sender, ItemChangeEventArgs e)
        {
            switch (e.ChangeType)
            {
            case ContentChangeType.None:
                break;

            case ContentChangeType.CollectionAdd:
            {
                RenderFeatures.Insert(e.Index.Int, new RenderFeatureViewModel(this, (RenderFeature)e.NewValue));
                break;
            }

            case ContentChangeType.CollectionRemove:
            {
                RenderFeatures.RemoveAt(e.Index.Int);
                break;
            }

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
        public sealed override Task <bool> Initialize()
        {
            // Add a block that represents entry points
            var entryPointOutputs = new[]
            {
                nameof(GraphicsCompositorAsset.Game),
                nameof(GraphicsCompositorAsset.SingleView),
                nameof(GraphicsCompositorAsset.Editor)
            };
            var entryPoint = new EntryPointBlockViewModel(this, graphicsCompositorNode, entryPointOutputs);

            entryPoint.Initialize();
            entryPoint.UpdateSlots();
            Blocks.Add(entryPoint);

            // Add blocks
            sharedRenderersNode.ItemChanged += SharedRenderersChanged;
            foreach (var sharedRendererNode in sharedRenderersNode.ItemReferences)
            {
                var sharedRenderer = (ISharedRenderer)sharedRendererNode.TargetNode.Retrieve();
                AddSharedRendererViewModel(sharedRenderer);
            }

            // Now that we have all blocks with all slots, we can update all links
            foreach (var block in Blocks)
            {
                foreach (var slot in block.OutputSlots.Cast <GraphicsCompositorSlotViewModel>())
                {
                    slot.UpdateLink();
                }
            }

            // TODO: Relayout the graph?

            // Add render stages
            renderStagesNode.ItemChanged += RenderStagesChanged;
            foreach (var renderStage in (IEnumerable <RenderStage>)renderStagesNode.Retrieve())
            {
                RenderStages.Add(new RenderStageViewModel(this, renderStage));
            }

            // Add render features
            renderFeaturesNode.ItemChanged += RenderFeaturesChanged;
            foreach (var renderFeature in (IEnumerable <RenderFeature>)renderFeaturesNode.Retrieve())
            {
                RenderFeatures.Add(new RenderFeatureViewModel(this, renderFeature));
            }

            // Add camera slots
            cameraSlotsNode.ItemChanged += CamerasSlotsChanged;
            foreach (var cameraSlot in (IEnumerable <SceneCameraSlot>)cameraSlotsNode.Retrieve())
            {
                CameraSlots.Add(new GraphicsCompositorCameraSlotsViewModel(this, cameraSlot));
            }

            // Update property grid on selected events
            SelectedRenderStages.CollectionChanged    += SelectionChanged;
            SelectedRenderFeatures.CollectionChanged  += SelectionChanged;
            SelectedCameraSlots.CollectionChanged     += SelectionChanged;
            SelectedSharedRenderers.CollectionChanged += SelectionChanged;
            SelectedRendererLinks.CollectionChanged   += SelectionChanged;

            // Make selection scope exclusives
            ServiceProvider.Get <SelectionService>().RegisterSelectionScope(id => RenderStages.FirstOrDefault(x => x.Id == id), obj => (obj as RenderStageViewModel)?.Id, SelectedRenderStages);
            ServiceProvider.Get <SelectionService>().RegisterSelectionScope(id => RenderFeatures.FirstOrDefault(x => x.Id == id), obj => (obj as RenderFeatureViewModel)?.Id, SelectedRenderFeatures);
            ServiceProvider.Get <SelectionService>().RegisterSelectionScope(id => CameraSlots.FirstOrDefault(x => x.Id == id), obj => (obj as GraphicsCompositorCameraSlotsViewModel)?.Id, SelectedCameraSlots);
            ServiceProvider.Get <SelectionService>().RegisterSelectionScope(id => Blocks.OfType <GraphicsCompositorBlockViewModel>().FirstOrDefault(x => x.Id == id), obj => (obj as GraphicsCompositorBlockViewModel)?.Id, SelectedSharedRenderers);

            // Update available types for factories
            UpdateAvailableTypes();
            AssemblyRegistry.AssemblyRegistered   += AssembliesUpdated;
            AssemblyRegistry.AssemblyUnregistered += AssembliesUpdated;

            return(Task.FromResult(true));
        }