diff --git a/FluentTerminal.App.ViewModels/MainViewModel.cs b/FluentTerminal.App.ViewModels/MainViewModel.cs index 3104298..27a97c3 100644 --- a/FluentTerminal.App.ViewModels/MainViewModel.cs +++ b/FluentTerminal.App.ViewModels/MainViewModel.cs @@ -375,17 +375,17 @@ namespace FluentTerminal.App.ViewModels if (sender is TerminalViewModel terminal) { Array.ForEach(Terminals.ToArray(), - t => { + async t => { if (terminal != t) { Logger.Instance.Debug("Terminal with Id: {@id} closed.", t.Terminal.Id); - t.CloseCommand.Execute(EventArgs.Empty); + await t.CloseCommand.ExecuteAsync(); } }); } } - private void Terminal_CloseRightTabsRequested(object sender, EventArgs e) + private async void Terminal_CloseRightTabsRequested(object sender, EventArgs e) { if (sender is TerminalViewModel terminal) { @@ -393,12 +393,12 @@ namespace FluentTerminal.App.ViewModels { var terminalToRemove = Terminals[i]; Logger.Instance.Debug("Terminal with Id: {@id} closed.", terminalToRemove.Terminal.Id); - terminalToRemove.CloseCommand.Execute(EventArgs.Empty); + await terminalToRemove.CloseCommand.ExecuteAsync(); } } } - private void Terminal_CloseLeftTabsRequested(object sender, EventArgs e) + private async void Terminal_CloseLeftTabsRequested(object sender, EventArgs e) { if (sender is TerminalViewModel terminal) { @@ -406,7 +406,7 @@ namespace FluentTerminal.App.ViewModels { var terminalToRemove = Terminals[i]; Logger.Instance.Debug("Terminal with Id: {@id} closed.", terminalToRemove.Terminal.Id); - terminalToRemove.CloseCommand.Execute(EventArgs.Empty); + await terminalToRemove.CloseCommand.ExecuteAsync(); } } } @@ -464,7 +464,7 @@ namespace FluentTerminal.App.ViewModels private void CloseCurrentTab() { - SelectedTerminal?.CloseCommand.Execute(null); + SelectedTerminal?.CloseCommand.ExecuteAsync(); } private void NewWindow(NewWindowAction showSelection) diff --git a/FluentTerminal.App.ViewModels/TerminalViewModel.cs b/FluentTerminal.App.ViewModels/TerminalViewModel.cs index ccc2b46..6c71460 100644 --- a/FluentTerminal.App.ViewModels/TerminalViewModel.cs +++ b/FluentTerminal.App.ViewModels/TerminalViewModel.cs @@ -118,16 +118,16 @@ namespace FluentTerminal.App.ViewModels TabThemes = new ObservableCollection(SettingsService.GetTabThemes()); TabTheme = TabThemes.FirstOrDefault(t => t.Id == ShellProfile.TabThemeId); - CloseCommand = new RelayCommand(async () => await TryClose().ConfigureAwait(false)); - CloseLeftTabsCommand = new RelayCommand(CloseLeftTabs); - CloseRightTabsCommand = new RelayCommand(CloseRightTabs); - CloseOtherTabsCommand = new RelayCommand(CloseOtherTabs); - FindNextCommand = new RelayCommand(FindNext); - FindPreviousCommand = new RelayCommand(FindPrevious); - CloseSearchPanelCommand = new RelayCommand(CloseSearchPanel); - SelectTabThemeCommand = new RelayCommand(SelectTabTheme); - EditTitleCommand = new AsyncCommand(EditTitle); - DuplicateTabCommand = new RelayCommand(DuplicateTab); + CloseCommand = new AsyncCommand(CloseTab, CanExecuteCommand); + CloseLeftTabsCommand = new RelayCommand(CloseLeftTabs, CanExecuteCommand); + CloseRightTabsCommand = new RelayCommand(CloseRightTabs, CanExecuteCommand); + CloseOtherTabsCommand = new RelayCommand(CloseOtherTabs, CanExecuteCommand); + FindNextCommand = new RelayCommand(FindNext, CanExecuteCommand); + FindPreviousCommand = new RelayCommand(FindPrevious, CanExecuteCommand); + CloseSearchPanelCommand = new RelayCommand(CloseSearchPanel, CanExecuteCommand); + SelectTabThemeCommand = new RelayCommand(SelectTabTheme, CanExecuteCommand); + EditTitleCommand = new AsyncCommand(EditTitle, CanExecuteCommand); + DuplicateTabCommand = new RelayCommand(DuplicateTab, CanExecuteCommand); if (!String.IsNullOrEmpty(terminalState)) { @@ -146,8 +146,12 @@ namespace FluentTerminal.App.ViewModels } + private bool _disposalRequested; + public void DisposalPrepare() { + _disposalRequested = true; + CloseCommand = null; TerminalView.DisposalPrepare(); TerminalView = null; Terminal = null; @@ -186,7 +190,7 @@ namespace FluentTerminal.App.ViewModels public string XtermBufferState { get; private set; } - public RelayCommand CloseCommand { get; } + public AsyncCommand CloseCommand { get; private set; } public RelayCommand CloseRightTabsCommand { get; } @@ -303,6 +307,8 @@ namespace FluentTerminal.App.ViewModels set => Set(ref _terminalTheme, value); } + public bool Initialized { get; set; } + public string TabTitle { get => _tabTitle; @@ -394,6 +400,21 @@ namespace FluentTerminal.App.ViewModels FocusTerminal(); } + private bool CanExecuteCommand(T a) + { + return CanExecuteCommand(); + } + + private bool CanExecuteCommand() + { + return (Initialized == true && _disposalRequested == false); + } + + private async Task CloseTab() + { + await TryClose().ConfigureAwait(false); + } + private void CloseLeftTabs() { CloseLeftTabsRequested?.Invoke(this, EventArgs.Empty); diff --git a/FluentTerminal.App/Utilities/DebouncedAction.cs b/FluentTerminal.App/Utilities/DebouncedAction.cs index 23aece1..bc5bf81 100644 --- a/FluentTerminal.App/Utilities/DebouncedAction.cs +++ b/FluentTerminal.App/Utilities/DebouncedAction.cs @@ -9,49 +9,56 @@ namespace FluentTerminal.App.Utilities private DispatcherTimer timer; private readonly CoreDispatcher _dispatcher; private readonly TimeSpan _interval; - private readonly WeakReference> _action; + private Action _action; private T _parameter; public DebouncedAction(CoreDispatcher dispatcher, TimeSpan interval, Action action) { _dispatcher = dispatcher; _interval = interval; - _action = new WeakReference>(action); + _action = action; } public void Invoke(T parameter) { _parameter = parameter; - timer?.Stop(); - timer = null; + ResetTimer(); timer = new DispatcherTimer { Interval = _interval }; - timer.Tick += Timer_Tick; + timer.Tick += async (s, e) => + { + if (!ResetTimer()) + { + return; + } + + await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => + { + _action.Invoke(_parameter); + }); + }; timer.Start(); } - private async void Timer_Tick(object sender, object e) + public void Stop() + { + ResetTimer(); + _action = null; + } + + private bool ResetTimer() { if (timer == null) { - return; + return false; } - - timer?.Stop(); - timer.Tick -= Timer_Tick; + timer.Stop(); timer = null; - - await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => - { - if (_action.TryGetTarget(out Action target)) - { - target.Invoke(_parameter); - } - }); + return true; } } } diff --git a/FluentTerminal.App/Views/TerminalView.xaml.cs b/FluentTerminal.App/Views/TerminalView.xaml.cs index 047b351..0afff96 100644 --- a/FluentTerminal.App/Views/TerminalView.xaml.cs +++ b/FluentTerminal.App/Views/TerminalView.xaml.cs @@ -25,6 +25,7 @@ namespace FluentTerminal.App.Views TerminalContainer.Children.Add((UIElement)_terminalView); _terminalView.Initialize(ViewModel); ViewModel.TerminalView = _terminalView; + ViewModel.Initialized = true; } public void DisposalPrepare() diff --git a/FluentTerminal.App/Views/XtermTerminalView.xaml.cs b/FluentTerminal.App/Views/XtermTerminalView.xaml.cs index 15881e9..dd731aa 100644 --- a/FluentTerminal.App/Views/XtermTerminalView.xaml.cs +++ b/FluentTerminal.App/Views/XtermTerminalView.xaml.cs @@ -198,6 +198,9 @@ namespace FluentTerminal.App.Views public void DisposalPrepare() { + _optionsChanged.Stop(); + _sizeChanged.Stop(); + _unblockOutput.Stop(); ViewModel = null; } @@ -410,12 +413,13 @@ namespace FluentTerminal.App.Views private async void Terminal_Closed(object sender, EventArgs e) { + ViewModel.Terminal.OutputReceived -= Terminal_OutputReceived; + ViewModel.Terminal.Closed -= Terminal_Closed; await ViewModel.ApplicationView.RunOnDispatcherThread(() => { _webView.NavigationCompleted -= _webView_NavigationCompleted; _webView.NavigationStarting -= _webView_NavigationStarting; - ViewModel.Terminal.OutputReceived -= Terminal_OutputReceived; - ViewModel.Terminal.Closed -= Terminal_Closed; + _webView?.Navigate(new Uri("about:blank")); Root.Children.Remove(_webView); _webView = null;