Merge pull request #3547 from Flow-Launcher/setting_window_navigation_issue

Fix setting window navigation update issue
This commit is contained in:
Jeremy Wu 2025-05-16 17:03:17 +10:00 committed by GitHub
commit e80d191fb8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 173 additions and 52 deletions

View file

@ -9,20 +9,19 @@ namespace Flow.Launcher.Resources.Pages
{
public partial class WelcomePage1
{
public Settings Settings { get; private set; }
private WelcomeViewModel _viewModel;
public Settings Settings { get; } = Ioc.Default.GetRequiredService<Settings>();
private readonly WelcomeViewModel _viewModel = Ioc.Default.GetRequiredService<WelcomeViewModel>();
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (!IsInitialized)
{
Settings = Ioc.Default.GetRequiredService<Settings>();
_viewModel = Ioc.Default.GetRequiredService<WelcomeViewModel>();
InitializeComponent();
}
// Sometimes the navigation is not triggered by button click,
// so we need to reset the page number
_viewModel.PageNum = 1;
if (!IsInitialized)
{
InitializeComponent();
}
base.OnNavigatedTo(e);
}

View file

@ -11,20 +11,19 @@ namespace Flow.Launcher.Resources.Pages
{
public partial class WelcomePage2
{
public Settings Settings { get; private set; }
private WelcomeViewModel _viewModel;
public Settings Settings { get; } = Ioc.Default.GetRequiredService<Settings>();
private readonly WelcomeViewModel _viewModel = Ioc.Default.GetRequiredService<WelcomeViewModel>();
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (!IsInitialized)
{
Settings = Ioc.Default.GetRequiredService<Settings>();
_viewModel = Ioc.Default.GetRequiredService<WelcomeViewModel>();
InitializeComponent();
}
// Sometimes the navigation is not triggered by button click,
// so we need to reset the page number
_viewModel.PageNum = 2;
if (!IsInitialized)
{
InitializeComponent();
}
base.OnNavigatedTo(e);
}

View file

@ -7,20 +7,19 @@ namespace Flow.Launcher.Resources.Pages
{
public partial class WelcomePage3
{
public Settings Settings { get; private set; }
private WelcomeViewModel _viewModel;
public Settings Settings { get; } = Ioc.Default.GetRequiredService<Settings>();
private readonly WelcomeViewModel _viewModel = Ioc.Default.GetRequiredService<WelcomeViewModel>();
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (!IsInitialized)
{
Settings = Ioc.Default.GetRequiredService<Settings>();
_viewModel = Ioc.Default.GetRequiredService<WelcomeViewModel>();
InitializeComponent();
}
// Sometimes the navigation is not triggered by button click,
// so we need to reset the page number
_viewModel.PageNum = 3;
if (!IsInitialized)
{
InitializeComponent();
}
base.OnNavigatedTo(e);
}
}

View file

@ -7,20 +7,19 @@ namespace Flow.Launcher.Resources.Pages
{
public partial class WelcomePage4
{
public Settings Settings { get; private set; }
private WelcomeViewModel _viewModel;
public Settings Settings { get; } = Ioc.Default.GetRequiredService<Settings>();
private readonly WelcomeViewModel _viewModel = Ioc.Default.GetRequiredService<WelcomeViewModel>();
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (!IsInitialized)
{
Settings = Ioc.Default.GetRequiredService<Settings>();
_viewModel = Ioc.Default.GetRequiredService<WelcomeViewModel>();
InitializeComponent();
}
// Sometimes the navigation is not triggered by button click,
// so we need to reset the page number
_viewModel.PageNum = 4;
if (!IsInitialized)
{
InitializeComponent();
}
base.OnNavigatedTo(e);
}
}

View file

@ -10,20 +10,19 @@ namespace Flow.Launcher.Resources.Pages
{
public partial class WelcomePage5
{
public Settings Settings { get; private set; }
private WelcomeViewModel _viewModel;
public Settings Settings { get; } = Ioc.Default.GetRequiredService<Settings>();
private readonly WelcomeViewModel _viewModel = Ioc.Default.GetRequiredService<WelcomeViewModel>();
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (!IsInitialized)
{
Settings = Ioc.Default.GetRequiredService<Settings>();
_viewModel = Ioc.Default.GetRequiredService<WelcomeViewModel>();
InitializeComponent();
}
// Sometimes the navigation is not triggered by button click,
// so we need to reset the page number
_viewModel.PageNum = 5;
if (!IsInitialized)
{
InitializeComponent();
}
base.OnNavigatedTo(e);
}

View file

@ -1,19 +1,29 @@
using System.Windows.Navigation;
using CommunityToolkit.Mvvm.DependencyInjection;
using Flow.Launcher.SettingPages.ViewModels;
using Flow.Launcher.ViewModel;
namespace Flow.Launcher.SettingPages.Views;
public partial class SettingsPaneAbout
{
private SettingsPaneAboutViewModel _viewModel = null!;
private readonly SettingWindowViewModel _settingViewModel = Ioc.Default.GetRequiredService<SettingWindowViewModel>();
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (!IsInitialized)
// Sometimes the navigation is not triggered by button click,
// so we need to reset the page type
_settingViewModel.PageType = typeof(SettingsPaneAbout);
// If the navigation is not triggered by button click, view model will be null again
if (_viewModel == null)
{
_viewModel = Ioc.Default.GetRequiredService<SettingsPaneAboutViewModel>();
DataContext = _viewModel;
}
if (!IsInitialized)
{
InitializeComponent();
}
base.OnNavigatedTo(e);

View file

@ -1,19 +1,29 @@
using System.Windows.Navigation;
using CommunityToolkit.Mvvm.DependencyInjection;
using Flow.Launcher.SettingPages.ViewModels;
using Flow.Launcher.ViewModel;
namespace Flow.Launcher.SettingPages.Views;
public partial class SettingsPaneGeneral
{
private SettingsPaneGeneralViewModel _viewModel = null!;
private readonly SettingWindowViewModel _settingViewModel = Ioc.Default.GetRequiredService<SettingWindowViewModel>();
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (!IsInitialized)
// Sometimes the navigation is not triggered by button click,
// so we need to reset the page type
_settingViewModel.PageType = typeof(SettingsPaneGeneral);
// If the navigation is not triggered by button click, view model will be null again
if (_viewModel == null)
{
_viewModel = Ioc.Default.GetRequiredService<SettingsPaneGeneralViewModel>();
DataContext = _viewModel;
}
if (!IsInitialized)
{
InitializeComponent();
}
base.OnNavigatedTo(e);

View file

@ -1,19 +1,29 @@
using System.Windows.Navigation;
using CommunityToolkit.Mvvm.DependencyInjection;
using Flow.Launcher.SettingPages.ViewModels;
using Flow.Launcher.ViewModel;
namespace Flow.Launcher.SettingPages.Views;
public partial class SettingsPaneHotkey
{
private SettingsPaneHotkeyViewModel _viewModel = null!;
private readonly SettingWindowViewModel _settingViewModel = Ioc.Default.GetRequiredService<SettingWindowViewModel>();
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (!IsInitialized)
// Sometimes the navigation is not triggered by button click,
// so we need to reset the page type
_settingViewModel.PageType = typeof(SettingsPaneHotkey);
// If the navigation is not triggered by button click, view model will be null again
if (_viewModel == null)
{
_viewModel = Ioc.Default.GetRequiredService<SettingsPaneHotkeyViewModel>();
DataContext = _viewModel;
}
if (!IsInitialized)
{
InitializeComponent();
}
base.OnNavigatedTo(e);

View file

@ -11,13 +11,22 @@ namespace Flow.Launcher.SettingPages.Views;
public partial class SettingsPanePluginStore
{
private SettingsPanePluginStoreViewModel _viewModel = null!;
private readonly SettingWindowViewModel _settingViewModel = Ioc.Default.GetRequiredService<SettingWindowViewModel>();
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (!IsInitialized)
// Sometimes the navigation is not triggered by button click,
// so we need to reset the page type
_settingViewModel.PageType = typeof(SettingsPanePluginStore);
// If the navigation is not triggered by button click, view model will be null again
if (_viewModel == null)
{
_viewModel = Ioc.Default.GetRequiredService<SettingsPanePluginStoreViewModel>();
DataContext = _viewModel;
}
if (!IsInitialized)
{
InitializeComponent();
}
_viewModel.PropertyChanged += ViewModel_PropertyChanged;

View file

@ -11,13 +11,22 @@ namespace Flow.Launcher.SettingPages.Views;
public partial class SettingsPanePlugins
{
private SettingsPanePluginsViewModel _viewModel = null!;
private readonly SettingWindowViewModel _settingViewModel = Ioc.Default.GetRequiredService<SettingWindowViewModel>();
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (!IsInitialized)
// Sometimes the navigation is not triggered by button click,
// so we need to reset the page type
_settingViewModel.PageType = typeof(SettingsPanePlugins);
// If the navigation is not triggered by button click, view model will be null again
if (_viewModel == null)
{
_viewModel = Ioc.Default.GetRequiredService<SettingsPanePluginsViewModel>();
DataContext = _viewModel;
}
if (!IsInitialized)
{
InitializeComponent();
}
_viewModel.PropertyChanged += ViewModel_PropertyChanged;

View file

@ -1,19 +1,29 @@
using System.Windows.Navigation;
using CommunityToolkit.Mvvm.DependencyInjection;
using Flow.Launcher.SettingPages.ViewModels;
using Flow.Launcher.ViewModel;
namespace Flow.Launcher.SettingPages.Views;
public partial class SettingsPaneProxy
{
private SettingsPaneProxyViewModel _viewModel = null!;
private readonly SettingWindowViewModel _settingViewModel = Ioc.Default.GetRequiredService<SettingWindowViewModel>();
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (!IsInitialized)
// Sometimes the navigation is not triggered by button click,
// so we need to reset the page type
_settingViewModel.PageType = typeof(SettingsPaneProxy);
// If the navigation is not triggered by button click, view model will be null again
if (_viewModel == null)
{
_viewModel = Ioc.Default.GetRequiredService<SettingsPaneProxyViewModel>();
DataContext = _viewModel;
}
if (!IsInitialized)
{
InitializeComponent();
}
base.OnNavigatedTo(e);

View file

@ -1,19 +1,29 @@
using System.Windows.Navigation;
using CommunityToolkit.Mvvm.DependencyInjection;
using Flow.Launcher.SettingPages.ViewModels;
using Flow.Launcher.ViewModel;
namespace Flow.Launcher.SettingPages.Views;
public partial class SettingsPaneTheme
{
private SettingsPaneThemeViewModel _viewModel = null!;
private readonly SettingWindowViewModel _settingViewModel = Ioc.Default.GetRequiredService<SettingWindowViewModel>();
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (!IsInitialized)
// Sometimes the navigation is not triggered by button click,
// so we need to reset the page type
_settingViewModel.PageType = typeof(SettingsPaneTheme);
// If the navigation is not triggered by button click, view model will be null again
if (_viewModel == null)
{
_viewModel = Ioc.Default.GetRequiredService<SettingsPaneThemeViewModel>();
DataContext = _viewModel;
}
if (!IsInitialized)
{
InitializeComponent();
}
base.OnNavigatedTo(e);

View file

@ -1,4 +1,5 @@
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
@ -18,6 +19,7 @@ public partial class SettingWindow
#region Private Fields
private readonly Settings _settings;
private readonly SettingWindowViewModel _viewModel;
#endregion
@ -26,8 +28,8 @@ public partial class SettingWindow
public SettingWindow()
{
_settings = Ioc.Default.GetRequiredService<Settings>();
var viewModel = Ioc.Default.GetRequiredService<SettingWindowViewModel>();
DataContext = viewModel;
_viewModel = Ioc.Default.GetRequiredService<SettingWindowViewModel>();
DataContext = _viewModel;
InitializeComponent();
UpdatePositionAndState();
@ -48,10 +50,37 @@ public partial class SettingWindow
hwndTarget.RenderMode = RenderMode.SoftwareOnly; // Must use software only render mode here
UpdatePositionAndState();
_viewModel.PropertyChanged += ViewModel_PropertyChanged;
}
// Sometimes the navigation is not triggered by button click,
// so we need to update the selected item here
private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case nameof(SettingWindowViewModel.PageType):
var selectedIndex = _viewModel.PageType.Name switch
{
nameof(SettingsPaneGeneral) => 0,
nameof(SettingsPanePlugins) => 1,
nameof(SettingsPanePluginStore) => 2,
nameof(SettingsPaneTheme) => 3,
nameof(SettingsPaneHotkey) => 4,
nameof(SettingsPaneProxy) => 5,
nameof(SettingsPaneAbout) => 6,
_ => 0
};
NavView.SelectedItem = NavView.MenuItems[selectedIndex];
break;
}
}
private void OnClosed(object sender, EventArgs e)
{
_viewModel.PropertyChanged -= ViewModel_PropertyChanged;
// If app is exiting, settings save is not needed because main window closing event will handle this
if (App.Exiting) return;
// Save settings when window is closed
@ -212,6 +241,7 @@ public partial class SettingWindow
{
if (args.IsSettingsSelected)
{
_viewModel.SetPageType(typeof(SettingsPaneGeneral));
ContentFrame.Navigate(typeof(SettingsPaneGeneral));
}
else
@ -234,7 +264,11 @@ public partial class SettingWindow
nameof(About) => typeof(SettingsPaneAbout),
_ => typeof(SettingsPaneGeneral)
};
ContentFrame.Navigate(pageType);
// Only navigate if the page type changes to fix navigation forward/back issue
if (_viewModel.SetPageType(pageType))
{
ContentFrame.Navigate(pageType);
}
}
}
@ -252,7 +286,8 @@ public partial class SettingWindow
private void ContentFrame_Loaded(object sender, RoutedEventArgs e)
{
NavView.SelectedItem ??= NavView.MenuItems[0]; /* Set First Page */
_viewModel.SetPageType(null); // Set page type to null so that NavigationView_SelectionChanged can navigate the frame
NavView.SelectedItem = NavView.MenuItems[0]; /* Set First Page */
}
#endregion

View file

@ -1,4 +1,5 @@
using Flow.Launcher.Infrastructure.UserSettings;
using System;
using Flow.Launcher.Infrastructure.UserSettings;
using Flow.Launcher.Plugin;
namespace Flow.Launcher.ViewModel;
@ -12,6 +13,28 @@ public partial class SettingWindowViewModel : BaseModel
_settings = settings;
}
public bool SetPageType(Type pageType)
{
if (_pageType == pageType) return false;
_pageType = pageType;
return true;
}
private Type _pageType = null;
public Type PageType
{
get => _pageType;
set
{
if (_pageType != value)
{
_pageType = value;
OnPropertyChanged();
}
}
}
public double SettingWindowWidth
{
get => _settings.SettingWindowWidth;