Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix regressions with NumberBox HeaderPresenter behavior #2148

Merged
merged 12 commits into from
Apr 28, 2020
10 changes: 9 additions & 1 deletion dev/Generated/NumberBox.properties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ void NumberBoxProperties::EnsureProperties()
winrt::name_of<winrt::NumberBox>(),
false /* isAttached */,
ValueHelper<winrt::DataTemplate>::BoxedDefaultValue(),
nullptr);
winrt::PropertyChangedCallback(&OnHeaderTemplatePropertyChanged));
}
if (!s_IsWrapEnabledProperty)
{
Expand Down Expand Up @@ -283,6 +283,14 @@ void NumberBoxProperties::OnHeaderPropertyChanged(
winrt::get_self<NumberBox>(owner)->OnHeaderPropertyChanged(args);
}

void NumberBoxProperties::OnHeaderTemplatePropertyChanged(
winrt::DependencyObject const& sender,
winrt::DependencyPropertyChangedEventArgs const& args)
{
auto owner = sender.as<winrt::NumberBox>();
winrt::get_self<NumberBox>(owner)->OnHeaderTemplatePropertyChanged(args);
}

void NumberBoxProperties::OnIsWrapEnabledPropertyChanged(
winrt::DependencyObject const& sender,
winrt::DependencyPropertyChangedEventArgs const& args)
Expand Down
4 changes: 4 additions & 0 deletions dev/Generated/NumberBox.properties.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ class NumberBoxProperties
winrt::DependencyObject const& sender,
winrt::DependencyPropertyChangedEventArgs const& args);

static void OnHeaderTemplatePropertyChanged(
winrt::DependencyObject const& sender,
winrt::DependencyPropertyChangedEventArgs const& args);

static void OnIsWrapEnabledPropertyChanged(
winrt::DependencyObject const& sender,
winrt::DependencyPropertyChangedEventArgs const& args);
Expand Down
31 changes: 25 additions & 6 deletions dev/NumberBox/InteractionTests/NumberBoxTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -315,15 +315,16 @@ public void ScrollTest()
Verify.AreEqual(0, numBox.Value);

FindTextBox(numBox).SetFocus();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Marcel, can you try adding a WaitForIdle here after setting focus ? From the test failure in downlevel, the verify with the value of 2 is failing with value of 0 which might be because the mouse wheel events are going before focus is set.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, merged with master and added a wait after setting focus.

Wait.ForIdle();

InputHelper.RotateWheel(numBox, 1);
InputHelper.RotateWheel(numBox, 1);
InputHelper.RotateWheel(FindTextBox(numBox), 1);
InputHelper.RotateWheel(FindTextBox(numBox), 1);
Wait.ForIdle();
Verify.AreEqual(2, numBox.Value);

InputHelper.RotateWheel(numBox, -1);
InputHelper.RotateWheel(numBox, -1);
InputHelper.RotateWheel(numBox, -1);
InputHelper.RotateWheel(FindTextBox(numBox), -1);
InputHelper.RotateWheel(FindTextBox(numBox), -1);
InputHelper.RotateWheel(FindTextBox(numBox), -1);
Wait.ForIdle();
Verify.AreEqual(-1, numBox.Value);

Expand Down Expand Up @@ -538,9 +539,15 @@ public void VerifyNumberBoxHeaderBehavior()
{
using (var setup = new TestSetupHelper("NumberBox Tests"))
{
var headerBeforeApplyTemplate = FindElement.ByName<TextBlock>("HeaderBeforeApplyTemplateTest");
Verify.IsNotNull(headerBeforeApplyTemplate);

var headerTemplateBeforeApplyTemplate = FindElement.ByName<TextBlock>("HeaderTemplateBeforeApplayTemplateTest");
Verify.IsNotNull(headerBeforeApplyTemplate);

var toggleHeaderButton = FindElement.ByName<Button>("ToggleHeaderValueButton");
var header = FindElement.ByName<TextBlock>("NumberBoxHeaderClippingDemoHeader");

Log.Comment("Check header is null");
Verify.IsNull(header);

Expand All @@ -559,6 +566,18 @@ public void VerifyNumberBoxHeaderBehavior()
Log.Comment("Check that header is null again");
header = FindElement.ByName<TextBlock>("NumberBoxHeaderClippingDemoHeader");
Verify.IsNull(header);


var toggleHeaderTemplateButton = FindElement.ByName<Button>("ToggleHeaderTemplateValueButton");
var headerTemplate = FindElement.ByName<TextBlock>("HeaderTemplateTestingBlock");

Verify.IsNull(headerTemplate);

toggleHeaderTemplateButton.Invoke();
Wait.ForIdle();

headerTemplate = FindElement.ByName<TextBlock>("HeaderTemplateTestingBlock");
Verify.IsNotNull(headerTemplate);
}
}

