Replace AppChromeAcrylicHostBackdropMediumLowBrush from OverflowTextBlock + improvements (#647)
* replace acrylic brush by margin/padding * Modify how the control manages the focus * remove comment * Prevent deadlock
This commit is contained in:
committed by
Stephanie Anderl
parent
98908c627f
commit
c877b0a2e9
@@ -27,9 +27,12 @@ using namespace Windows::UI::Xaml::Navigation;
|
||||
DEPENDENCY_PROPERTY_INITIALIZATION(OverflowTextBlock, IsActive);
|
||||
DEPENDENCY_PROPERTY_INITIALIZATION(OverflowTextBlock, TextStyle);
|
||||
DEPENDENCY_PROPERTY_INITIALIZATION(OverflowTextBlock, TokensUpdated);
|
||||
DEPENDENCY_PROPERTY_INITIALIZATION(OverflowTextBlock, ColumnWidth);
|
||||
DEPENDENCY_PROPERTY_INITIALIZATION(OverflowTextBlock, ColumnHeight);
|
||||
DEPENDENCY_PROPERTY_INITIALIZATION(OverflowTextBlock, ScrollButtonFontSize);
|
||||
DEPENDENCY_PROPERTY_INITIALIZATION(OverflowTextBlock, ScrollButtonsWidth);
|
||||
DEPENDENCY_PROPERTY_INITIALIZATION(OverflowTextBlock, ScrollButtonsFontSize);
|
||||
DEPENDENCY_PROPERTY_INITIALIZATION(OverflowTextBlock, ScrollButtonsPlacement);
|
||||
|
||||
static constexpr unsigned int SCROLL_BUTTONS_APPROXIMATION_RANGE = 4;
|
||||
static constexpr double SCROLL_RATIO = 0.7;
|
||||
|
||||
void OverflowTextBlock::OnApplyTemplate()
|
||||
{
|
||||
@@ -44,35 +47,32 @@ void OverflowTextBlock::OnApplyTemplate()
|
||||
ref new EventHandler<ScrollViewerViewChangedEventArgs ^>(this, &OverflowTextBlock::OnViewChanged);
|
||||
}
|
||||
|
||||
uiElement = GetTemplateChild("ExpressionContent");
|
||||
if (uiElement != nullptr)
|
||||
{
|
||||
m_expressionContent = safe_cast<FrameworkElement ^>(uiElement);
|
||||
}
|
||||
|
||||
uiElement = GetTemplateChild("ScrollLeft");
|
||||
if (uiElement != nullptr)
|
||||
{
|
||||
m_scrollLeft = safe_cast<Button ^>(uiElement);
|
||||
m_scrollLeftClickEventToken = m_scrollLeft->Click += ref new RoutedEventHandler(this, &OverflowTextBlock::OnScrollClick);
|
||||
m_scrollLeftClickEventToken = m_scrollLeft->Click += ref new RoutedEventHandler(this, &OverflowTextBlock::OnScrollLeftClick);
|
||||
}
|
||||
|
||||
uiElement = GetTemplateChild("ScrollRight");
|
||||
if (uiElement != nullptr)
|
||||
{
|
||||
m_scrollRight = safe_cast<Button ^>(uiElement);
|
||||
m_scrollRightClickEventToken = m_scrollRight->Click += ref new RoutedEventHandler(this, &OverflowTextBlock::OnScrollClick);
|
||||
m_scrollRightClickEventToken = m_scrollRight->Click += ref new RoutedEventHandler(this, &OverflowTextBlock::OnScrollRightClick);
|
||||
}
|
||||
|
||||
m_scrollingLeft = false;
|
||||
m_scrollingRight = false;
|
||||
|
||||
uiElement = GetTemplateChild("TokenList");
|
||||
if (uiElement != nullptr)
|
||||
{
|
||||
m_itemsControl = safe_cast<ItemsControl ^>(uiElement);
|
||||
}
|
||||
|
||||
uiElement = GetTemplateChild("EditableToken");
|
||||
if (uiElement != nullptr)
|
||||
{
|
||||
m_editableToken = safe_cast<TextBlock ^>(uiElement);
|
||||
}
|
||||
|
||||
UpdateAllState();
|
||||
}
|
||||
|
||||
@@ -118,8 +118,7 @@ void OverflowTextBlock::ScrollLeft()
|
||||
{
|
||||
if (m_expressionContainer != nullptr && m_expressionContainer->HorizontalOffset > 0)
|
||||
{
|
||||
m_scrollingLeft = true;
|
||||
double offset = m_expressionContainer->HorizontalOffset - (scrollRatio * m_expressionContainer->ViewportWidth);
|
||||
double offset = m_expressionContainer->HorizontalOffset - (SCROLL_RATIO * m_expressionContainer->ViewportWidth);
|
||||
m_expressionContainer->ChangeView(offset, nullptr, nullptr);
|
||||
m_expressionContainer->UpdateLayout();
|
||||
UpdateScrollButtons();
|
||||
@@ -128,93 +127,80 @@ void OverflowTextBlock::ScrollLeft()
|
||||
|
||||
void OverflowTextBlock::ScrollRight()
|
||||
{
|
||||
if (m_expressionContainer != nullptr && m_expressionContainer->HorizontalOffset < m_expressionContainer->ExtentWidth - m_expressionContainer->ViewportWidth)
|
||||
auto realOffset = m_expressionContainer->HorizontalOffset + m_expressionContainer->Padding.Left + m_expressionContent->Margin.Left;
|
||||
if (m_expressionContainer != nullptr && realOffset + m_expressionContainer->ActualWidth < m_expressionContent->ActualWidth)
|
||||
{
|
||||
m_scrollingRight = true;
|
||||
double offset = m_expressionContainer->HorizontalOffset + (scrollRatio * m_expressionContainer->ViewportWidth);
|
||||
double offset = m_expressionContainer->HorizontalOffset + (SCROLL_RATIO * m_expressionContainer->ViewportWidth);
|
||||
m_expressionContainer->ChangeView(offset, nullptr, nullptr);
|
||||
m_expressionContainer->UpdateLayout();
|
||||
UpdateScrollButtons();
|
||||
}
|
||||
}
|
||||
|
||||
void OverflowTextBlock::OnScrollClick(_In_ Object ^ sender, _In_ RoutedEventArgs ^)
|
||||
void OverflowTextBlock::OnScrollLeftClick(_In_ Object ^ sender, _In_ RoutedEventArgs ^)
|
||||
{
|
||||
auto clicked = safe_cast<Button ^>(sender);
|
||||
if (clicked == m_scrollLeft)
|
||||
{
|
||||
ScrollLeft();
|
||||
}
|
||||
else
|
||||
{
|
||||
ScrollRight();
|
||||
}
|
||||
ScrollLeft();
|
||||
}
|
||||
|
||||
void OverflowTextBlock::OnScrollRightClick(_In_ Object ^ sender, _In_ RoutedEventArgs ^)
|
||||
{
|
||||
ScrollRight();
|
||||
}
|
||||
|
||||
void OverflowTextBlock::UpdateScrollButtons()
|
||||
{
|
||||
if (m_expressionContainer == nullptr)
|
||||
if (m_expressionContainer == nullptr || m_scrollLeft == nullptr || m_scrollRight == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
double editableTokenWidth = 0;
|
||||
if (m_editableToken != nullptr && m_editableToken->Visibility == ::Visibility::Visible)
|
||||
{
|
||||
editableTokenWidth = m_editableToken->ActualWidth;
|
||||
}
|
||||
auto realOffset = m_expressionContainer->HorizontalOffset + m_expressionContainer->Padding.Left + m_expressionContent->Margin.Left;
|
||||
auto scrollLeftVisibility = realOffset > SCROLL_BUTTONS_APPROXIMATION_RANGE ? ::Visibility::Visible : ::Visibility::Collapsed;
|
||||
auto scrollRightVisibility = realOffset + m_expressionContainer->ActualWidth + SCROLL_BUTTONS_APPROXIMATION_RANGE < m_expressionContent->ActualWidth
|
||||
? ::Visibility::Visible
|
||||
: ::Visibility::Collapsed;
|
||||
|
||||
double itemsControlWidth = 0;
|
||||
if (m_itemsControl != nullptr && m_itemsControl->Visibility == ::Visibility::Visible)
|
||||
bool shouldTryFocusScrollRight = false;
|
||||
if (m_scrollLeft->Visibility != scrollLeftVisibility)
|
||||
{
|
||||
itemsControlWidth = m_itemsControl->ActualWidth;
|
||||
}
|
||||
|
||||
// When the width is smaller than the container, don't show any
|
||||
if (itemsControlWidth + editableTokenWidth <= m_expressionContainer->ActualWidth)
|
||||
{
|
||||
ShowHideScrollButtons(::Visibility::Collapsed, ::Visibility::Collapsed);
|
||||
}
|
||||
// We have more number on both side. Show both arrows
|
||||
else if (
|
||||
(m_expressionContainer->HorizontalOffset > 0)
|
||||
&& (m_expressionContainer->HorizontalOffset < (m_expressionContainer->ExtentWidth - m_expressionContainer->ViewportWidth)))
|
||||
{
|
||||
ShowHideScrollButtons(::Visibility::Visible, ::Visibility::Visible);
|
||||
}
|
||||
// Width is larger than the container and left most part of the number is shown. Should be able to scroll right.
|
||||
else if (m_expressionContainer->HorizontalOffset == 0)
|
||||
{
|
||||
ShowHideScrollButtons(::Visibility::Collapsed, ::Visibility::Visible);
|
||||
if (m_scrollingLeft)
|
||||
if (scrollLeftVisibility == ::Visibility::Collapsed)
|
||||
{
|
||||
m_scrollingLeft = false;
|
||||
if (m_scrollRight != nullptr)
|
||||
{
|
||||
m_scrollRight->Focus(::FocusState::Programmatic);
|
||||
}
|
||||
shouldTryFocusScrollRight = m_scrollLeft->Equals(FocusManager::GetFocusedElement());
|
||||
}
|
||||
}
|
||||
else // Width is larger than the container and right most part of the number is shown. Should be able to scroll left.
|
||||
{
|
||||
ShowHideScrollButtons(::Visibility::Visible, ::Visibility::Collapsed);
|
||||
if (m_scrollingRight)
|
||||
{
|
||||
m_scrollingRight = false;
|
||||
if (m_scrollLeft != nullptr)
|
||||
{
|
||||
m_scrollLeft->Focus(::FocusState::Programmatic);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OverflowTextBlock::ShowHideScrollButtons(::Visibility vLeft, ::Visibility vRight)
|
||||
{
|
||||
if (m_scrollLeft != nullptr && m_scrollRight != nullptr)
|
||||
m_scrollLeft->Visibility = scrollLeftVisibility;
|
||||
}
|
||||
|
||||
if (m_scrollRight->Visibility != scrollRightVisibility)
|
||||
{
|
||||
m_scrollLeft->Visibility = vLeft;
|
||||
m_scrollRight->Visibility = vRight;
|
||||
if (scrollRightVisibility == ::Visibility::Collapsed && m_scrollLeft->Visibility == ::Visibility::Visible
|
||||
&& m_scrollRight->Equals(FocusManager::GetFocusedElement()))
|
||||
{
|
||||
m_scrollLeft->Focus(::FocusState::Programmatic);
|
||||
}
|
||||
m_scrollRight->Visibility = scrollRightVisibility;
|
||||
}
|
||||
|
||||
if (shouldTryFocusScrollRight && scrollRightVisibility == ::Visibility::Visible)
|
||||
{
|
||||
m_scrollRight->Focus(::FocusState::Programmatic);
|
||||
}
|
||||
|
||||
if (ScrollButtonsPlacement == OverflowButtonPlacement::Above && m_expressionContent != nullptr)
|
||||
{
|
||||
double left = m_scrollLeft != nullptr && m_scrollLeft->Visibility == ::Visibility::Visible ? ScrollButtonsWidth : 0;
|
||||
double right = m_scrollRight != nullptr && m_scrollRight->Visibility == ::Visibility::Visible ? ScrollButtonsWidth : 0;
|
||||
if (m_expressionContainer->Padding.Left != left || m_expressionContainer->Padding.Right != right)
|
||||
{
|
||||
m_expressionContainer->ViewChanged -= m_containerViewChangedToken;
|
||||
|
||||
m_expressionContainer->Padding = Thickness(left, 0, right, 0);
|
||||
m_expressionContent->Margin = Thickness(-left, 0, -right, 0);
|
||||
m_expressionContainer->UpdateLayout();
|
||||
|
||||
m_containerViewChangedToken = m_expressionContainer->ViewChanged +=
|
||||
ref new EventHandler<ScrollViewerViewChangedEventArgs ^>(this, &OverflowTextBlock::OnViewChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,3 +227,13 @@ void OverflowTextBlock::OnViewChanged(_In_opt_ Object ^ /*sender*/, _In_opt_ Scr
|
||||
{
|
||||
UpdateScrollButtons();
|
||||
}
|
||||
|
||||
void OverflowTextBlock::OnScrollButtonsPlacementPropertyChanged(OverflowButtonPlacement /*oldValue*/, OverflowButtonPlacement newValue)
|
||||
{
|
||||
if (newValue == OverflowButtonPlacement::InLine)
|
||||
{
|
||||
m_expressionContainer->Padding = Thickness(0);
|
||||
m_expressionContent->Margin = Thickness(0);
|
||||
}
|
||||
UpdateScrollButtons();
|
||||
}
|
||||
|
@@ -9,6 +9,13 @@ namespace CalculatorApp
|
||||
{
|
||||
namespace Controls
|
||||
{
|
||||
public
|
||||
enum class OverflowButtonPlacement : int
|
||||
{
|
||||
InLine,
|
||||
Above
|
||||
};
|
||||
|
||||
public
|
||||
ref class OverflowTextBlock sealed : public Windows::UI::Xaml::Controls::Control
|
||||
{
|
||||
@@ -19,13 +26,14 @@ namespace CalculatorApp
|
||||
|
||||
DEPENDENCY_PROPERTY_OWNER(OverflowTextBlock);
|
||||
DEPENDENCY_PROPERTY_WITH_CALLBACK(bool, TokensUpdated);
|
||||
DEPENDENCY_PROPERTY_WITH_CALLBACK(OverflowButtonPlacement, ScrollButtonsPlacement);
|
||||
DEPENDENCY_PROPERTY(bool, IsActive);
|
||||
DEPENDENCY_PROPERTY(Windows::UI::Xaml::Style ^, TextStyle);
|
||||
DEPENDENCY_PROPERTY(double, ColumnWidth);
|
||||
DEPENDENCY_PROPERTY(double, ColumnHeight);
|
||||
DEPENDENCY_PROPERTY(double, ScrollButtonFontSize);
|
||||
DEPENDENCY_PROPERTY(double, ScrollButtonsWidth);
|
||||
DEPENDENCY_PROPERTY(double, ScrollButtonsFontSize);
|
||||
|
||||
void OnTokensUpdatedPropertyChanged(bool oldValue, bool newValue);
|
||||
void OnScrollButtonsPlacementPropertyChanged(OverflowButtonPlacement oldValue, OverflowButtonPlacement newValue);
|
||||
void UpdateScrollButtons();
|
||||
void UnregisterEventHandlers();
|
||||
|
||||
@@ -34,23 +42,17 @@ namespace CalculatorApp
|
||||
virtual Windows::UI::Xaml::Automation::Peers::AutomationPeer ^ OnCreateAutomationPeer() override;
|
||||
|
||||
private:
|
||||
void OnScrollClick(_In_ Platform::Object ^ sender, _In_ Windows::UI::Xaml::RoutedEventArgs ^ e);
|
||||
void OnPointerEntered(_In_ Platform::Object ^ sender, _In_ Windows::UI::Xaml::Input::PointerRoutedEventArgs ^ e);
|
||||
void OnPointerExited(_In_ Platform::Object ^ sender, _In_ Windows::UI::Xaml::Input::PointerRoutedEventArgs ^ e);
|
||||
void ShowHideScrollButtons(Windows::UI::Xaml::Visibility vLeft, Windows::UI::Xaml::Visibility vRight);
|
||||
void OnScrollLeftClick(_In_ Platform::Object ^ sender, _In_ Windows::UI::Xaml::RoutedEventArgs ^ e);
|
||||
void OnScrollRightClick(_In_ Platform::Object ^ sender, _In_ Windows::UI::Xaml::RoutedEventArgs ^ e);
|
||||
void OnViewChanged(_In_opt_ Platform::Object ^ sender, _In_opt_ Windows::UI::Xaml::Controls::ScrollViewerViewChangedEventArgs ^ args);
|
||||
|
||||
void UpdateVisualState();
|
||||
void UpdateExpressionState();
|
||||
void UpdateAllState();
|
||||
void ScrollLeft();
|
||||
void ScrollRight();
|
||||
|
||||
double scrollRatio = 0.7;
|
||||
bool m_scrollingLeft;
|
||||
bool m_scrollingRight;
|
||||
bool m_isAccessibilityViewControl;
|
||||
Windows::UI::Xaml::Controls::TextBlock ^ m_editableToken;
|
||||
Windows::UI::Xaml::FrameworkElement ^ m_expressionContent;
|
||||
Windows::UI::Xaml::Controls::ItemsControl ^ m_itemsControl;
|
||||
Windows::UI::Xaml::Controls::ScrollViewer ^ m_expressionContainer;
|
||||
Windows::UI::Xaml::Controls::Button ^ m_scrollLeft;
|
||||
|
Reference in New Issue
Block a user