From 10cef2a826769ffddfcca4667e0f970a82c4bdd6 Mon Sep 17 00:00:00 2001 From: atouu <67765922+atouu@users.noreply.github.com> Date: Tue, 16 Jun 2026 21:36:23 +0800 Subject: [PATCH 1/2] Skip observable first init in PreferenceViewModel --- OpenUtau/ViewModels/PreferencesViewModel.cs | 45 +++++++++++++++++++-- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/OpenUtau/ViewModels/PreferencesViewModel.cs b/OpenUtau/ViewModels/PreferencesViewModel.cs index 9db829b46..492aab429 100644 --- a/OpenUtau/ViewModels/PreferencesViewModel.cs +++ b/OpenUtau/ViewModels/PreferencesViewModel.cs @@ -196,11 +196,13 @@ public PreferencesViewModel() { .Subscribe(_ => this.RaisePropertyChanged(nameof(IsThemeEditorOpen))); this.WhenAnyValue(vm => vm.UseSystemDefaultDevice) + .Skip(1) .Subscribe(useDefault => { Preferences.Default.UseSystemDefaultAudioDevice = useDefault; Preferences.Save(); }); this.WhenAnyValue(vm => vm.AudioOutputDevice) + .Skip(1) .WhereNotNull() .SubscribeOn(RxApp.MainThreadScheduler) .Subscribe(device => { @@ -216,57 +218,68 @@ public PreferencesViewModel() { } }); this.WhenAnyValue(vm => vm.PreferPortAudio) + .Skip(1) .Subscribe(index => { Preferences.Default.PreferPortAudio = index > 0; Preferences.Save(); }); this.WhenAnyValue(vm => vm.PlaybackAutoScroll) + .Skip(1) .Subscribe(autoScroll => { Preferences.Default.PlaybackAutoScroll = autoScroll; Preferences.Save(); }); this.WhenAnyValue(vm => vm.PlayPosMarkerMargin) + .Skip(1) .Subscribe(playPosMarkerMargin => { Preferences.Default.PlayPosMarkerMargin = playPosMarkerMargin; Preferences.Save(); }); this.WhenAnyValue(vm => vm.LockStartTime) + .Skip(1) .Subscribe(lockStartTime => { Preferences.Default.LockStartTime = lockStartTime; Preferences.Save(); }); this.WhenAnyValue(vm => vm.InstallToAdditionalSingersPath) + .Skip(1) .Subscribe(additionalSingersPath => { Preferences.Default.InstallToAdditionalSingersPath = additionalSingersPath; Preferences.Save(); }); this.WhenAnyValue(vm => vm.LoadDeepFolders) + .Skip(1) .Subscribe(loadDeepFolders => { Preferences.Default.LoadDeepFolderSinger = loadDeepFolders; Preferences.Save(); }); this.WhenAnyValue(vm => vm.PreRender) + .Skip(1) .Subscribe(preRender => { Preferences.Default.PreRender = preRender; Preferences.Save(); }); this.WhenAnyValue(vm => vm.PenPlusDefault) + .Skip(1) .Subscribe(penPlusDefault => { Preferences.Default.PenPlusDefault = penPlusDefault; Preferences.Save(); }); this.WhenAnyValue(vm => vm.Language) + .Skip(1) .Subscribe(lang => { Preferences.Default.Language = lang?.Name ?? string.Empty; Preferences.Save(); App.SetLanguage(Preferences.Default.Language); }); this.WhenAnyValue(vm => vm.SortingOrder) + .Skip(1) .Subscribe(so => { Preferences.Default.SortingOrder = so?.Name ?? null; Preferences.Save(); }); this.WhenAnyValue(vm => vm.ThemeName) + .Skip(1) .Subscribe(themeName => { ThemeEditable = themeName != "Light" && themeName != "Dark"; if (!IsThemeEditorOpen) { @@ -276,129 +289,153 @@ public PreferencesViewModel() { } }); this.WhenAnyValue(vm => vm.DegreeStyle) + .Skip(1) .Subscribe(degreeStyle => { Preferences.Default.DegreeStyle = degreeStyle; Preferences.Save(); MessageBus.Current.SendMessage(new PianorollRefreshEvent("Part")); }); this.WhenAnyValue(vm => vm.UseTrackColor) + .Skip(1) .Subscribe(trackColor => { Preferences.Default.UseTrackColor = trackColor; Preferences.Save(); MessageBus.Current.SendMessage(new PianorollRefreshEvent("TrackColor")); }); this.WhenAnyValue(vm => vm.ShowPortrait) + .Skip(1) .Subscribe(showPortrait => { Preferences.Default.ShowPortrait = showPortrait; Preferences.Save(); MessageBus.Current.SendMessage(new PianorollRefreshEvent("Portrait")); }); this.WhenAnyValue(vm => vm.ShowIcon) + .Skip(1) .Subscribe(showIcon => { Preferences.Default.ShowIcon = showIcon; Preferences.Save(); MessageBus.Current.SendMessage(new PianorollRefreshEvent("Portrait")); }); this.WhenAnyValue(vm => vm.ShowGhostNotes) + .Skip(1) .Subscribe(showGhostNotes => { Preferences.Default.ShowGhostNotes = showGhostNotes; Preferences.Save(); MessageBus.Current.SendMessage(new PianorollRefreshEvent("Part")); }); this.WhenAnyValue(vm => vm.Beta) + .Skip(1) .Subscribe(beta => { Preferences.Default.Beta = beta; Preferences.Save(); }); this.WhenAnyValue(vm => vm.LyricsHelper) + .Skip(1) .Subscribe(option => { ActiveLyricsHelper.Inst.Set(option?.klass); Preferences.Default.LyricHelper = option?.klass?.Name ?? string.Empty; Preferences.Save(); }); this.WhenAnyValue(vm => vm.LyricsHelperBrackets) + .Skip(1) .Subscribe(brackets => { Preferences.Default.LyricsHelperBrackets = brackets; Preferences.Save(); }); this.WhenAnyValue(vm => vm.OtoEditor) + .Skip(1) .Subscribe(index => { Preferences.Default.OtoEditor = index; Preferences.Save(); }); this.WhenAnyValue(vm => vm.NumRenderThreads) + .Skip(1) .Subscribe(index => { Preferences.Default.NumRenderThreads = index; HighThreads = index > SafeMaxThreadCount ? true : false; Preferences.Save(); }); this.WhenAnyValue(vm => vm.DefaultRenderer) + .Skip(1) .Subscribe(index => { Preferences.Default.DefaultRenderer = index; Preferences.Save(); }); this.WhenAnyValue(vm => vm.OnnxRunner) + .Skip(1) .Subscribe(index => { Preferences.Default.OnnxRunner = index; Preferences.Save(); ToggleOnnxGpuDisplay(index == "DirectML"); }); this.WhenAnyValue(vm => vm.OnnxGpu) + .Skip(1) .Subscribe(index => { Preferences.Default.OnnxGpu = index.deviceId; Preferences.Save(); }); this.WhenAnyValue(vm => vm.RememberMid) + .Skip(1) .Subscribe(index => { Preferences.Default.RememberMid = index; Preferences.Save(); }); this.WhenAnyValue(vm => vm.RememberUst) + .Skip(1) .Subscribe(index => { Preferences.Default.RememberUst = index; Preferences.Save(); }); this.WhenAnyValue(vm => vm.RememberVsqx) + .Skip(1) .Subscribe(index => { Preferences.Default.RememberVsqx = index; Preferences.Save(); }); this.WhenAnyValue(vm => vm.ClearCacheOnQuit) + .Skip(1) .Subscribe(index => { Preferences.Default.ClearCacheOnQuit = index; Preferences.Save(); }); this.WhenAnyValue(vm => vm.DiffSingerSteps) + .Skip(1) .Subscribe(index => { Preferences.Default.DiffSingerSteps = index; Preferences.Save(); }); this.WhenAnyValue(vm => vm.DiffSingerStepsVariance) - .Subscribe(index => { - Preferences.Default.DiffSingerStepsVariance = index; - Preferences.Save(); - }); + .Skip(1) + .Subscribe(index => { + Preferences.Default.DiffSingerStepsVariance = index; + Preferences.Save(); + }); this.WhenAnyValue(vm => vm.DiffSingerStepsPitch) + .Skip(1) .Subscribe(index => { Preferences.Default.DiffSingerStepsPitch = index; Preferences.Save(); }); this.WhenAnyValue(vm => vm.DiffSingerDepth) + .Skip(1) .Subscribe(index => { Preferences.Default.DiffSingerDepth = index / 100; Preferences.Save(); }); this.WhenAnyValue(vm => vm.DiffSingerTensorCache) + .Skip(1) .Subscribe(useCache => { Preferences.Default.DiffSingerTensorCache = useCache; Preferences.Save(); }); this.WhenAnyValue(vm => vm.DiffSingerLangCodeHide) + .Skip(1) .Subscribe(useCache => { Preferences.Default.DiffSingerLangCodeHide = useCache; Preferences.Save(); }); this.WhenAnyValue(vm => vm.SkipRenderingMutedTracks) + .Skip(1) .Subscribe(skipRenderingMutedTracks => { Preferences.Default.SkipRenderingMutedTracks = skipRenderingMutedTracks; Preferences.Save(); From 63718309c1a829d4122407705ca4302f8970c3e2 Mon Sep 17 00:00:00 2001 From: atouu <67765922+atouu@users.noreply.github.com> Date: Tue, 30 Jun 2026 16:36:14 +0800 Subject: [PATCH 2/2] fix getters --- OpenUtau/ViewModels/PreferencesViewModel.cs | 53 +++++---------------- 1 file changed, 13 insertions(+), 40 deletions(-) diff --git a/OpenUtau/ViewModels/PreferencesViewModel.cs b/OpenUtau/ViewModels/PreferencesViewModel.cs index 702ef2208..6cee3c8e5 100644 --- a/OpenUtau/ViewModels/PreferencesViewModel.cs +++ b/OpenUtau/ViewModels/PreferencesViewModel.cs @@ -27,33 +27,15 @@ public override string ToString() { public class PreferencesViewModel : ViewModelBase { // General - private CultureInfo? language; - private CultureInfo? sortingOrder; - public List? Languages { get; } - public CultureInfo? Language { - get => language; - set => this.RaiseAndSetIfChanged(ref language, value); - } + [Reactive] public CultureInfo? Language { get; set; } public List? SortingOrders { get; } - public CultureInfo? SortingOrder { - get => sortingOrder; - set => this.RaiseAndSetIfChanged(ref sortingOrder, value); - } + [Reactive] public CultureInfo? SortingOrder { get; set; } [Reactive] public bool Beta { get; set; } // Playback - private List? audioOutputDevices; - private AudioOutputDevice? audioOutputDevice; - - public List? AudioOutputDevices { - get => audioOutputDevices; - set => this.RaiseAndSetIfChanged(ref audioOutputDevices, value); - } - public AudioOutputDevice? AudioOutputDevice { - get => audioOutputDevice; - set => this.RaiseAndSetIfChanged(ref audioOutputDevice, value); - } + [Reactive] public List? AudioOutputDevices { get; set; } + [Reactive] public AudioOutputDevice? AudioOutputDevice { get; set; } [Reactive] public bool UseSystemDefaultDevice { get; set; } [Reactive] public int PreferPortAudio { get; set; } [Reactive] public int LockStartTime { get; set; } @@ -78,20 +60,16 @@ public AudioOutputDevice? AudioOutputDevice { // Render [Reactive] public bool PreRender { get; set; } [Reactive] public int NumRenderThreads { get; set; } - public int LogicalCoreCount { - get => Environment.ProcessorCount; - } - [Reactive] public bool HighThreads { get; set; } - public int SafeMaxThreadCount { - get => Math.Min(8, LogicalCoreCount / 2); - } + public int LogicalCoreCount => Environment.ProcessorCount; + public int SafeMaxThreadCount => Math.Min(8, LogicalCoreCount / 2); + public bool HighThreads => NumRenderThreads > SafeMaxThreadCount; [Reactive] public bool SkipRenderingMutedTracks { get; set; } [Reactive] public bool ClearCacheOnQuit { get; set; } public List OnnxRunnerOptions { get; set; } [Reactive] public string OnnxRunner { get; set; } public List OnnxGpuOptions { get; set; } [Reactive] public GpuInfo OnnxGpu { get; set; } - [Reactive] public bool ShowOnnxGpu { get; set; } + public bool ShowOnnxGpu => OnnxRunner == "DirectML"; // Appearance [Reactive] public string ThemeName { get; set; } @@ -100,7 +78,7 @@ public int SafeMaxThreadCount { [Reactive] public bool ShowPortrait { get; set; } [Reactive] public bool ShowIcon { get; set; } [Reactive] public bool ShowGhostNotes { get; set; } - [Reactive] public bool ThemeEditable { get; set; } + public bool ThemeEditable => ThemeName != "Light" && ThemeName != "Dark"; public List ThemeItems => ThemeManager.GetAvailableThemes(); public bool IsThemeEditorOpen => Views.ThemeEditorWindow.IsOpen; @@ -168,7 +146,6 @@ public PreferencesViewModel() { OnnxRunnerOptions[0] : Preferences.Default.OnnxRunner; OnnxGpuOptions = Onnx.getGpuInfo(); OnnxGpu = OnnxGpuOptions.FirstOrDefault(x => x.deviceId == Preferences.Default.OnnxGpu, OnnxGpuOptions[0]); - ShowOnnxGpu = OnnxRunner == "DirectML"; DiffSingerDepth = Preferences.Default.DiffSingerDepth * 100; DiffSingerSteps = Preferences.Default.DiffSingerSteps; DiffSingerStepsVariance = Preferences.Default.DiffSingerStepsVariance; @@ -193,7 +170,7 @@ public PreferencesViewModel() { MessageBus.Current.Listen() .Subscribe(_ => this.RaisePropertyChanged(nameof(IsThemeEditorOpen))); - + this.WhenAnyValue(vm => vm.UseSystemDefaultDevice) .Skip(1) .Subscribe(useDefault => { @@ -274,7 +251,7 @@ public PreferencesViewModel() { this.WhenAnyValue(vm => vm.ThemeName) .Skip(1) .Subscribe(themeName => { - ThemeEditable = themeName != "Light" && themeName != "Dark"; + this.RaisePropertyChanged(nameof(ThemeEditable)); if (!IsThemeEditorOpen) { Preferences.Default.ThemeName = themeName; Preferences.Save(); @@ -344,8 +321,8 @@ public PreferencesViewModel() { this.WhenAnyValue(vm => vm.NumRenderThreads) .Skip(1) .Subscribe(index => { + this.RaisePropertyChanged(nameof(HighThreads)); Preferences.Default.NumRenderThreads = index; - HighThreads = index > SafeMaxThreadCount ? true : false; Preferences.Save(); }); this.WhenAnyValue(vm => vm.DefaultRenderer) @@ -357,9 +334,9 @@ public PreferencesViewModel() { this.WhenAnyValue(vm => vm.OnnxRunner) .Skip(1) .Subscribe(index => { + this.RaisePropertyChanged(nameof(ShowOnnxGpu)); Preferences.Default.OnnxRunner = index; Preferences.Save(); - ToggleOnnxGpuDisplay(index == "DirectML"); }); this.WhenAnyValue(vm => vm.OnnxGpu) .Skip(1) @@ -482,9 +459,5 @@ public void SetWinePath(string path) { public void RefreshThemes() { this.RaisePropertyChanged(nameof(ThemeItems)); } - - public void ToggleOnnxGpuDisplay(bool show) { - ShowOnnxGpu = show; - } } }