Make History and Memory list items context menu accessible using keyboard (#432)

* Move History and Memory context menus to ListViewItemContainer so users can open them with keyboards

* replace static_cast by dynamic_cast
This commit is contained in:
Rudy Huyn 2019-07-16 14:24:27 -07:00 committed by Pepe Rivera
parent 5b59bdcb60
commit 23550f751c
5 changed files with 36 additions and 60 deletions

View File

@ -49,7 +49,7 @@
Invoked="OnDeleteSwipeInvoked"/> Invoked="OnDeleteSwipeInvoked"/>
</muxc:SwipeItems> </muxc:SwipeItems>
<MenuFlyout x:Key="HistoryContextMenu"> <MenuFlyout x:Name="HistoryContextMenu">
<MenuFlyoutItem x:Uid="DeleteHistoryMenuItem" <MenuFlyoutItem x:Uid="DeleteHistoryMenuItem"
Click="OnDeleteMenuItemClicked" Click="OnDeleteMenuItemClicked"
Icon="Delete"/> Icon="Delete"/>
@ -57,9 +57,7 @@
<DataTemplate x:Key="HistoryItemTemplate" x:DataType="model:HistoryItemViewModel"> <DataTemplate x:Key="HistoryItemTemplate" x:DataType="model:HistoryItemViewModel">
<muxc:SwipeControl RightItems="{StaticResource HistorySwipeItems}"> <muxc:SwipeControl RightItems="{StaticResource HistorySwipeItems}">
<StackPanel Margin="0,6,4,6" <StackPanel Margin="0,6,4,6" Background="Transparent">
Background="Transparent"
ContextFlyout="{StaticResource HistoryContextMenu}">
<TextBlock x:Name="ExprTextBlock" <TextBlock x:Name="ExprTextBlock"
Margin="0,0,0,4" Margin="0,0,0,4"
HorizontalAlignment="Right" HorizontalAlignment="Right"
@ -85,6 +83,7 @@
BasedOn="{StaticResource HistoryMemoryItemContainerStyle}" BasedOn="{StaticResource HistoryMemoryItemContainerStyle}"
TargetType="ListViewItem"> TargetType="ListViewItem">
<Setter Property="Margin" Value="0,0,0,20"/> <Setter Property="Margin" Value="0,0,0,20"/>
<Setter Property="ContextFlyout" Value="{StaticResource HistoryContextMenu}"/>
</Style> </Style>
</ResourceDictionary> </ResourceDictionary>
</UserControl.Resources> </UserControl.Resources>

View File

@ -42,11 +42,11 @@ HistoryList::HistoryList()
void HistoryList::ListView_ItemClick(_In_ Object ^ sender, _In_ ItemClickEventArgs ^ e) void HistoryList::ListView_ItemClick(_In_ Object ^ sender, _In_ ItemClickEventArgs ^ e)
{ {
HistoryViewModel ^ historyVM = static_cast<HistoryViewModel ^>(this->DataContext); HistoryViewModel^ historyVM = dynamic_cast<HistoryViewModel ^>(this->DataContext);
HistoryItemViewModel ^ clickedItem = safe_cast<HistoryItemViewModel ^>(e->ClickedItem); HistoryItemViewModel^ clickedItem = dynamic_cast<HistoryItemViewModel ^>(e->ClickedItem);
// When the user clears the history list in the overlay view and presses enter, the clickedItem is nullptr // When the user clears the history list in the overlay view and presses enter, the clickedItem is nullptr
if (clickedItem != nullptr) if (clickedItem != nullptr && historyVM != nullptr)
{ {
historyVM->ShowItem(clickedItem); historyVM->ShowItem(clickedItem);
} }
@ -54,16 +54,21 @@ void HistoryList::ListView_ItemClick(_In_ Object ^ sender, _In_ ItemClickEventAr
void HistoryList::OnDeleteMenuItemClicked(_In_ Object ^ sender, _In_ RoutedEventArgs ^ e) void HistoryList::OnDeleteMenuItemClicked(_In_ Object ^ sender, _In_ RoutedEventArgs ^ e)
{ {
auto clickedItem = safe_cast<HistoryItemViewModel ^>(safe_cast<FrameworkElement ^>(sender)->DataContext); auto listViewItem = HistoryContextMenu->Target;
auto itemViewModel = dynamic_cast<HistoryItemViewModel ^>(HistoryListView->ItemFromContainer(listViewItem));
Model->DeleteItem(clickedItem); if (itemViewModel != nullptr)
{
Model->DeleteItem(itemViewModel);
}
} }
void HistoryList::OnDeleteSwipeInvoked(_In_ MUXC::SwipeItem ^ sender, _In_ MUXC::SwipeItemInvokedEventArgs ^ e) void HistoryList::OnDeleteSwipeInvoked(_In_ MUXC::SwipeItem ^ sender, _In_ MUXC::SwipeItemInvokedEventArgs ^ e)
{ {
auto swipedItem = safe_cast<HistoryItemViewModel ^>(e->SwipeControl->DataContext); auto swipedItem = dynamic_cast<HistoryItemViewModel ^>(e->SwipeControl->DataContext);
if (swipedItem != nullptr)
Model->DeleteItem(swipedItem); {
Model->DeleteItem(swipedItem);
}
} }
void HistoryList::ScrollToBottom() void HistoryList::ScrollToBottom()

View File

@ -17,7 +17,7 @@
<converters:BooleanToVisibilityNegationConverter x:Key="BooleanToVisibilityNegationConverter"/> <converters:BooleanToVisibilityNegationConverter x:Key="BooleanToVisibilityNegationConverter"/>
<converters:BooleanNegationConverter x:Key="BooleanNegationConverter"/> <converters:BooleanNegationConverter x:Key="BooleanNegationConverter"/>
<MenuFlyout x:Key="MemoryContextMenu"> <MenuFlyout x:Name="MemoryContextMenu">
<MenuFlyoutItem x:Uid="ClearMemoryMenuItem" Click="OnClearMenuItemClicked"> <MenuFlyoutItem x:Uid="ClearMemoryMenuItem" Click="OnClearMenuItemClicked">
<MenuFlyoutItem.Icon> <MenuFlyoutItem.Icon>
<FontIcon FontFamily="{StaticResource CalculatorFontFamily}" Glyph="&#xf754;"/> <FontIcon FontFamily="{StaticResource CalculatorFontFamily}" Glyph="&#xf754;"/>
@ -42,6 +42,7 @@
BasedOn="{StaticResource HistoryMemoryItemContainerStyle}" BasedOn="{StaticResource HistoryMemoryItemContainerStyle}"
TargetType="ListViewItem"> TargetType="ListViewItem">
<Setter Property="Margin" Value="0,0,0,8"/> <Setter Property="Margin" Value="0,0,0,8"/>
<Setter Property="ContextFlyout" Value="{StaticResource MemoryContextMenu}"/>
</Style> </Style>
</UserControl.Resources> </UserControl.Resources>
@ -103,8 +104,6 @@
<ListView x:Name="MemoryListView" <ListView x:Name="MemoryListView"
Padding="0,12,0,0" Padding="0,12,0,0"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
ContextCanceled="OnContextCanceled"
ContextRequested="OnContextRequested"
IsItemClickEnabled="true" IsItemClickEnabled="true"
ItemClick="MemoryListItemClick" ItemClick="MemoryListItemClick"
ItemContainerStyle="{ThemeResource MemoryItemContainerStyle}" ItemContainerStyle="{ThemeResource MemoryItemContainerStyle}"

View File

@ -39,7 +39,6 @@ Memory::Memory()
: m_isErrorVisualState(false) : m_isErrorVisualState(false)
{ {
InitializeComponent(); InitializeComponent();
m_memoryItemFlyout = safe_cast<MenuFlyout ^>(Resources->Lookup("MemoryContextMenu"));
MemoryPaneEmpty->FlowDirection = LocalizationService::GetInstance()->GetFlowDirection(); MemoryPaneEmpty->FlowDirection = LocalizationService::GetInstance()->GetFlowDirection();
} }
@ -56,53 +55,31 @@ void Memory::MemoryListItemClick(_In_ Object ^ sender, _In_ ItemClickEventArgs ^
} }
} }
void Memory::OnContextRequested(Windows::UI::Xaml::UIElement ^ sender, Windows::UI::Xaml::Input::ContextRequestedEventArgs ^ e)
{
// Walk up the tree to find the ListViewItem.
// There may not be one if the click wasn't on an item.
auto requestedElement = safe_cast<FrameworkElement ^>(e->OriginalSource);
while ((requestedElement != sender) && !dynamic_cast<ListViewItem ^>(requestedElement))
{
requestedElement = safe_cast<FrameworkElement ^>(VisualTreeHelper::GetParent(requestedElement));
}
if (requestedElement != sender)
{
// The context menu request was for a ListViewItem.
auto memorySlot = safe_cast<MemoryItemViewModel ^>(MemoryListView->ItemFromContainer(requestedElement));
Point point;
if (e->TryGetPosition(requestedElement, &point))
{
m_memoryItemFlyout->ShowAt(requestedElement, point);
}
else
{
// Not invoked via pointer, so let XAML choose a default location.
m_memoryItemFlyout->ShowAt(requestedElement);
}
e->Handled = true;
}
}
void Memory::OnContextCanceled(Windows::UI::Xaml::UIElement ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e)
{
m_memoryItemFlyout->Hide();
}
void Memory::OnClearMenuItemClicked(_In_ Object ^ sender, _In_ RoutedEventArgs ^ e) void Memory::OnClearMenuItemClicked(_In_ Object ^ sender, _In_ RoutedEventArgs ^ e)
{ {
GetMemoryItemForCurrentFlyout()->Clear(); auto memoryItem = GetMemoryItemForCurrentFlyout();
if (memoryItem != nullptr)
{
memoryItem->Clear();
}
} }
void Memory::OnMemoryAddMenuItemClicked(_In_ Object ^ sender, _In_ RoutedEventArgs ^ e) void Memory::OnMemoryAddMenuItemClicked(_In_ Object ^ sender, _In_ RoutedEventArgs ^ e)
{ {
GetMemoryItemForCurrentFlyout()->MemoryAdd(); auto memoryItem = GetMemoryItemForCurrentFlyout();
if (memoryItem != nullptr)
{
memoryItem->MemoryAdd();
}
} }
void Memory::OnMemorySubtractMenuItemClicked(_In_ Object ^ sender, _In_ RoutedEventArgs ^ e) void Memory::OnMemorySubtractMenuItemClicked(_In_ Object ^ sender, _In_ RoutedEventArgs ^ e)
{ {
GetMemoryItemForCurrentFlyout()->MemorySubtract(); auto memoryItem = GetMemoryItemForCurrentFlyout();
if (memoryItem != nullptr)
{
memoryItem->MemorySubtract();
}
} }
bool Memory::IsErrorVisualState::get() bool Memory::IsErrorVisualState::get()
@ -122,7 +99,6 @@ void Memory::IsErrorVisualState::set(bool value)
MemoryItemViewModel ^ Memory::GetMemoryItemForCurrentFlyout() MemoryItemViewModel ^ Memory::GetMemoryItemForCurrentFlyout()
{ {
auto listViewItem = m_memoryItemFlyout->Target; auto listViewItem = MemoryContextMenu->Target;
return dynamic_cast<MemoryItemViewModel ^>(MemoryListView->ItemFromContainer(listViewItem));
return safe_cast<MemoryItemViewModel ^>(MemoryListView->ItemFromContainer(listViewItem));
} }

View File

@ -36,14 +36,11 @@ namespace CalculatorApp
} }
private: private:
Windows::UI::Xaml::Controls::MenuFlyout ^ m_memoryItemFlyout;
Windows::Foundation::Rect m_visibleBounds; Windows::Foundation::Rect m_visibleBounds;
Windows::Foundation::Rect m_coreBounds; Windows::Foundation::Rect m_coreBounds;
bool m_isErrorVisualState; bool m_isErrorVisualState;
void MemoryListItemClick(_In_ Platform::Object ^ sender, _In_ Windows::UI::Xaml::Controls::ItemClickEventArgs ^ e); void MemoryListItemClick(_In_ Platform::Object ^ sender, _In_ Windows::UI::Xaml::Controls::ItemClickEventArgs ^ e);
void OnContextRequested(Windows::UI::Xaml::UIElement ^ sender, Windows::UI::Xaml::Input::ContextRequestedEventArgs ^ e);
void OnContextCanceled(Windows::UI::Xaml::UIElement ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
void OnClearMenuItemClicked(_In_ Platform::Object ^ sender, _In_ Windows::UI::Xaml::RoutedEventArgs ^ e); void OnClearMenuItemClicked(_In_ Platform::Object ^ sender, _In_ Windows::UI::Xaml::RoutedEventArgs ^ e);
void OnMemoryAddMenuItemClicked(_In_ Platform::Object ^ sender, _In_ Windows::UI::Xaml::RoutedEventArgs ^ e); void OnMemoryAddMenuItemClicked(_In_ Platform::Object ^ sender, _In_ Windows::UI::Xaml::RoutedEventArgs ^ e);
void OnMemorySubtractMenuItemClicked(_In_ Platform::Object ^ sender, _In_ Windows::UI::Xaml::RoutedEventArgs ^ e); void OnMemorySubtractMenuItemClicked(_In_ Platform::Object ^ sender, _In_ Windows::UI::Xaml::RoutedEventArgs ^ e);