Skip to content

Commit cf808ad

Browse files
committed
feat: Implement flush for pending edits before saving notes to capture in-progress changes
1 parent d44bba5 commit cf808ad

3 files changed

Lines changed: 20 additions & 15 deletions

File tree

TimmyTools.WpfUi/ViewModels/NoteViewModel.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ ThemeService themeService
5353

5454
public NoteModel Note { get; set; } = null!;
5555

56+
// The View sets this to flush pending TextBox bindings before each save.
57+
// Needed because RtfContent uses UpdateSourceTrigger=LostFocus to keep
58+
// selection stable during typing — without a flush, periodic saves would
59+
// miss in-progress edits.
60+
public Action? FlushPendingEdits { get; set; }
61+
5662
public async Task Initialize(int? noteId = null, NoteModel? parent = null, nint? managementWindowHandle = null)
5763
{
5864
if (noteId is null)
@@ -117,6 +123,8 @@ public void UpdateAlwaysOnTop()
117123

118124
public async Task SaveNote()
119125
{
126+
FlushPendingEdits?.Invoke();
127+
120128
if (Note.IsSaved)
121129
return;
122130

TimmyTools.WpfUi/Views/NoteWindow.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@
272272
FontSize="18"
273273
x:Name="NoteTextBox"
274274
Padding="5,5,5,5"
275-
RtfContent="{Binding Note.Content, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
275+
RtfContent="{Binding Note.Content, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
276276

277277
SpellCheck.IsEnabled="{Binding EditorSettings.CheckSpelling}"
278278
NewLineAtEnd="{Binding EditorSettings.NewLineAtEnd}"

TimmyTools.WpfUi/Views/NoteWindow.xaml.cs

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,17 @@ public NoteWindow(SettingsService settingsService, MessengerService messengerSer
4848

4949
InitializeComponent();
5050

51+
// Flush the LostFocus-triggered RtfContent binding before each save
52+
// so the periodic auto-save still captures in-progress edits.
53+
_viewModel.FlushPendingEdits = () =>
54+
BindingOperations.GetBindingExpression(
55+
NoteTextBox,
56+
Controls.NoteTextBoxControl.RtfContentProperty
57+
)?.UpdateSource();
58+
5159
Activated += Window_Activated;
5260
Closing += Window_Closing;
5361
Deactivated += Window_Deactivated;
54-
MouseDown += NoteWindow_MouseDown;
5562
MouseEnter += Window_MouseEnter;
5663
MouseLeave += Window_MouseLeave;
5764
Loaded += Window_Loaded;
@@ -104,18 +111,6 @@ private void Window_Loaded(object sender, RoutedEventArgs e)
104111
);
105112
}
106113

107-
private void NoteWindow_MouseDown(object sender, MouseButtonEventArgs e)
108-
{
109-
// Check mouse button is pressed as a missed click of a button
110-
// can cause issues with DragMove().
111-
if (e.LeftButton != MouseButtonState.Pressed)
112-
return;
113-
114-
DragMove();
115-
116-
_viewModel.OnWindowMoved(Left, Top);
117-
}
118-
119114
private void NoteWindow_StateChanged(object? sender, EventArgs e)
120115
{
121116
if (WindowState == WindowState.Minimized)
@@ -144,7 +139,9 @@ private void Window_Activated(object? sender, EventArgs e)
144139
{
145140
_viewModel.Note.IsFocused = true;
146141
_viewModel.UpdateOpacity();
147-
_viewModel.UpdateAlwaysOnTop();
142+
// Defer the topmost toggle past the current input gesture so it
143+
// doesn't reorder the window mid-click/drag and disrupt selection.
144+
Dispatcher.BeginInvoke(_viewModel.UpdateAlwaysOnTop, System.Windows.Threading.DispatcherPriority.Input);
148145
ShowTitleBar();
149146
}
150147

0 commit comments

Comments
 (0)