Files
vba10/NavMenuListView.cpp
2015-07-08 13:47:53 +00:00

255 lines
7.5 KiB
C++

#include "NavMenuListView.h"
using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::System;
using namespace Windows::UI::Core;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Documents;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Interop;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Xaml::Media::Animation;
namespace VBA10
{
namespace Controls
{
NavMenuListView::NavMenuListView()
{
this->SelectionMode = ListViewSelectionMode::Single;
this->IsItemClickEnabled = true;
this->ItemClick += ref new ItemClickEventHandler(this, &NavMenuListView::ItemClickHandler);
// Locate the hosting SplitView control
this->Loaded += ref new Windows::UI::Xaml::RoutedEventHandler(this, &VBA10::Controls::NavMenuListView::OnLoaded);
}
void NavMenuListView::OnLoaded(Platform::Object ^sender, Windows::UI::Xaml::RoutedEventArgs ^e)
{
auto parent = VisualTreeHelper::GetParent(this);
while (parent != nullptr && dynamic_cast<SplitView^>(parent) == nullptr)
{
parent = VisualTreeHelper::GetParent((DependencyObject^)parent);
}
if (parent != nullptr)
{
_splitViewHost = dynamic_cast<SplitView^>(parent);
_splitViewHost->RegisterPropertyChangedCallback(
SplitView::IsPaneOpenProperty,
ref new DependencyPropertyChangedCallback(this, &NavMenuListView::IsOpenPanePropertyChangedCallback));
// Call once to ensure we're in the correct state
OnPaneToggled();
}
}
void NavMenuListView::IsOpenPanePropertyChangedCallback(DependencyObject^ sender, DependencyProperty^ args)
{
OnPaneToggled();
}
void NavMenuListView::OnApplyTemplate()
{
ListView::OnApplyTemplate();
// Remove the entrance animation on the item containers.
for (int i = 0; i < (int)ItemContainerTransitions->Size; i++)
{
if (dynamic_cast<EntranceThemeTransition^>(ItemContainerTransitions->GetAt(i)) != nullptr)
{
ItemContainerTransitions->RemoveAt(i);
}
}
}
///// <summary>
///// Custom keyboarding logic to enable movement via the arrow keys without triggering selection
///// until a 'Space' or 'Enter' key is pressed.
///// </summary>
///// <param name="e"></param>
//void NavMenuListView::OnKeyDown(KeyRoutedEventArgs^ e)
//{
// auto focusedItem = FocusManager::GetFocusedElement();
// auto shiftKeyState = CoreWindow::GetForCurrentThread()->GetKeyState(VirtualKey::Shift);
// auto shiftKeyDown = (shiftKeyState & CoreVirtualKeyStates::Down) == CoreVirtualKeyStates::Down;
// switch (e->Key)
// {
// case VirtualKey::Up:
// this->TryMoveFocus(FocusNavigationDirection::Up);
// e->Handled = true;
// break;
// case VirtualKey::Down:
// this->TryMoveFocus(FocusNavigationDirection::Down);
// e->Handled = true;
// break;
// case VirtualKey::Tab:
// // If we're on the header item then this will be null and we'll still get the default behavior.
// if (dynamic_cast<ListViewItem^>(focusedItem) != nullptr)
// {
// auto currentItem = (ListViewItem^)focusedItem;
// bool onlastitem = currentItem != nullptr && IndexFromContainer(currentItem) == Items->Size - 1;
// bool onfirstitem = currentItem != nullptr && IndexFromContainer(currentItem) == 0;
// if (!shiftKeyDown)
// {
// if (onlastitem)
// {
// this->TryMoveFocus(FocusNavigationDirection::Next);
// }
// else
// {
// this->TryMoveFocus(FocusNavigationDirection::Down);
// }
// }
// else // Shift + Tab
// {
// if (onfirstitem)
// {
// this->TryMoveFocus(FocusNavigationDirection::Previous);
// }
// else
// {
// this->TryMoveFocus(FocusNavigationDirection::Up);
// }
// }
// }
// else if (dynamic_cast<Control^>(focusedItem) != nullptr)
// {
// if (!shiftKeyDown)
// {
// this->TryMoveFocus(FocusNavigationDirection::Down);
// }
// else // Shift + Tab
// {
// this->TryMoveFocus(FocusNavigationDirection::Up);
// }
// }
// e->Handled = true;
// break;
// case VirtualKey::Space:
// case VirtualKey::Enter:
// // Fire our event using the item with current keyboard focus
// InvokeItem(focusedItem);
// e->Handled = true;
// break;
// default:
// ListView::OnKeyDown(e);
// break;
// }
//}
/// <summary>
/// This method is a work-around until the bug in FocusManager.TryMoveFocus is fixed.
/// </summary>
/// <param name="direction"></param>
//void NavMenuListView::TryMoveFocus(FocusNavigationDirection direction)
//{
// if (direction == FocusNavigationDirection::Next || direction == FocusNavigationDirection::Previous)
// {
// FocusManager::TryMoveFocus(direction);
// }
// else
// {
// auto control = dynamic_cast<Control^>(FocusManager::FindNextFocusableElement(direction));
// if (control != nullptr)
// {
// control->Focus(Windows::UI::Xaml::FocusState::Programmatic);
// }
// }
//}
void NavMenuListView::ItemClickHandler(Object^ sender, ItemClickEventArgs^ e)
{
// Triggered when the item is selected using something other than a keyboard
auto item = ContainerFromItem(e->ClickedItem);
InvokeItem(item);
}
void NavMenuListView::InvokeItem(Object^ focusedItem)
{
auto item = dynamic_cast<ListViewItem^>(focusedItem);
SetSelectedItem(item);
ItemInvoked(this, item);
//if (_splitViewHost->IsPaneOpen && (
// _splitViewHost->DisplayMode == SplitViewDisplayMode::CompactOverlay ||
// _splitViewHost->DisplayMode == SplitViewDisplayMode::Overlay))
//{
// _splitViewHost->IsPaneOpen = false;
// if (item != nullptr)
// {
// item->Focus(Windows::UI::Xaml::FocusState::Programmatic);
// }
//}
}
/// <summary>
/// Mark the <paramref name="item"/> as selected and ensures everything else is not.
/// If the <paramref name="item"/> is null then everything is unselected.
/// </summary>
/// <param name="item"></param>
void NavMenuListView::SetSelectedItem(ListViewItem^ item)
{
int index = -1;
if (item != nullptr)
{
index = IndexFromContainer(item);
}
for (int i = 0; i < (int)Items->Size; i++)
{
auto lvi = (ListViewItem^)ContainerFromIndex(i);
if (lvi != nullptr)
{
if (i != index)
{
lvi->IsSelected = false;
}
else if (i == index)
{
lvi->IsSelected = true;
}
}
}
}
/// <summary>
/// Re-size the ListView's Panel when the SplitView is compact so the items
/// will fit within the visible space and correctly display a keyboard focus rect.
/// </summary>
void NavMenuListView::OnPaneToggled()
{
if (_splitViewHost->IsPaneOpen)
{
ItemsPanelRoot->ClearValue(FrameworkElement::WidthProperty);
ItemsPanelRoot->ClearValue(FrameworkElement::HorizontalAlignmentProperty);
}
else if (_splitViewHost->DisplayMode == SplitViewDisplayMode::CompactInline ||
_splitViewHost->DisplayMode == SplitViewDisplayMode::CompactOverlay)
{
ItemsPanelRoot->SetValue(FrameworkElement::WidthProperty, _splitViewHost->CompactPaneLength);
ItemsPanelRoot->SetValue(FrameworkElement::HorizontalAlignmentProperty, Windows::UI::Xaml::HorizontalAlignment::Left);
}
}
}
}