fix(notes): Shift+Enter in the capture box, not just in the note rows

The previous fix put AcceptsReturn on the rows in the DataTemplate and
missed the box you actually type new notes into, which still had it off
and only a KeyBinding for Enter — so Shift+Enter there did nothing.

Both now go through the same tunnel handler: Enter files the note,
Shift+Enter is left to the TextBox for the line break. The KeyBinding is
gone; with AcceptsReturn on it could never have fired anyway, because
TextBox consumes Enter in its own OnKeyDown before bindings or bubbling
handlers run.

Verified against the running app: a note typed with Shift+Enter is
stored as "fe\r\ndwa".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
CubeGameLP
2026-08-28 21:46:59 +02:00
co-authored by Claude Opus 5
parent b90c5855f4
commit f640580463
2 changed files with 25 additions and 10 deletions
@@ -45,14 +45,14 @@
<PathIcon Width="12" Height="12" Data="{StaticResource Icon.Plus}"
Foreground="{DynamicResource TextFaintBrush}"/>
</Border>
<!-- Enter/Shift+Enter are handled in the code-behind's tunnel handler, same as the note
rows: a KeyBinding would never fire, because AcceptsReturn makes TextBox consume
Enter first. -->
<TextBox Grid.Column="1" x:Name="NewNoteBox" Classes="add-task-input"
PlaceholderText="{loc:Tr notes.newNotePlaceholder}"
Text="{Binding NewBulletText, Mode=TwoWay}"
VerticalAlignment="Center" Margin="12,0,0,0">
<TextBox.KeyBindings>
<KeyBinding Gesture="Enter" Command="{Binding AddBulletCommand}"/>
</TextBox.KeyBindings>
</TextBox>
AcceptsReturn="True" TextWrapping="Wrap"
VerticalAlignment="Center" Margin="12,0,0,0"/>
<Border Grid.Column="2" Classes="kbd kbd-enter" VerticalAlignment="Center"
IsVisible="{Binding #NewNoteBox.IsFocused}">
<TextBlock Text="{loc:Tr tasks.enterKey}"/>
@@ -21,6 +21,7 @@ public partial class NotesEditorView : UserControl
AddHandler(KeyDownEvent, OnBulletKeyDown, RoutingStrategies.Tunnel);
}
private void OnDataContextChanged(object? sender, EventArgs e)
{
if (_vm is not null) _vm.FocusRequested -= FocusBullet;
@@ -37,13 +38,27 @@ public partial class NotesEditorView : UserControl
private void OnBulletKeyDown(object? sender, KeyEventArgs e)
{
// Source, not sender: the tunnel handler is attached to the whole view, so this also sees
// keys from the capture box at the top — which has no bullet behind it and is skipped.
if (e.Source is not TextBox { DataContext: NoteBulletViewModel bullet } box
|| DataContext is not NotesEditorViewModel vm) return;
// Source, not sender: the tunnel handler is attached to the whole view, so it sees the
// capture box at the top as well as the note rows. Both need the same Enter/Shift+Enter
// split, and neither can get it from a KeyBinding — with AcceptsReturn on, TextBox eats
// Enter in its own OnKeyDown before any bubbling handler or binding runs.
if (e.Source is not TextBox box || DataContext is not NotesEditorViewModel vm) return;
var shift = e.KeyModifiers.HasFlag(KeyModifiers.Shift);
if (ReferenceEquals(box, NewNoteBox))
{
if (e.Key == Key.Enter && !shift)
{
e.Handled = true;
vm.AddBulletCommand.Execute(null);
}
return;
}
if (box.DataContext is not NoteBulletViewModel bullet) return;
// Shift+Enter falls through to the TextBox and breaks the line — a note can be several.
if (e.Key == Key.Enter && !e.KeyModifiers.HasFlag(KeyModifiers.Shift))
if (e.Key == Key.Enter && !shift)
{
e.Handled = true;
vm.SplitBulletCommand.Execute(bullet);