/// <summary>
        /// Binds the asynchronous.
        /// </summary>
        /// <param name="game">The game.</param>
        /// <returns>Task.</returns>
        protected virtual async Task BindAsync(IGame game = null)
        {
            await TriggerOverlayAsync(true, localizationManager.GetResource(LocalizationResources.Installed_Mods.LoadingMods));

            if (game == null)
            {
                game = gameService.GetSelected();
            }
            ModFilePopulationInCompleted = false;
            ActiveGame = game;
            if (game != null)
            {
                var mods = await Task.Run(() => modService.GetInstalledMods(game));

                await Task.Run(async() =>
                {
                    await PopulateModFilesAsyncAsync(mods).ConfigureAwait(false);
                    ModFilePopulationInCompleted = true;
                    EvalAchievementCompatibility(mods);
                });

                await Task.Delay(100);

                Mods    = mods.ToObservableCollection();
                AllMods = Mods.ToHashSet();
                var invalidMods = AllMods.Where(p => !p.IsValid);
                if (invalidMods.Count() > 0)
                {
                    await RemoveInvalidModsPromptAsync(invalidMods).ConfigureAwait(false);
                }
                var searchString = FilterMods.Text ?? string.Empty;
                FilteredMods = Mods.Where(p => p.Name.Contains(searchString, StringComparison.InvariantCultureIgnoreCase) ||
                                          (p.RemoteId.HasValue && p.RemoteId.GetValueOrDefault().ToString().Contains(searchString))).ToObservableCollection();
                AllModsEnabled = FilteredMods.Where(p => p.IsValid).Count() > 0 && FilteredMods.Where(p => p.IsValid).All(p => p.IsSelected);

                if (Disposables != null)
                {
                    modChanged?.Dispose();
                    modChanged = null;
                    modChanged = Mods.ToSourceList().Connect().WhenPropertyChanged(s => s.IsSelected).Subscribe(s =>
                    {
                        if (!checkingState)
                        {
                            CheckModEnabledStateAsync().ConfigureAwait(false);
                        }
                    }).DisposeWith(Disposables);
                }

                var state = appStateService.Get();
                InitSortersAndFilters(state);

                ApplyDefaultSort();
            }
            else
            {
                Mods    = FilteredMods = new System.Collections.ObjectModel.ObservableCollection <IMod>();
                AllMods = Mods.ToHashSet();
            }
            await TriggerOverlayAsync(false);
        }
        /// <summary>
        /// check mod enabled state as an asynchronous operation.
        /// </summary>
        protected virtual async Task CheckModEnabledStateAsync()
        {
            checkingState = true;
            await Task.Delay(50);

            AllModsEnabled = FilteredMods.Where(p => p.IsValid).Any() && FilteredMods.Where(p => p.IsValid).All(p => p.IsSelected);
            checkingState  = false;
        }
        /// <summary>
        /// Sorts the function.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sortProp">The sort property.</param>
        /// <param name="dictKey">The dictionary key.</param>
        protected virtual void SortFunction <T>(Func <IMod, T> sortProp, string dictKey)
        {
            if (FilteredMods != null)
            {
                var           sortOrder = sortOrders[dictKey];
                IComparer <T> comparer  = ResolveComparer <T>(dictKey);
                switch (sortOrder.SortOrder)
                {
                case Implementation.SortOrder.Asc:
                    if (comparer != null)
                    {
                        FilteredMods = FilteredMods.OrderBy(sortProp, comparer).ToObservableCollection();
                        AllMods      = AllMods.OrderBy(sortProp, comparer).ToHashSet();
                    }
                    else
                    {
                        FilteredMods = FilteredMods.OrderBy(sortProp).ToObservableCollection();
                        AllMods      = AllMods.OrderBy(sortProp).ToHashSet();
                    }
                    SelectedMod = null;
                    break;

                case Implementation.SortOrder.Desc:
                    if (comparer != null)
                    {
                        FilteredMods = FilteredMods.OrderByDescending(sortProp, comparer).ToObservableCollection();
                        AllMods      = AllMods.OrderByDescending(sortProp, comparer).ToHashSet();
                    }
                    else
                    {
                        FilteredMods = FilteredMods.OrderByDescending(sortProp).ToObservableCollection();
                        AllMods      = AllMods.OrderByDescending(sortProp).ToHashSet();
                    }
                    SelectedMod = null;
                    break;

                default:
                    break;
                }
                foreach (var sort in sortOrders.Where(p => p.Value != sortOrder))
                {
                    sort.Value.SetSortOrder(Implementation.SortOrder.None);
                }
                SaveState();
            }
        }
        /// <summary>
        /// Called when [activated].
        /// </summary>
        /// <param name="disposables">The disposables.</param>
        protected override void OnActivated(CompositeDisposable disposables)
        {
            // Set default order and sort order text
            var state = appStateService.Get();

            InitSortersAndFilters(state);

            Bind();

            this.WhenAnyValue(v => v.ModNameSortOrder.IsActivated, v => v.ModVersionSortOrder.IsActivated, v => v.ModSelectedSortOrder.IsActivated).Where(s => s.Item1 && s.Item2 && s.Item3)
            .Subscribe(s =>
            {
                Observable.Merge(ModNameSortOrder.SortCommand.Select(_ => ModNameKey),
                                 ModVersionSortOrder.SortCommand.Select(_ => ModVersionKey),
                                 ModSelectedSortOrder.SortCommand.Select(_ => ModSelectedKey)).Subscribe(s =>
                {
                    ApplySort(s);
                }).DisposeWith(disposables);
            }).DisposeWith(disposables);

            OpenUrlCommand = ReactiveCommand.CreateFromTask(async() =>
            {
                var url = GetHoveredModUrl();
                if (!string.IsNullOrWhiteSpace(url))
                {
                    await appAction.OpenAsync(url).ConfigureAwait(true);
                }
            }).DisposeWith(disposables);

            CopyUrlCommand = ReactiveCommand.CreateFromTask(async() =>
            {
                var url = GetHoveredModUrl();
                if (!string.IsNullOrWhiteSpace(url))
                {
                    await appAction.CopyAsync(url).ConfigureAwait(true);
                }
            }).DisposeWith(disposables);

            OpenInSteamCommand = ReactiveCommand.CreateFromTask(async() =>
            {
                var url = GetHoveredModSteamUrl();
                if (!string.IsNullOrWhiteSpace(url))
                {
                    await appAction.OpenAsync(url).ConfigureAwait(true);
                }
            }).DisposeWith(disposables);

            OpenInAssociatedAppCommand = ReactiveCommand.CreateFromTask(async() =>
            {
                if (!string.IsNullOrWhiteSpace(HoveredMod?.FullPath))
                {
                    await appAction.OpenAsync(HoveredMod.FullPath).ConfigureAwait(true);
                }
            }).DisposeWith(disposables);

            this.WhenAnyValue(s => s.FilterMods.Text).Subscribe(s =>
            {
                var searchString = FilterMods.Text ?? string.Empty;
                FilteredMods     = Mods?.Where(p => p.Name.Contains(searchString, StringComparison.InvariantCultureIgnoreCase) ||
                                               (p.RemoteId.HasValue && p.RemoteId.GetValueOrDefault().ToString().Contains(searchString))).ToObservableCollection();
                AllModsEnabled = FilteredMods != null && FilteredMods.Where(p => p.IsValid).Any() && FilteredMods.Where(p => p.IsValid).All(p => p.IsSelected);
                ApplyDefaultSort();
                SaveState();
            }).DisposeWith(disposables);

            EnableAllCommand = ReactiveCommand.Create(() =>
            {
                if (FilteredMods?.Count() > 0)
                {
                    PerformingEnableAll = true;
                    bool enabled        = FilteredMods.Where(p => p.IsValid).All(p => p.IsSelected);
                    foreach (var item in FilteredMods)
                    {
                        item.IsSelected = !enabled;
                    }
                    AllModsEnabled      = FilteredMods.Where(p => p.IsValid).Any() && FilteredMods.Where(p => p.IsValid).All(p => p.IsSelected);
                    PerformingEnableAll = false;
                }
            }).DisposeWith(disposables);

            DeleteDescriptorCommand = ReactiveCommand.CreateFromTask(async() =>
            {
                if (HoveredMod != null)
                {
                    await DeleteDescriptorAsync(new List <IMod>()
                    {
                        HoveredMod
                    }).ConfigureAwait(true);
                }
            }).DisposeWith(disposables);

            DeleteAllDescriptorsCommand = ReactiveCommand.CreateFromTask(async() =>
            {
                if (FilteredMods != null)
                {
                    await DeleteDescriptorAsync(FilteredMods).ConfigureAwait(true);
                }
            }).DisposeWith(disposables);

            LockDescriptorCommand = ReactiveCommand.CreateFromTask(async() =>
            {
                if (HoveredMod != null)
                {
                    await LockDescriptorAsync(new List <IMod>()
                    {
                        HoveredMod
                    }, true).ConfigureAwait(true);
                }
            }).DisposeWith(disposables);

            LockAllDescriptorsCommand = ReactiveCommand.CreateFromTask(async() =>
            {
                if (FilteredMods != null)
                {
                    await LockDescriptorAsync(FilteredMods, true).ConfigureAwait(true);
                }
            }).DisposeWith(disposables);

            UnlockDescriptorCommand = ReactiveCommand.CreateFromTask(async() =>
            {
                if (HoveredMod != null)
                {
                    await LockDescriptorAsync(new List <IMod>()
                    {
                        HoveredMod
                    }, false).ConfigureAwait(true);
                }
            }).DisposeWith(disposables);

            UnlockAllDescriptorsCommand = ReactiveCommand.CreateFromTask(async() =>
            {
                if (FilteredMods != null)
                {
                    await LockDescriptorAsync(FilteredMods, false).ConfigureAwait(true);
                }
            }).DisposeWith(disposables);

            CheckNewModsCommand = ReactiveCommand.CreateFromTask(async() =>
            {
                await CheckNewModsAsync().ConfigureAwait(true);
            }).DisposeWith(disposables);

            base.OnActivated(disposables);
        }
        /// <summary>
        /// Binds the asynchronous.
        /// </summary>
        /// <param name="game">The game.</param>
        /// <param name="skipOverlay">if set to <c>true</c> [skip overlay].</param>
        /// <returns>Task.</returns>
        protected virtual async Task BindAsync(IGame game = null, bool skipOverlay = false)
        {
            var raiseGameChanged = game != null;

            GameChangedRefresh = false;
            var id = idGenerator.GetNextId();

            if (!skipOverlay)
            {
                await TriggerOverlayAsync(id, true, localizationManager.GetResource(LocalizationResources.Installed_Mods.LoadingMods));
            }
            if (game == null)
            {
                game = gameService.GetSelected();
            }
            ModFilePopulationCompleted = false;
            ActiveGame = game;
            if (game != null)
            {
                if (raiseGameChanged)
                {
                    GameChangedRefresh = true;
                }
                var mods = await Task.Run(async() => await modService.GetInstalledModsAsync(game));

                await Task.Run(async() =>
                {
                    await PopulateModFilesAsyncAsync(mods).ConfigureAwait(false);
                    ModFilePopulationCompleted = true;
                    EvalAchievementCompatibility(mods);
                });

                await Task.Delay(100);

                Mods    = mods.ToObservableCollection();
                AllMods = Mods.ToHashSet();
                var invalidMods = AllMods.Where(p => !p.IsValid);
                if (invalidMods.Any())
                {
                    await Dispatcher.UIThread.SafeInvokeAsync(async() =>
                    {
                        await RemoveInvalidModsPromptAsync(invalidMods).ConfigureAwait(false);
                    });
                }
                var searchString = FilterMods.Text ?? string.Empty;
                FilteredMods   = modService.FilterMods(Mods, searchString).ToObservableCollection();
                AllModsEnabled = FilteredMods.Where(p => p.IsValid).Any() && FilteredMods.Where(p => p.IsValid).All(p => p.IsSelected);

                if (Disposables != null)
                {
                    modChanged?.Dispose();
                    modChanged = null;
                    modChanged = Mods.ToSourceList().Connect().WhenPropertyChanged(s => s.IsSelected).Subscribe(s =>
                    {
                        if (!checkingState)
                        {
                            CheckModEnabledStateAsync().ConfigureAwait(false);
                        }
                    }).DisposeWith(Disposables);
                }

                var state = appStateService.Get();
                InitSortersAndFilters(state);

                ApplyDefaultSort();
            }
            else
            {
                if (raiseGameChanged)
                {
                    GameChangedRefresh = true;
                }
                Mods    = FilteredMods = new System.Collections.ObjectModel.ObservableCollection <IMod>();
                AllMods = Mods.ToHashSet();
            }
            if (!skipOverlay)
            {
                await TriggerOverlayAsync(id, false);
            }
        }