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:
		@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 | 
			
		||||
    Model->DeleteItem(swipedItem);
 | 
			
		||||
    auto swipedItem = dynamic_cast<HistoryItemViewModel ^>(e->SwipeControl->DataContext);
 | 
			
		||||
    if (swipedItem != nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        Model->DeleteItem(swipedItem);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HistoryList::ScrollToBottom()
 | 
			
		||||
 
 | 
			
		||||
@@ -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=""/>
 | 
			
		||||
@@ -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}"
 | 
			
		||||
 
 | 
			
		||||
@@ -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));
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user