Expand Down
85 changes: 50 additions & 35 deletions dev/NumberBox/NumberBox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,7 @@ void NumberBox::OnApplyTemplate()
}
}

if (const auto headerPresenter = GetTemplateChildT<winrt::ContentPresenter>(c_numberBoxHeaderName, controlProtected))
{
// Set presenter to enable lightweight styling of the headers margin
m_headerPresenter.set(headerPresenter);
}
UpdateHeaderPresenterState();

m_textBox.set([this, controlProtected]() {
const auto textBox = GetTemplateChildT<winrt::TextBox>(c_numberBoxTextBoxName, controlProtected);
Expand Down Expand Up @@ -328,36 +324,12 @@ void NumberBox::UpdateValueToText()

void NumberBox::OnHeaderPropertyChanged(const winrt::DependencyPropertyChangedEventArgs& args)
{
// To enable lightweight styling, collapse header presenter if there is no header specified
if (const auto headerPresenter = m_headerPresenter.get())
{
if (const auto header = Header())
{
// Check if header is string or not
if (const auto headerAsString = Header().try_as<winrt::IReference<winrt::hstring>>())
{
if (headerAsString.Value().empty())
{
// String is the empty string, hide presenter
headerPresenter.Visibility(winrt::Visibility::Collapsed);
}
else
{
// String is not an empty string
headerPresenter.Visibility(winrt::Visibility::Visible);
}
}
else
{
// Header is not a string, so let's show header presenter
headerPresenter.Visibility(winrt::Visibility::Visible);
}
}
else
{
headerPresenter.Visibility(winrt::Visibility::Collapsed);
}
}
UpdateHeaderPresenterState();
}

void NumberBox::OnHeaderTemplatePropertyChanged(const winrt::DependencyPropertyChangedEventArgs& args)
{
UpdateHeaderPresenterState();
}

void NumberBox::OnValidationModePropertyChanged(const winrt::DependencyPropertyChangedEventArgs& args)
Expand Down Expand Up @@ -663,3 +635,46 @@ bool NumberBox::IsInBounds(double value)
return (value >= Minimum() && value <= Maximum());
}

void NumberBox::UpdateHeaderPresenterState()
{
bool shouldShowHeader = false;

// Load header presenter as late as possible

// To enable lightweight styling, collapse header presenter if there is no header specified
if (const auto header = Header())
{
// Check if header is string or not
if (const auto headerAsString = header.try_as<winrt::IReference<winrt::hstring>>())
{
if (!headerAsString.Value().empty())
{
// Header is not empty string
shouldShowHeader = true;
}
}
else
{
// Header is not a string, so let's show header presenter
shouldShowHeader = true;
}
}
if(const auto headerTemplate = HeaderTemplate())
{
shouldShowHeader = true;
}

if(shouldShowHeader && m_headerPresenter == nullptr)
{
if (const auto headerPresenter = GetTemplateChildT<winrt::ContentPresenter>(c_numberBoxHeaderName, (winrt::IControlProtected)*this))
{
// Set presenter to enable lightweight styling of the headers margin
m_headerPresenter.set(headerPresenter);
}
}

if (auto&& headerPresenter = m_headerPresenter.get())
{
headerPresenter.Visibility(shouldShowHeader ? winrt::Visibility::Visible : winrt::Visibility::Collapsed);
}
}
3 changes: 3 additions & 0 deletions dev/NumberBox/NumberBox.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class NumberBox :
void OnApplyTemplate();

void OnHeaderPropertyChanged(const winrt::DependencyPropertyChangedEventArgs& args);
void OnHeaderTemplatePropertyChanged(const winrt::DependencyPropertyChangedEventArgs& args);
void OnSpinButtonPlacementModePropertyChanged(const winrt::DependencyPropertyChangedEventArgs& args);
void OnTextPropertyChanged(const winrt::DependencyPropertyChangedEventArgs& args);

Expand Down Expand Up @@ -81,6 +82,8 @@ class NumberBox :
void UpdateSpinButtonEnabled();
void StepValue(double change);

void UpdateHeaderPresenterState();

bool IsInBounds(double value);

bool m_valueUpdating{ false };
Expand Down
1 change: 1 addition & 0 deletions dev/NumberBox/NumberBox.idl
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ unsealed runtimeclass NumberBox : Windows.UI.Xaml.Controls.Control

[MUX_PROPERTY_CHANGED_CALLBACK(TRUE)]
static Windows.UI.Xaml.DependencyProperty HeaderProperty{ get; };
[MUX_PROPERTY_CHANGED_CALLBACK(TRUE)]
static Windows.UI.Xaml.DependencyProperty HeaderTemplateProperty{ get; };
static Windows.UI.Xaml.DependencyProperty PlaceholderTextProperty{ get; };
static Windows.UI.Xaml.DependencyProperty SelectionFlyoutProperty{ get; };
Expand Down
20 changes: 18 additions & 2 deletions dev/NumberBox/TestUI/NumberBoxPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,19 +63,22 @@
<Button x:Name="SetTwoWayBoundValueNaNButton" AutomationProperties.Name="SetTwoWayBoundValueNaNButton" Content="Set two way bound value to NaN" Click="SetTwoWayBoundNaNButton_Click" Margin="0,4,0,0"/>

<Button x:Name="ToggleHeaderValueButton" AutomationProperties.Name="ToggleHeaderValueButton" Content="Toggle header for clipping issue" Click="ToggleHeaderValueButton_Click" Margin="0,4,0,0"/>

<Button x:Name="ToggleHeaderTemplateValueButton" AutomationProperties.Name="ToggleHeaderTemplateValueButton" Content="Toggle header template" Click="ToggleHeaderTemplateValueButton_Click" Margin="0,4,0,0"/>

</StackPanel>

<Grid Grid.Column="1">

<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"
Orientation="Horizontal" contract5Present:Spacing="4">
Orientation="Vertical" contract5Present:Spacing="4">
<!--Standard NumberBox test UI -->
<StackPanel>
<controls:NumberBox
MinWidth="150"
x:Name="TestNumberBox"
Header="TestNumberBox"
Description="Description text"
Header="TestNumberBox"
PlaceholderText="Text"
ValueChanged="NumberBoxValueChanged"
SmallChange="{x:Bind SmallChangeNumberBox.Value, Mode=OneWay}"
Expand Down Expand Up @@ -129,6 +132,19 @@
<StackPanel Orientation="Horizontal">
<TextBox MaxHeight="30" VerticalAlignment="Top"/>
<controls:NumberBox x:Name="HeaderTestingNumberBox" MaxHeight="32" VerticalAlignment="Top" PlaceholderText="I should not be clipped without header"/>
<controls:NumberBox x:Name="HeaderTestingNumberBoxTwo" MaxHeight="32" VerticalAlignment="Top">
<controls:NumberBox.HeaderTemplate>
<DataTemplate>
<TextBlock AutomationProperties.Name="HeaderTemplateBeforeApplayTemplateTest" Text="MyText"/>
</DataTemplate>
</controls:NumberBox.HeaderTemplate>
</controls:NumberBox>
<controls:NumberBox>
<controls:NumberBox.Header>
<TextBlock AutomationProperties.Name="HeaderBeforeApplyTemplateTest" Text="TestNumberBox"/>
</controls:NumberBox.Header>
</controls:NumberBox>
<controls:NumberBox x:Name="HeaderTemplateTestingNumberBox"/>
</StackPanel>
</StackPanel>
</Grid>
Expand Down
21 changes: 21 additions & 0 deletions dev/NumberBox/TestUI/NumberBoxPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Xml;
using Windows.Globalization.NumberFormatting;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Markup;

namespace MUXControlsTestApp
{
Expand Down Expand Up @@ -148,6 +151,24 @@ private void ToggleHeaderValueButton_Click(object sender, RoutedEventArgs e)
}
}

private void ToggleHeaderTemplateValueButton_Click(object sender, RoutedEventArgs e)
{
if (HeaderTemplateTestingNumberBox.HeaderTemplate is null)
{
string templateString =
@"<DataTemplate
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"">
<TextBlock AutomationProperties.Name=""HeaderTemplateTestingBlock"" Text=""Some text""/>
</DataTemplate>";
HeaderTemplateTestingNumberBox.HeaderTemplate = XamlReader.Load(templateString) as DataTemplate;
}
else
{
// Switching between normal header and empty string header
HeaderTemplateTestingNumberBox.HeaderTemplate = null;
}
}

private void TextPropertyChanged(DependencyObject o, DependencyProperty p)
{
TextTextBox.Text = TestNumberBox.Text;
Expand Down