diff --git a/OpenUtau/Controls/PianoRoll.axaml b/OpenUtau/Controls/PianoRoll.axaml
index 647d22145..2ba480cb5 100644
--- a/OpenUtau/Controls/PianoRoll.axaml
+++ b/OpenUtau/Controls/PianoRoll.axaml
@@ -359,7 +359,7 @@
-
+
@@ -538,6 +538,7 @@
+
+
+
+
+
@@ -626,6 +631,20 @@
+
+
+
+
+
+
+
@@ -678,4 +697,4 @@
-
+
\ No newline at end of file
diff --git a/OpenUtau/Controls/PianoRoll.axaml.cs b/OpenUtau/Controls/PianoRoll.axaml.cs
index 2fd05db2d..76ae4049f 100644
--- a/OpenUtau/Controls/PianoRoll.axaml.cs
+++ b/OpenUtau/Controls/PianoRoll.axaml.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
@@ -11,6 +11,7 @@
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity;
+using Avalonia.Threading;
using OpenUtau.App.ViewModels;
using OpenUtau.App.Views;
using OpenUtau.Core;
@@ -349,9 +350,25 @@ void OnMenuSearchNote(object sender, RoutedEventArgs args) {
void OnMenuDetachPianoRoll(object sender, RoutedEventArgs args) {
MainWindow?.SetPianoRollAttachment();
ViewModel.RaisePropertyChanged(nameof(ViewModel.PianoRollDetached));
+ // 延迟通知,等窗口切换完成后再更新,避免切换过程中触发 UI 更新导致崩溃
+ Dispatcher.UIThread.Post(() => {
+ ViewModel.RaisePropertyChanged(nameof(ViewModel.HideMenuItemVisible));
+ });
}
void OnMenuHidePianoRoll(object sender, RoutedEventArgs args) {
+ // Reset ToggleButton checked state / 重置 ToggleButton 的 checked 状态
+ // Reason / 原因:
+ // ToggleButton keeps IsChecked=true after click, causing darker background.
+ // But this close button is a one-shot action, not a state toggle.
+ // So we manually reset it to false immediately after click.
+ // Since piano roll hides instantly, users never see this momentary state change.
+ //
+ // 详细说明:
+ // ToggleButton 点击后会保持 IsChecked=true,导致底纹变深。
+ // 但关闭按钮是一次性操作,不应该保持状态,所以手动重置为 false。
+ // 因为点击后钢琴卷帘立即隐藏,用户看不到这个瞬间的状态变化。
+ HidePianoRollButton.IsChecked = false;
if (RootWindow.DataContext is MainWindowViewModel mwvm) {
mwvm.ShowPianoRoll = false;
} else {
@@ -360,6 +377,24 @@ void OnMenuHidePianoRoll(object sender, RoutedEventArgs args) {
}
// Edit Tools
+ private long _lastToolbarClickTime = 0;
+ private const long DoubleClickThreshold = 300; // 毫秒
+
+ void OnToolbarPointerPressed(object sender, PointerPressedEventArgs args) {
+ // 双击工具栏空白处关闭钢琴卷帘(仅嵌入模式生效)
+ if (!args.GetCurrentPoint(this).Properties.IsLeftButtonPressed) return;
+
+ long now = DateTimeOffset.Now.ToUnixTimeMilliseconds();
+ if (now - _lastToolbarClickTime < DoubleClickThreshold) {
+ // 双击
+ if (RootWindow.DataContext is MainWindowViewModel mwvm) {
+ mwvm.ShowPianoRoll = false;
+ }
+ // 分离模式下不响应,保持和原来一模一样
+ }
+ _lastToolbarClickTime = now;
+ }
+
private CancellationTokenSource? _longPressCts;
private async void OnToolButtonPointerPressed(object? sender, PointerPressedEventArgs args) {
if (!args.GetCurrentPoint(this).Properties.IsLeftButtonPressed) return;
@@ -2017,4 +2052,4 @@ public void OnNext(UCommand cmd, bool isUndo) {
}
}
}
-}
+}
\ No newline at end of file
diff --git a/OpenUtau/ViewModels/PianoRollViewModel.cs b/OpenUtau/ViewModels/PianoRollViewModel.cs
index f4f1bfbcb..14120b084 100644
--- a/OpenUtau/ViewModels/PianoRollViewModel.cs
+++ b/OpenUtau/ViewModels/PianoRollViewModel.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive;
@@ -68,6 +68,7 @@ public class PianoRollViewModel : ViewModelBase, ICmdSubscriber {
public bool PlaybackAutoScroll1 { get => Preferences.Default.PlaybackAutoScroll == 1 ? true : false; }
public bool PlaybackAutoScroll2 { get => Preferences.Default.PlaybackAutoScroll == 2 ? true : false; }
public bool PianoRollDetached { get => Preferences.Default.DetachPianoRoll; }
+ public bool HideMenuItemVisible => !Preferences.Default.DetachPianoRoll;
public bool ShowPhonemizerTags {
get => Preferences.Default.ShowPhonemizerTags;
set {
@@ -319,4 +320,4 @@ public void OnNext(UCommand cmd, bool isUndo) {
#endregion
}
-}
+}
\ No newline at end of file