/// <inheritdoc />
        public async Task <bool> ComposeAsync(IViewCompositionContext context)
        {
            try
            {
                DataContextLoadedCompletion = new TaskCompletionSource <object>();
                SetCoordinationArguments(context.Control, context.CoordinationArguments);

                Log.Debug($"Composition is being configured.");
                Configure(context);

                Log.Debug($"Attaching DataContextChanged and Unload events.");
                context.Control.DataContextChanged -= DataContextChanged;
                context.Control.DataContextChanged += DataContextChanged;

                // memory leak countermeasure
                context.Control.Unloaded += ControlOnUnloaded;

                Log.Debug($"Finalizing composition.");
                await FinalizeCompositionAsync(context);

                await BehaviorRunner.ExecuteAsync(context.DataContext as IBehaviorHost, new ViewComposedBehaviorContext(context, ServiceContext));

                await DataContextLoadedCompletion.Task;

                return(true);
            }
            catch (Exception e)
            {
                Log.Error(e);
                return(false);
            }
        }
        /// <inheritdoc />
        protected override void Configure(IViewCompositionContext context)
        {
            if (context.Control is Window window)
            {
                if (context.DataContext is IWindowViewModel windowViewModel)
                {
                    window.SizeToContent = windowViewModel.SizeToContent;
                    window.ShowInTaskbar = windowViewModel.ShowInTaskbar;

                    windowViewModel.WhenFocusRequested.Subscribe(o => window.Focus());
                    windowViewModel.WhenClosingRequested.Subscribe(o => window.Close());
                    windowViewModel.WhenMinimizeRequested.Subscribe(o => window.WindowState  = WindowState.Minimized);
                    windowViewModel.WhenMaximizeRequested.Subscribe(o => window.WindowState  = WindowState.Maximized);
                    windowViewModel.WhenNormalizeRequested.Subscribe(o => window.WindowState = WindowState.Normal);

                    window.WhenClosing().Subscribe(args =>
                    {
                        if (windowViewModel is IWindowListener listener)
                        {
                            listener.NotifyClosing(args);
                        }
                    });

                    window.WhenStateChanged().Throttle(TimeSpan.FromMilliseconds(50)).Subscribe(args =>
                    {
                        if (windowViewModel is IWindowListener listener)
                        {
                            listener.NotifyWindowStateChange(args);
                        }
                    });

                    window.WhenLocationChanged().Throttle(TimeSpan.FromMilliseconds(50)).Subscribe(args =>
                    {
                        if (windowViewModel is IWindowListener listener)
                        {
                            listener.NotifyLocationChanged(args);
                        }
                    });

                    window.WhenSizeChanged().Throttle(TimeSpan.FromMilliseconds(50)).Subscribe(args =>
                    {
                        if (windowViewModel is IWindowListener listener)
                        {
                            listener.NotifySizeChanged(args);
                        }
                    });

                    window.WhenClosed().Subscribe(async(args) =>
                    {
                        if (windowViewModel is IWindowListener listener)
                        {
                            listener.NotifyClosed();
                        }

                        await BehaviorRunner.ExecuteAsync(windowViewModel as IBehaviorHost, new WindowClosedContext(windowViewModel, ServiceContext.ServiceProvider, context));
                    });
                }
            }
        }
        private async void DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            try
            {
                if (sender is FrameworkElement element)
                {
                    Log.Debug($"DataContext has changed.");
                    element.DataContextChanged -= DataContextChanged;
                    if (element.DataContext is IServiceProviderHolder holder)
                    {
                        Log.Debug($"ServiceProvider set through {nameof(IServiceProviderHolder)}.");
                        holder.ServiceProvider = ServiceContext.ServiceProvider;
                    }

                    if (element.DataContext is IWindowViewModel windowViewModel)
                    {
                        if (windowViewModel.Content is IServiceProviderHolder subHolder)
                        {
                            subHolder.ServiceProvider = ServiceContext.ServiceProvider;
                        }
                    }

                    if (element.DataContext is IDefaultBehaviorProvider behaviourProvider && element.DataContext is IBehaviorHost interactiveBehaviour)
                    {
                        var behaviours = behaviourProvider.GetDefaultBehaviors().ToArray();
                        if (behaviours.Length > 0)
                        {
                            Log.Debug($"Binding {behaviours.Length} behaviours through {nameof(IDefaultBehaviorProvider)} [{string.Join(".", behaviours.Select(s => s.GetType().ToString()))}].");
                        }

                        interactiveBehaviour.Behaviors.AddRange(behaviours);
                    }

                    foreach (var hook in ComposerHooks)
                    {
                        Log.Debug($"Executing [{nameof(IViewComposerHook)}] -> [{hook.GetType().ToString()}]");
                        hook.Execute(element, element.DataContext);
                    }

                    await BehaviorRunner.ExecuteAsync(element.DataContext as IBehaviorHost, new ActivationBehaviorContext(element.DataContext, ServiceContext.ServiceProvider));

                    var coordinationArguments = GetCoordinationArguments(element);

                    if (element.DataContext is ICompositionListener listener)
                    {
                        listener.Execute(new ViewCompositionContext(element, element.DataContext, coordinationArguments));
                    }

                    DataContextLoaded(new ViewCompositionContext(element, element.DataContext, coordinationArguments));
                }

                DataContextLoadedCompletion.TrySetResult(true);
            }
            catch (Exception exception)
            {
                DataContextLoadedCompletion.TrySetException(exception);
            }
        }