Public Access
Let a group be right-clicked, as a host already can
The host cards have had a menu since the grid replaced the sidebar; the group cards above them had a double-click and two buttons beside the heading, and nothing that named the card under the pointer. Open, Edit and Delete are on them now, drawn and aimed the same way. On the list rather than in the item template, for the reason the host grid's is: the three commands are the vault's, and a ContextMenu inside a DataTemplate has the row for its data context, so every binding in it would silently resolve to nothing. The code-behind selects whatever was right-clicked before the menu opens, and that is what makes one menu act on the card under the pointer rather than on whichever was selected before. **Cancelled over the space around the cards, and here that guard is doing more than the host grid's.** GroupTarget falls back to the group whose contents are on screen when no card is selected — the right answer for a pair of buttons beside the heading, which would otherwise have no subject the moment a group with nothing inside it is opened, and the wrong one for a menu that opened on a card. Without the guard, right-clicking the gap beside the cards would offer to delete the group the trail ends with: a question about something the user is not pointing at, in the one menu where the answer is a deletion. Only Open takes a parameter, and it has to. OpenGroupCommand's null is a real argument rather than a missing one — it is the trail's first crumb, ALL HOSTS — so an entry with no parameter would not open the card, it would leave the group the user right-clicked and go back to the top level. Two tests beside the two the host menu already had. What they hold that a build cannot is the CommandParameter binding: a path that resolves to nothing compiles and draws, and the entry would then quietly do the opposite of what it says. The popup itself is still the platform's, so manual-checks 7.9 gained the group half of the same check.
This commit is contained in:
@@ -282,6 +282,34 @@
|
||||
<ListBox.ItemsPanel>
|
||||
<ItemsPanelTemplate><WrapPanel /></ItemsPanelTemplate>
|
||||
</ListBox.ItemsPanel>
|
||||
|
||||
<!--
|
||||
The three things you can do to a group, on the group itself — the same menu the host grid
|
||||
below has, for the same reasons. On the list rather than in the item template, because the
|
||||
commands are the vault's and a menu inside a DataTemplate would have the row for its data
|
||||
context; the code-behind selects whatever was right-clicked before the menu opens, and
|
||||
cancels it outright over the space around the cards.
|
||||
|
||||
Open is here as well as on the double-click, and Edit and Delete as well as on the two
|
||||
buttons above, and neither is a duplicate for its own sake: a gesture is unreachable without
|
||||
a pointer, and the buttons act on GroupTarget — which with no card selected is the group the
|
||||
trail ends with rather than the one under the pointer. This menu is the one place all three
|
||||
act on the card that was right-clicked.
|
||||
|
||||
Only Open takes a parameter, because OpenGroupCommand's null means ALL HOSTS rather than
|
||||
nothing; Edit and Delete read GroupTarget, which the selection the code-behind has just made
|
||||
is the first half of.
|
||||
-->
|
||||
<ListBox.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="Open" Command="{Binding OpenGroupCommand}"
|
||||
CommandParameter="{Binding SelectedGroup}" />
|
||||
<MenuItem Header="Edit…" Command="{Binding EditGroupCommand}" />
|
||||
<Separator />
|
||||
<MenuItem Header="Delete…" Command="{Binding DeleteGroupCommand}" />
|
||||
</ContextMenu>
|
||||
</ListBox.ContextMenu>
|
||||
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:HostGroupRowViewModel">
|
||||
<Border Classes="tile">
|
||||
|
||||
@@ -96,6 +96,11 @@ internal sealed partial class HostsScreen : UserControl
|
||||
HostGrid.AddHandler(PointerPressedEvent, OnPointerPressed, RoutingStrategies.Tunnel);
|
||||
HostGrid.AddHandler(ContextRequestedEvent, OnContextRequested, RoutingStrategies.Tunnel);
|
||||
|
||||
// And the group cards answer a right click the same way, for the same reason: their menu's commands
|
||||
// read the vault's group selection, and without this they would act on whichever card was selected
|
||||
// before — or, with none, on the group the trail ends with, which is not on screen at all.
|
||||
GroupGrid.AddHandler(ContextRequestedEvent, OnGroupContextRequested, RoutingStrategies.Tunnel);
|
||||
|
||||
HostGrid.PointerMoved += OnPointerMoved;
|
||||
HostGrid.PointerReleased += OnPointerReleased;
|
||||
HostGrid.PointerCaptureLost += OnPointerCaptureLost;
|
||||
@@ -204,6 +209,33 @@ internal sealed partial class HostsScreen : UserControl
|
||||
vault.SelectedSidebarRow = row;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Points the group menu at whatever was right-clicked.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The host grid's rule, applied to the cards above it — see <see cref="OnContextRequested"/>. What is
|
||||
/// different is what an unaimed menu would have done: <c>GroupTarget</c> falls back to the open group
|
||||
/// when no card is selected, so Edit and Delete over a card would have been offered about the group whose
|
||||
/// contents are showing rather than the one the pointer is on. That fallback is right for a pair of
|
||||
/// buttons that sit beside the heading and wrong for a menu that opened on a card.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Cancelled outright over the space around the cards, as the host grid's is. That is not a group, and
|
||||
/// the fallback is exactly what would make the menu look like it worked there.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
private void OnGroupContextRequested(object? sender, ContextRequestedEventArgs e)
|
||||
{
|
||||
if (Vault is not { } vault || RowUnder(e.Source) is not HostGroupRowViewModel row)
|
||||
{
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
vault.SelectedGroup = row;
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// Remembered rather than acted on. Whether this press is a click or the start of a drag is not known
|
||||
/// until the pointer moves, so this is the point at which both are still possible.
|
||||
|
||||
Reference in New Issue
Block a user