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

View File

@ -42,11 +42,11 @@ HistoryList::HistoryList()
void HistoryList::ListView_ItemClick(_In_ Object ^ sender, _In_ ItemClickEventArgs ^ e)
{
HistoryViewModel ^ historyVM = static_cast<HistoryViewModel ^>(this->DataContext);
HistoryItemViewModel ^ clickedItem = safe_cast<HistoryItemViewModel ^>(e->ClickedItem);
HistoryViewModel^ historyVM = dynamic_cast<HistoryViewModel ^>(this->DataContext);
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
if (clickedItem != nullptr)
if (clickedItem != nullptr && historyVM != nullptr)
{
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)
{
auto clickedItem = safe_cast<HistoryItemViewModel ^>(safe_cast<FrameworkElement ^>(sender)->DataContext);
Model->DeleteItem(clickedItem);
auto listViewItem = HistoryContextMenu->Target;
auto itemViewModel = dynamic_cast<HistoryItemViewModel ^>(HistoryListView->ItemFromContainer(listViewItem));
if (itemViewModel != nullptr)
{
Model->DeleteItem(itemViewModel);
}
}
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);
}
}
void HistoryList::ScrollToBottom()

View File

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

View File

@ -39,7 +39,6 @@ Memory::Memory()
: m_isErrorVisualState(false)
{
InitializeComponent();
m_memoryItemFlyout = safe_cast<MenuFlyout ^>(Resources->Lookup("MemoryContextMenu"));
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)
{
GetMemoryItemForCurrentFlyout()->Clear();
auto memoryItem = GetMemoryItemForCurrentFlyout();
if (memoryItem != nullptr)
{
memoryItem->Clear();
}
}
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)
{
GetMemoryItemForCurrentFlyout()->MemorySubtract();
auto memoryItem = GetMemoryItemForCurrentFlyout();
if (memoryItem != nullptr)
{
memoryItem->MemorySubtract();
}
}
bool Memory::IsErrorVisualState::get()
@ -122,7 +99,6 @@ void Memory::IsErrorVisualState::set(bool value)
MemoryItemViewModel ^ Memory::GetMemoryItemForCurrentFlyout()
{
auto listViewItem = m_memoryItemFlyout->Target;
return safe_cast<MemoryItemViewModel ^>(MemoryListView->ItemFromContainer(listViewItem));
auto listViewItem = MemoryContextMenu->Target;
return dynamic_cast<MemoryItemViewModel ^>(MemoryListView->ItemFromContainer(listViewItem));
}

View File

@ -36,14 +36,11 @@ namespace CalculatorApp
}
private:
Windows::UI::Xaml::Controls::MenuFlyout ^ m_memoryItemFlyout;
Windows::Foundation::Rect m_visibleBounds;
Windows::Foundation::Rect m_coreBounds;
bool m_isErrorVisualState;
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 OnMemoryAddMenuItemClicked(_In_ Platform::Object ^ sender, _In_ Windows::UI::Xaml::RoutedEventArgs ^ e);
void OnMemorySubtractMenuItemClicked(_In_ Platform::Object ^ sender, _In_ Windows::UI::Xaml::RoutedEventArgs ^ e);