private void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    this.router?.Stop();
                    this.deviceManager.Dispose();
                    this.router.Dispose();
                    this.mainWindow.Dispose();
                }

                this.disposed = true;

                try {
                    this.diskManager.Dispose();
                } catch {
                } finally {
                    this.deviceManager = null;
                    this.router        = null;
                    this.diskManager   = null;
                    this.mainWindow    = null;
                }
            }
        }
        /// <summary>
        /// Loads all components and sets up bindings for main window.
        /// Components will be started later in separate threads once
        /// the main window is rendered.
        /// </summary>
        public void Run()
        {
            // initialize main window and get the dispatcher
            this.mainWindow = new MainWindow();
            this.dispatcher = this.mainWindow.Dispatcher;

            // create components
            this.deviceManager = new DeviceManager(this.dispatcher);
            this.router        = new RoutingEngine(this.dispatcher);
            this.playlist      = new PlaylistManager(this.dispatcher);
            this.diskManager   = new RemovableDriveManager();

            // main window needs the PlaylistManager
            this.mainWindow.Playlist = this.playlist;

            // subscribe to component events
            this.mainWindow.Closed             += MainWindowClosed;
            this.mainWindow.ContentRendered    += MainWindowContentRendered;
            this.mainWindow.OpenSettings       += MainWindowOpenSettings;
            this.mainWindow.OpenScheduler      += MainWindowOpenScheduler;
            this.router.RuleProcessed          += RouterRuleProcessed;
            this.playlist.PlaylistChanged      += PlaylistChanged;
            this.deviceManager.ControllerError += ControllerError;
            this.diskManager.DeviceArrived     += DiskManagerDeviceArrived;
            this.diskManager.DeviceRemoved     += DiskManagerDeviceRemoved;
            this.diskManager.QueryRemove       += DiskManagerQueryRemove;

            // initialize devices
            this.deviceManager.ControllersInit();
            this.router.LoadRules();
            this.router.BindControllers(this.deviceManager.Controllers);
            this.router.Start();

            // add all UI elements to the main window
            this.mainWindow.BindDevices(this.deviceManager.Devices);

            // create a control for the routing engine rules
            var routingControl = new Controls.RoutingControl()
            {
                ItemsSource = this.router.Rules,
            };

            routingControl.ListDoubleClick   += RoutingControlListDoubleClick;
            routingControl.ListAddClick      += RoutingControlListAddClick;
            routingControl.ListRemoveClick   += RoutingControlListRemoveClick;
            routingControl.ListMoveItemClick += RoutingControlListMoveItemClick;
            this.mainWindow.InsertControl(routingControl);

            // show the window
            this.mainWindow.Show();
        }