Decrease CPU usage of OverflowTextBlock + optimization (#403)
Fixes #402 and #414 Divide by 4 the CPU usage of OverflowTextBlock when buttons are pressed very quickly. Description of the changes: Xaml-side: OverflowTextBlock has some performance issues: double scrollviewer: the listview was in a scrollviewer, while the control already containing one -> it breaks the virtualization of the listview and impacts on UI performance. The listview used a StackPanel, this panel doesn't support virtualization of ListViewItems contrary to ItemsStackPanel No ListView-specific features were used, an ItemsControl is more efficient and lighter. refactor how we manage the visibility of the left/right buttons in OverflowTextBlock, the new version is more reactive and will not display the right arrow when not necessary (see GIF below). remove the ItemContainerSelector ExpressionItemContainerStyle, not really used by OverflowTextBlock remove UI glitches generated by ChangeView when users type fast (control partially hidden and scrolling issues, see the GIF below). only modify the accessibility view when it's necessary ViewModel-side: stop fully refreshing ExpressionTokens in StandardCalculatorViewModel when a new command were sent, instead, use a IObservableVector to only send new tokens to the UI (in average only 1 or 2 UI items are refreshed while the full expression was refreshed before) How changes were validated: Manually
This commit is contained in:
Родитель
d21a47d5a1
Коммит
de65db6197
|
@ -66,6 +66,7 @@ StandardCalculatorViewModel::StandardCalculatorViewModel() :
|
|||
m_BinaryDisplayValue(L"0"),
|
||||
m_OctalDisplayValue(L"0"),
|
||||
m_standardCalculatorManager(&m_calculatorDisplay, &m_resourceProvider),
|
||||
m_ExpressionTokens(ref new Vector<DisplayExpressionToken^>()),
|
||||
m_MemorizedNumbers(ref new Vector<MemoryItemViewModel^>()),
|
||||
m_IsMemoryEmpty(true),
|
||||
m_IsFToEChecked(false),
|
||||
|
@ -314,59 +315,67 @@ void StandardCalculatorViewModel::SetTokens(_Inout_ shared_ptr<CalculatorVector<
|
|||
{
|
||||
AreTokensUpdated = false;
|
||||
|
||||
if (m_ExpressionTokens == nullptr)
|
||||
{
|
||||
m_ExpressionTokens = ref new Vector<DisplayExpressionToken^>();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ExpressionTokens->Clear();
|
||||
}
|
||||
|
||||
unsigned int nTokens = 0;
|
||||
tokens->GetSize(&nTokens);
|
||||
|
||||
if (nTokens == 0)
|
||||
{
|
||||
m_ExpressionTokens->Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
pair <wstring, int> currentToken;
|
||||
const auto& localizer = LocalizationSettings::GetInstance();
|
||||
|
||||
const wstring separator = L" ";
|
||||
for (unsigned int i = 0; i < nTokens; ++i)
|
||||
{
|
||||
if (SUCCEEDED(tokens->GetAt(i, ¤tToken)))
|
||||
{
|
||||
Common::TokenType type;
|
||||
const wstring separator = L" ";
|
||||
bool isEditable = (currentToken.second == -1) ? false : true;
|
||||
localizer.LocalizeDisplayValue(&(currentToken.first));
|
||||
|
||||
if (!isEditable)
|
||||
{
|
||||
if (currentToken.first == separator)
|
||||
{
|
||||
type = TokenType::Separator;
|
||||
}
|
||||
else
|
||||
{
|
||||
type = TokenType::Operator;
|
||||
}
|
||||
type = currentToken.first == separator ? TokenType::Separator : TokenType::Operator;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
shared_ptr<IExpressionCommand> command;
|
||||
IFTPlatformException(m_commands->GetAt(static_cast<unsigned int>(currentToken.second), &command));
|
||||
type = command->GetCommandType() == CommandType::OperandCommand ? TokenType::Operand : TokenType::Operator;
|
||||
}
|
||||
|
||||
if (command->GetCommandType() == CommandType::OperandCommand)
|
||||
auto currentTokenString = ref new String(currentToken.first.c_str());
|
||||
if (i < m_ExpressionTokens->Size)
|
||||
{
|
||||
auto existingItem = m_ExpressionTokens->GetAt(i);
|
||||
if (type == existingItem->Type && existingItem->Token->Equals(currentTokenString))
|
||||
{
|
||||
type = TokenType::Operand;
|
||||
existingItem->TokenPosition = i;
|
||||
existingItem->IsTokenEditable = isEditable;
|
||||
existingItem->CommandIndex = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
type = TokenType::Operator;
|
||||
auto expressionToken = ref new DisplayExpressionToken(currentTokenString, i, isEditable, type);
|
||||
m_ExpressionTokens->InsertAt(i, expressionToken);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
auto expressionToken = ref new DisplayExpressionToken(currentTokenString, i, isEditable, type);
|
||||
m_ExpressionTokens->Append(expressionToken);
|
||||
}
|
||||
DisplayExpressionToken^ expressionToken = ref new DisplayExpressionToken(ref new String(currentToken.first.c_str()), i, isEditable, type);
|
||||
m_ExpressionTokens->Append(expressionToken);
|
||||
}
|
||||
}
|
||||
|
||||
while (m_ExpressionTokens->Size != nTokens)
|
||||
{
|
||||
m_ExpressionTokens->RemoveAtEnd();
|
||||
}
|
||||
}
|
||||
|
||||
String^ StandardCalculatorViewModel::GetCalculatorExpressionAutomationName()
|
||||
|
@ -524,7 +533,7 @@ void StandardCalculatorViewModel::HandleUpdatedOperandData(Command cmdenum)
|
|||
{
|
||||
if (commandIndex == 0)
|
||||
{
|
||||
delete [] temp;
|
||||
delete[] temp;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -545,7 +554,7 @@ void StandardCalculatorViewModel::HandleUpdatedOperandData(Command cmdenum)
|
|||
length = m_selectedExpressionLastData->Length() + 1;
|
||||
if (length > 50)
|
||||
{
|
||||
delete [] temp;
|
||||
delete[] temp;
|
||||
return;
|
||||
}
|
||||
for (; i < length; ++i)
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace CalculatorApp
|
|||
OBSERVABLE_NAMED_PROPERTY_RW(bool, IsInError);
|
||||
OBSERVABLE_PROPERTY_RW(bool, IsOperatorCommand);
|
||||
OBSERVABLE_PROPERTY_RW(Platform::String^, DisplayStringExpression);
|
||||
OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IVector<Common::DisplayExpressionToken^>^, ExpressionTokens);
|
||||
OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector<Common::DisplayExpressionToken^>^, ExpressionTokens);
|
||||
OBSERVABLE_PROPERTY_RW(Platform::String^, DecimalDisplayValue);
|
||||
OBSERVABLE_PROPERTY_RW(Platform::String^, HexDisplayValue);
|
||||
OBSERVABLE_PROPERTY_RW(Platform::String^, OctalDisplayValue);
|
||||
|
|
|
@ -243,7 +243,6 @@
|
|||
<ClInclude Include="Converters\BitFlipAutomationNameConverter.h" />
|
||||
<ClInclude Include="Converters\BooleanNegationConverter.h" />
|
||||
<ClInclude Include="Converters\BooleanToVisibilityConverter.h" />
|
||||
<ClInclude Include="Converters\ExpressionItemContainerStyle.h" />
|
||||
<ClInclude Include="Converters\ExpressionItemTemplateSelector.h" />
|
||||
<ClInclude Include="Converters\ItemSizeToVisibilityConverter.h" />
|
||||
<ClInclude Include="Converters\RadixToStringConverter.h" />
|
||||
|
@ -375,7 +374,6 @@
|
|||
<ClCompile Include="Converters\BitFlipAutomationNameConverter.cpp" />
|
||||
<ClCompile Include="Converters\BooleanNegationConverter.cpp" />
|
||||
<ClCompile Include="Converters\BooleanToVisibilityConverter.cpp" />
|
||||
<ClCompile Include="Converters\ExpressionItemContainerStyle.cpp" />
|
||||
<ClCompile Include="Converters\ExpressionItemTemplateSelector.cpp" />
|
||||
<ClCompile Include="Converters\ItemSizeToVisibilityConverter.cpp" />
|
||||
<ClCompile Include="Converters\RadixToStringConverter.cpp" />
|
||||
|
|
|
@ -243,9 +243,6 @@
|
|||
<ClCompile Include="Converters\BooleanToVisibilityConverter.cpp">
|
||||
<Filter>Converters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Converters\ExpressionItemContainerStyle.cpp">
|
||||
<Filter>Converters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Converters\ExpressionItemTemplateSelector.cpp">
|
||||
<Filter>Converters</Filter>
|
||||
</ClCompile>
|
||||
|
@ -333,9 +330,6 @@
|
|||
<ClInclude Include="Converters\BooleanToVisibilityConverter.h">
|
||||
<Filter>Converters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Converters\ExpressionItemContainerStyle.h">
|
||||
<Filter>Converters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Converters\ExpressionItemTemplateSelector.h">
|
||||
<Filter>Converters</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
@ -30,25 +30,38 @@ DEPENDENCY_PROPERTY_INITIALIZATION(OverflowTextBlock, TokensUpdated);
|
|||
|
||||
void OverflowTextBlock::OnApplyTemplate()
|
||||
{
|
||||
assert(((m_scrollLeft == nullptr) && (m_scrollRight == nullptr)) || ((m_scrollLeft != nullptr) && (m_scrollRight != nullptr)));
|
||||
UnregisterEventHandlers();
|
||||
|
||||
m_expressionContainer = safe_cast<ScrollViewer^>(GetTemplateChild("expressionContainer"));
|
||||
m_expressionContainer->ChangeView(m_expressionContainer->ExtentWidth - m_expressionContainer->ViewportWidth, nullptr, nullptr);
|
||||
auto uiElement = GetTemplateChild("expressionContainer");
|
||||
if (uiElement != nullptr)
|
||||
{
|
||||
m_expressionContainer = safe_cast<ScrollViewer^>(uiElement);
|
||||
m_expressionContainer->ChangeView(m_expressionContainer->ExtentWidth - m_expressionContainer->ViewportWidth, nullptr, nullptr);
|
||||
m_containerViewChangedToken = m_expressionContainer->ViewChanged += ref new EventHandler<ScrollViewerViewChangedEventArgs ^>(this, &OverflowTextBlock::OnViewChanged);
|
||||
}
|
||||
|
||||
m_scrollLeft = safe_cast<Button^>(GetTemplateChild("scrollLeft"));
|
||||
m_scrollRight = safe_cast<Button^>(GetTemplateChild("scrollRight"));
|
||||
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::OnScrollClick);
|
||||
m_scrollRightClickEventToken = m_scrollRight->Click += ref new RoutedEventHandler(this, &OverflowTextBlock::OnScrollClick);
|
||||
uiElement = GetTemplateChild("scrollRight");
|
||||
if (uiElement != nullptr)
|
||||
{
|
||||
m_scrollRight = safe_cast<Button^>(GetTemplateChild("scrollRight"));
|
||||
m_scrollRightClickEventToken = m_scrollRight->Click += ref new RoutedEventHandler(this, &OverflowTextBlock::OnScrollClick);
|
||||
}
|
||||
|
||||
m_scrollingLeft = false;
|
||||
m_scrollingRight = false;
|
||||
|
||||
auto borderContainer = safe_cast<Border^>(GetTemplateChild("expressionborder"));
|
||||
m_pointerEnteredEventToken = borderContainer->PointerEntered += ref new PointerEventHandler(this, &OverflowTextBlock::OnPointerEntered);
|
||||
m_pointerExitedEventToken = borderContainer->PointerExited += ref new PointerEventHandler(this, &OverflowTextBlock::OnPointerExited);
|
||||
|
||||
m_listView = safe_cast<ListView^>(GetTemplateChild("TokenList"));
|
||||
uiElement = GetTemplateChild("TokenList");
|
||||
if (uiElement != nullptr)
|
||||
{
|
||||
m_itemsControl = safe_cast<ItemsControl^>(uiElement);
|
||||
}
|
||||
|
||||
UpdateAllState();
|
||||
}
|
||||
|
@ -60,18 +73,19 @@ AutomationPeer^ OverflowTextBlock::OnCreateAutomationPeer()
|
|||
|
||||
void OverflowTextBlock::OnTokensUpdatedPropertyChanged(bool /*oldValue*/, bool newValue)
|
||||
{
|
||||
if ((m_listView != nullptr) && (newValue))
|
||||
if (m_expressionContainer != nullptr && newValue)
|
||||
{
|
||||
unsigned int tokenCount = m_listView->Items->Size;
|
||||
if (tokenCount > 0)
|
||||
{
|
||||
m_listView->UpdateLayout();
|
||||
m_listView->ScrollIntoView(m_listView->Items->GetAt(tokenCount - 1));
|
||||
m_expressionContainer->ChangeView(m_expressionContainer->ExtentWidth - m_expressionContainer->ViewportWidth, nullptr, nullptr);
|
||||
}
|
||||
m_expressionContainer->UpdateLayout();
|
||||
m_expressionContainer->ChangeView(m_expressionContainer->ScrollableWidth, nullptr, nullptr, true);
|
||||
}
|
||||
AutomationProperties::SetAccessibilityView(this,
|
||||
m_listView != nullptr && m_listView->Items->Size > 0 ? AccessibilityView::Control : AccessibilityView::Raw);
|
||||
auto newIsAccessibilityViewControl = m_itemsControl != nullptr && m_itemsControl->Items->Size > 0;
|
||||
if (m_isAccessibilityViewControl != newIsAccessibilityViewControl)
|
||||
{
|
||||
m_isAccessibilityViewControl = newIsAccessibilityViewControl;
|
||||
AutomationProperties::SetAccessibilityView(this,
|
||||
newIsAccessibilityViewControl ? AccessibilityView::Control : AccessibilityView::Raw);
|
||||
}
|
||||
UpdateScrollButtons();
|
||||
}
|
||||
|
||||
void OverflowTextBlock::UpdateAllState()
|
||||
|
@ -93,7 +107,7 @@ void OverflowTextBlock::UpdateVisualState()
|
|||
|
||||
void OverflowTextBlock::ScrollLeft()
|
||||
{
|
||||
if (m_expressionContainer->HorizontalOffset > 0)
|
||||
if (m_expressionContainer != nullptr && m_expressionContainer->HorizontalOffset > 0)
|
||||
{
|
||||
m_scrollingLeft = true;
|
||||
double offset = m_expressionContainer->HorizontalOffset - (scrollRatio * m_expressionContainer->ViewportWidth);
|
||||
|
@ -105,7 +119,7 @@ void OverflowTextBlock::ScrollLeft()
|
|||
|
||||
void OverflowTextBlock::ScrollRight()
|
||||
{
|
||||
if (m_expressionContainer->HorizontalOffset < m_expressionContainer->ExtentWidth - m_expressionContainer->ViewportWidth)
|
||||
if (m_expressionContainer != nullptr && m_expressionContainer->HorizontalOffset < m_expressionContainer->ExtentWidth - m_expressionContainer->ViewportWidth)
|
||||
{
|
||||
m_scrollingRight = true;
|
||||
double offset = m_expressionContainer->HorizontalOffset + (scrollRatio * m_expressionContainer->ViewportWidth);
|
||||
|
@ -128,26 +142,15 @@ void OverflowTextBlock::OnScrollClick(_In_ Object^ sender, _In_ RoutedEventArgs^
|
|||
}
|
||||
}
|
||||
|
||||
void OverflowTextBlock::OnPointerEntered(_In_ Object^, _In_ PointerRoutedEventArgs^ e)
|
||||
{
|
||||
if (e->Pointer->PointerDeviceType == PointerDeviceType::Mouse)
|
||||
{
|
||||
UpdateScrollButtons();
|
||||
}
|
||||
}
|
||||
|
||||
void OverflowTextBlock::OnPointerExited(_In_ Object^, _In_ PointerRoutedEventArgs^ e)
|
||||
{
|
||||
if (e->Pointer->PointerDeviceType == PointerDeviceType::Mouse)
|
||||
{
|
||||
UpdateScrollButtons();
|
||||
}
|
||||
}
|
||||
|
||||
void OverflowTextBlock::UpdateScrollButtons()
|
||||
{
|
||||
if (m_itemsControl == nullptr || m_expressionContainer == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// When the width is smaller than the container, don't show any
|
||||
if (m_listView->ActualWidth <= m_expressionContainer->ActualWidth)
|
||||
if (m_itemsControl->ActualWidth <= m_expressionContainer->ActualWidth)
|
||||
{
|
||||
ShowHideScrollButtons(::Visibility::Collapsed, ::Visibility::Collapsed);
|
||||
}
|
||||
|
@ -163,7 +166,10 @@ void OverflowTextBlock::UpdateScrollButtons()
|
|||
if (m_scrollingLeft)
|
||||
{
|
||||
m_scrollingLeft = false;
|
||||
m_scrollRight->Focus(::FocusState::Programmatic);
|
||||
if (m_scrollRight != nullptr)
|
||||
{
|
||||
m_scrollRight->Focus(::FocusState::Programmatic);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // Width is larger than the container and right most part of the number is shown. Should be able to scroll left.
|
||||
|
@ -172,7 +178,10 @@ void OverflowTextBlock::UpdateScrollButtons()
|
|||
if (m_scrollingRight)
|
||||
{
|
||||
m_scrollingRight = false;
|
||||
m_scrollLeft->Focus(::FocusState::Programmatic);
|
||||
if (m_scrollLeft != nullptr)
|
||||
{
|
||||
m_scrollLeft->Focus(::FocusState::Programmatic);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -199,12 +208,13 @@ void OverflowTextBlock::UnregisterEventHandlers()
|
|||
m_scrollRight->Click -= m_scrollRightClickEventToken;
|
||||
}
|
||||
|
||||
auto borderContainer = safe_cast<Border^>(GetTemplateChild("expressionborder"));
|
||||
|
||||
// Adding an extra check, in case the returned template is null
|
||||
if (borderContainer != nullptr)
|
||||
if (m_expressionContainer != nullptr)
|
||||
{
|
||||
borderContainer->PointerEntered -= m_pointerEnteredEventToken;
|
||||
borderContainer->PointerExited -= m_pointerExitedEventToken;
|
||||
m_expressionContainer->ViewChanged -= m_containerViewChangedToken;
|
||||
}
|
||||
}
|
||||
|
||||
void OverflowTextBlock::OnViewChanged(_In_opt_ Object^ /*sender*/, _In_opt_ ScrollViewerViewChangedEventArgs^ /*args*/)
|
||||
{
|
||||
UpdateScrollButtons();
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ namespace CalculatorApp
|
|||
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 OnTokensUpdatedPropertyChanged(bool oldValue, bool newValue);
|
||||
void OnViewChanged(_In_opt_ Platform::Object ^sender, _In_opt_ Windows::UI::Xaml::Controls::ScrollViewerViewChangedEventArgs ^args);
|
||||
|
||||
void UpdateVisualState();
|
||||
void UpdateExpressionState();
|
||||
|
@ -44,15 +45,15 @@ namespace CalculatorApp
|
|||
double scrollRatio = 0.7;
|
||||
bool m_scrollingLeft;
|
||||
bool m_scrollingRight;
|
||||
Windows::UI::Xaml::Controls::ListView^ m_listView;
|
||||
bool m_isAccessibilityViewControl;
|
||||
Windows::UI::Xaml::Controls::ItemsControl^ m_itemsControl;
|
||||
Windows::UI::Xaml::Controls::ScrollViewer^ m_expressionContainer;
|
||||
Windows::UI::Xaml::Controls::Button^ m_scrollLeft;
|
||||
Windows::UI::Xaml::Controls::Button^ m_scrollRight;
|
||||
|
||||
Windows::Foundation::EventRegistrationToken m_scrollLeftClickEventToken;
|
||||
Windows::Foundation::EventRegistrationToken m_scrollRightClickEventToken;
|
||||
Windows::Foundation::EventRegistrationToken m_pointerEnteredEventToken;
|
||||
Windows::Foundation::EventRegistrationToken m_pointerExitedEventToken;
|
||||
Windows::Foundation::EventRegistrationToken m_containerViewChangedToken;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "pch.h"
|
||||
#include "ExpressionItemContainerStyle.h"
|
||||
#include "CalcViewModel/Common/DisplayExpressionToken.h"
|
||||
|
||||
using namespace CalculatorApp::Common;
|
||||
|
||||
namespace CalculatorApp
|
||||
{
|
||||
namespace Converters
|
||||
{
|
||||
Windows::UI::Xaml::Style^ ExpressionItemContainerStyle::SelectStyleCore(Platform::Object^ item, Windows::UI::Xaml::DependencyObject^ container)
|
||||
{
|
||||
DisplayExpressionToken^ token = dynamic_cast<DisplayExpressionToken^>(item);
|
||||
if (token != nullptr)
|
||||
{
|
||||
Common::TokenType type = token->Type;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case TokenType::Operator:
|
||||
if (token->IsTokenEditable)
|
||||
{
|
||||
return m_editableOperatorStyle;
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_nonEditableOperatorStyle;
|
||||
}
|
||||
case TokenType::Operand:
|
||||
return m_operandStyle;
|
||||
case TokenType::Separator:
|
||||
return m_separatorStyle;
|
||||
default:
|
||||
throw ref new Platform::Exception(E_FAIL, L"Invalid token type");
|
||||
}
|
||||
}
|
||||
|
||||
return m_separatorStyle;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace CalculatorApp
|
||||
{
|
||||
namespace Converters
|
||||
{
|
||||
[Windows::UI::Xaml::Data::Bindable]
|
||||
public ref class ExpressionItemContainerStyle sealed : public Windows::UI::Xaml::Controls::StyleSelector
|
||||
{
|
||||
public:
|
||||
virtual Windows::UI::Xaml::Style^ SelectStyleCore(Platform::Object^ item, Windows::UI::Xaml::DependencyObject^ container) override;
|
||||
|
||||
property Windows::UI::Xaml::Style^ EditableOperatorStyle
|
||||
{
|
||||
Windows::UI::Xaml::Style^ get()
|
||||
{
|
||||
return m_editableOperatorStyle;
|
||||
}
|
||||
void set(Windows::UI::Xaml::Style^ val)
|
||||
{
|
||||
m_editableOperatorStyle = val;
|
||||
}
|
||||
}
|
||||
|
||||
property Windows::UI::Xaml::Style^ OperandStyle
|
||||
{
|
||||
Windows::UI::Xaml::Style^ get()
|
||||
{
|
||||
return m_operandStyle;
|
||||
}
|
||||
void set(Windows::UI::Xaml::Style^ val)
|
||||
{
|
||||
m_operandStyle = val;
|
||||
}
|
||||
}
|
||||
|
||||
property Windows::UI::Xaml::Style^ SeparatorStyle
|
||||
{
|
||||
Windows::UI::Xaml::Style^ get()
|
||||
{
|
||||
return m_separatorStyle;
|
||||
}
|
||||
void set(Windows::UI::Xaml::Style^ val)
|
||||
{
|
||||
m_separatorStyle = val;
|
||||
}
|
||||
}
|
||||
|
||||
property Windows::UI::Xaml::Style^ NonEditableOperatorStyle
|
||||
{
|
||||
Windows::UI::Xaml::Style^ get()
|
||||
{
|
||||
return m_nonEditableOperatorStyle;
|
||||
}
|
||||
void set(Windows::UI::Xaml::Style^ val)
|
||||
{
|
||||
m_nonEditableOperatorStyle = val;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Windows::UI::Xaml::Style^ m_editableOperatorStyle;
|
||||
Windows::UI::Xaml::Style^ m_nonEditableOperatorStyle;
|
||||
Windows::UI::Xaml::Style^ m_operandStyle;
|
||||
Windows::UI::Xaml::Style^ m_separatorStyle;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -8,7 +8,6 @@
|
|||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:CalculatorApp"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:model="using:CalculatorApp.ViewModel"
|
||||
Loaded="OnLoaded"
|
||||
mc:Ignorable="d">
|
||||
|
||||
|
@ -19,20 +18,20 @@
|
|||
<TextBlock Margin="2,0,0,0"
|
||||
Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}"
|
||||
IsTextScaleFactorEnabled="False"
|
||||
Text="{Binding Token, Mode=OneWay}"/>
|
||||
Text="{x:Bind Token, Mode=OneWay}"/>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="Operator" x:DataType="common:DisplayExpressionToken">
|
||||
<TextBlock Margin="2,0,0,0"
|
||||
Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}"
|
||||
IsTextScaleFactorEnabled="False"
|
||||
Text="{Binding Token, Mode=OneWay}"/>
|
||||
Text="{x:Bind Token, Mode=OneWay}"/>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="Separator" x:DataType="common:DisplayExpressionToken">
|
||||
<TextBlock x:Name="MainText"
|
||||
IsTextScaleFactorEnabled="False"
|
||||
Text="{Binding Token, Mode=OneWay}"/>
|
||||
Text="{x:Bind Token, Mode=OneWay}"/>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- TextBox Styles -->
|
||||
|
@ -42,119 +41,59 @@
|
|||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="controls:OverflowTextBlock">
|
||||
<Border x:Name="expressionborder" Background="Transparent">
|
||||
<Grid x:Name="tokenContainer" Background="{TemplateBinding Background}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="12"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="12"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<ScrollViewer x:Name="expressionContainer"
|
||||
Grid.Column="1"
|
||||
Padding="0,0,0,0"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Style="{StaticResource ResultsScrollerSnapped}"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
LayoutUpdated="expressionContainer_LayoutUpdated">
|
||||
<ListView x:Name="TokenList"
|
||||
<Grid x:Name="tokenContainer" Background="{TemplateBinding Background}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="12"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="12"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<ScrollViewer x:Name="expressionContainer"
|
||||
Grid.Column="1"
|
||||
Padding="0,0,0,0"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Style="{StaticResource ResultsScrollerSnapped}"
|
||||
AutomationProperties.AccessibilityView="Raw">
|
||||
<ItemsControl x:Name="TokenList"
|
||||
Padding="0"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Right"
|
||||
VerticalContentAlignment="Stretch"
|
||||
IsTabStop="False"
|
||||
ItemContainerStyleSelector="{StaticResource ExpressionItemContainerStyle}"
|
||||
ItemTemplateSelector="{StaticResource ExpressionItemTemplateSelector}"
|
||||
ItemsSource="{Binding ExpressionTokens}"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
|
||||
ScrollViewer.HorizontalScrollMode="Enabled"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Disabled"
|
||||
ScrollViewer.VerticalScrollMode="Disabled"
|
||||
SelectionMode="None">
|
||||
<ListView.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel HorizontalAlignment="Right"
|
||||
VerticalAlignment="Stretch"
|
||||
Orientation="Horizontal"/>
|
||||
</ItemsPanelTemplate>
|
||||
</ListView.ItemsPanel>
|
||||
<ListView.ItemContainerTransitions>
|
||||
<TransitionCollection/>
|
||||
</ListView.ItemContainerTransitions>
|
||||
</ListView>
|
||||
</ScrollViewer>
|
||||
<Button x:Name="scrollLeft"
|
||||
x:Uid="scrollLeft"
|
||||
Grid.Column="0"
|
||||
Margin="-4,3,-4,0"
|
||||
Style="{StaticResource ScrollButtonStyle}">
|
||||
<FontIcon FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
||||
FontSize="12"
|
||||
Glyph=""/>
|
||||
</Button>
|
||||
<Button x:Name="scrollRight"
|
||||
x:Uid="scrollRight"
|
||||
Grid.Column="2"
|
||||
Margin="0,3,-9,0"
|
||||
Style="{StaticResource ScrollButtonStyle}">
|
||||
<FontIcon FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
||||
FontSize="12"
|
||||
Glyph=""/>
|
||||
</Button>
|
||||
</Grid>
|
||||
</Border>
|
||||
ItemsSource="{Binding ExpressionTokens}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<ItemsStackPanel HorizontalAlignment="Right"
|
||||
VerticalAlignment="Stretch"
|
||||
Orientation="Horizontal"/>
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
<Button x:Name="scrollLeft"
|
||||
x:Uid="scrollLeft"
|
||||
Grid.Column="0"
|
||||
Margin="-4,3,-4,0"
|
||||
Style="{StaticResource ScrollButtonStyle}">
|
||||
<FontIcon FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
||||
FontSize="12"
|
||||
Glyph=""/>
|
||||
</Button>
|
||||
<Button x:Name="scrollRight"
|
||||
x:Uid="scrollRight"
|
||||
Grid.Column="2"
|
||||
Margin="0,3,-9,0"
|
||||
Style="{StaticResource ScrollButtonStyle}">
|
||||
<FontIcon FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
||||
FontSize="12"
|
||||
Glyph=""/>
|
||||
</Button>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- ListViewItem Styles -->
|
||||
|
||||
<Style x:Key="ExpressionBaseContainerStyle" TargetType="ListViewItem">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="Margin" Value="0"/>
|
||||
<Setter Property="MinWidth" Value="0"/>
|
||||
<Setter Property="MinHeight" Value="0"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Center"/>
|
||||
<Setter Property="VerticalAlignment" Value="Stretch"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ListViewItem">
|
||||
<ListViewItemPresenter Padding="0"
|
||||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
ContentMargin="0"
|
||||
DisabledOpacity="{ThemeResource ListViewItemDisabledThemeOpacity}"
|
||||
DragOpacity="{ThemeResource ListViewItemDragThemeOpacity}"
|
||||
PointerOverBackground="{ThemeResource SystemControlHighlightListAccentLowBrush}"
|
||||
PointerOverBackgroundMargin="0"
|
||||
SelectedBackground="{ThemeResource SystemControlBackgroundAccentBrush}"
|
||||
SelectedBorderThickness="0"
|
||||
SelectedForeground="{ThemeResource SystemControlForegroundChromeWhiteBrush}"
|
||||
SelectedPointerOverBackground="{ThemeResource SystemControlHighlightListAccentLowBrush}"
|
||||
SelectedPointerOverBorderBrush="Transparent"
|
||||
SelectionCheckMarkVisualEnabled="False"/>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="NonEditableOperatorContainerStyle"
|
||||
BasedOn="{StaticResource ExpressionBaseContainerStyle}"
|
||||
TargetType="ListViewItem">
|
||||
<Setter Property="IsHitTestVisible" Value="False"/>
|
||||
<Setter Property="IsTabStop" Value="False"/>
|
||||
<Setter Property="MinWidth" Value="4"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="EditableOperatorContainerStyle"
|
||||
BasedOn="{StaticResource ExpressionBaseContainerStyle}"
|
||||
TargetType="ListViewItem">
|
||||
<Setter Property="IsHitTestVisible" Value="True"/>
|
||||
<Setter Property="MinWidth" Value="32"/>
|
||||
</Style>
|
||||
|
||||
<!-- Calculation Result Styles -->
|
||||
<Style x:Key="ResultsStyle"
|
||||
BasedOn="{StaticResource CalculationResultStyle}"
|
||||
|
@ -313,12 +252,6 @@
|
|||
OperatorTemplate="{StaticResource Operator}"
|
||||
SeparatorTemplate="{StaticResource Separator}"/>
|
||||
|
||||
<converters:ExpressionItemContainerStyle x:Key="ExpressionItemContainerStyle"
|
||||
EditableOperatorStyle="{StaticResource NonEditableOperatorContainerStyle}"
|
||||
NonEditableOperatorStyle="{StaticResource NonEditableOperatorContainerStyle}"
|
||||
OperandStyle="{StaticResource NonEditableOperatorContainerStyle}"
|
||||
SeparatorStyle="{StaticResource NonEditableOperatorContainerStyle}"/>
|
||||
|
||||
<!-- Miscellaneous Resources -->
|
||||
|
||||
<automation:NarratorNotifier x:Name="NarratorNotifier" Announcement="{x:Bind Model.Announcement, Mode=OneWay}"/>
|
||||
|
@ -528,7 +461,7 @@
|
|||
AutomationProperties.AutomationId="CalculatorExpression"
|
||||
AutomationProperties.Name="{x:Bind Model.CalculationExpressionAutomationName, Mode=OneWay}"
|
||||
IsTabStop="False"
|
||||
TokensUpdated="{Binding AreTokensUpdated, Mode=OneWay}"/>
|
||||
TokensUpdated="{x:Bind Model.AreTokensUpdated, Mode=OneWay}"/>
|
||||
|
||||
<!-- Programmer display panel controls -->
|
||||
<local:CalculatorProgrammerOperators x:Name="ProgrammerOperators"
|
||||
|
|
|
@ -659,11 +659,6 @@ void Calculator::OnHistoryFlyOutTapped(_In_ Object^ sender, _In_ TappedRoutedEve
|
|||
}
|
||||
}
|
||||
|
||||
void Calculator::expressionContainer_LayoutUpdated(_In_ Object^ sender, _In_ Object^ e)
|
||||
{
|
||||
expressionText->UpdateScrollButtons();
|
||||
}
|
||||
|
||||
bool Calculator::IsValidRegularExpression(std::wstring str)
|
||||
{
|
||||
bool result = false;
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
#include "Views/Calculator.g.h"
|
||||
#include "Converters/BooleanNegationConverter.h"
|
||||
#include "Converters/ExpressionItemContainerStyle.h"
|
||||
#include "Converters/ExpressionItemTemplateSelector.h"
|
||||
#include "Converters/VisibilityNegationConverter.h"
|
||||
#include "CalcViewModel/Common/Automation/NarratorNotifier.h"
|
||||
|
@ -130,7 +129,6 @@ namespace CalculatorApp
|
|||
void EnableMemoryControls(bool enable);
|
||||
void OnMemoryFlyOutTapped(_In_ Platform::Object^ sender, _In_ Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e);
|
||||
void OnHistoryFlyOutTapped(_In_ Platform::Object^ sender, _In_ Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e);
|
||||
void expressionContainer_LayoutUpdated(_In_ Platform::Object^ sender, _In_ Platform::Object^ e);
|
||||
bool IsValidRegularExpression(std::wstring str);
|
||||
void DockPanelTapped(_In_ Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e);
|
||||
void OnErrorLayoutCompleted(_In_ Platform::Object^ sender, _In_ Platform::Object^ e);
|
||||
|
|
Загрузка…
Ссылка в новой задаче