Skip to content

Commit 85bfe0e

Browse files
committed
Merge branch 'main' into winui
# Conflicts: # CommunityToolkit.WinUI.UI.Behaviors/Viewport/ViewportBehavior.Properties.cs # UITests/UITests.App/UITests.App.csproj
2 parents 1a7fb53 + 44ad0cc commit 85bfe0e

File tree

13 files changed

+334
-86
lines changed

13 files changed

+334
-86
lines changed

CommunityToolkit.Diagnostics/Guard.String.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ public static void IsNullOrEmpty(string? text, string name)
3737
/// </summary>
3838
/// <param name="text">The input <see cref="string"/> instance to test.</param>
3939
/// <param name="name">The name of the input parameter being tested.</param>
40-
/// <exception cref="ArgumentException">Thrown if <paramref name="text"/> is <see langword="null"/> or empty.</exception>
40+
/// <exception cref="ArgumentNullException">Thrown if <paramref name="text"/> is <see langword="null"/>.</exception>
41+
/// <exception cref="ArgumentException">Thrown if <paramref name="text"/> is empty.</exception>
4142
[MethodImpl(MethodImplOptions.AggressiveInlining)]
4243
public static void IsNotNullOrEmpty([NotNull] string? text, string name)
4344
{
@@ -89,7 +90,8 @@ public static void IsNullOrWhitespace(string? text, string name)
8990
/// </summary>
9091
/// <param name="text">The input <see cref="string"/> instance to test.</param>
9192
/// <param name="name">The name of the input parameter being tested.</param>
92-
/// <exception cref="ArgumentException">Thrown if <paramref name="text"/> is <see langword="null"/> or whitespace.</exception>
93+
/// <exception cref="ArgumentNullException">Thrown if <paramref name="text"/> is <see langword="null"/>.</exception>
94+
/// <exception cref="ArgumentException">Thrown if <paramref name="text"/> is whitespace.</exception>
9395
[MethodImpl(MethodImplOptions.AggressiveInlining)]
9496
public static void IsNotNullOrWhiteSpace([NotNull] string? text, string name)
9597
{

CommunityToolkit.Diagnostics/Internals/Guard.String.ThrowHelper.cs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
using System;
66
using System.Diagnostics.CodeAnalysis;
7+
using System.Runtime.CompilerServices;
78

89
namespace CommunityToolkit.Diagnostics
910
{
@@ -27,12 +28,23 @@ public static void ThrowArgumentExceptionForIsNullOrEmpty(string? text, string n
2728
}
2829

2930
/// <summary>
30-
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsNotNullOrEmpty"/> fails.
31+
/// Throws an <see cref="ArgumentNullException"/> or <see cref="ArgumentException"/> when <see cref="Guard.IsNotNullOrEmpty"/> fails.
3132
/// </summary>
3233
[DoesNotReturn]
3334
public static void ThrowArgumentExceptionForIsNotNullOrEmpty(string? text, string name)
3435
{
35-
throw new ArgumentException($"Parameter {AssertString(name)} (string) must not be null or empty, was {(text is null ? "null" : "empty")}", name);
36+
[MethodImpl(MethodImplOptions.NoInlining)]
37+
static Exception GetException(string? text, string name)
38+
{
39+
if (text is null)
40+
{
41+
return new ArgumentNullException(name, $"Parameter {AssertString(name)} (string) must not be null or empty, was null");
42+
}
43+
44+
return new ArgumentException($"Parameter {AssertString(name)} (string) must not be null or empty, was empty", name);
45+
}
46+
47+
throw GetException(text, name);
3648
}
3749

3850
/// <summary>
@@ -50,7 +62,18 @@ public static void ThrowArgumentExceptionForIsNullOrWhiteSpace(string? text, str
5062
[DoesNotReturn]
5163
public static void ThrowArgumentExceptionForIsNotNullOrWhiteSpace(string? text, string name)
5264
{
53-
throw new ArgumentException($"Parameter {AssertString(name)} (string) must not be null or whitespace, was {(text is null ? "null" : "whitespace")}", name);
65+
[MethodImpl(MethodImplOptions.NoInlining)]
66+
static Exception GetException(string? text, string name)
67+
{
68+
if (text is null)
69+
{
70+
return new ArgumentNullException(name, $"Parameter {AssertString(name)} (string) must not be null or whitespace, was null");
71+
}
72+
73+
return new ArgumentException($"Parameter {AssertString(name)} (string) must not be null or whitespace, was whitespace", name);
74+
}
75+
76+
throw GetException(text, name);
5477
}
5578

5679
/// <summary>

CommunityToolkit.WinUI.SampleApp/SamplePages/ViewportBehavior/ViewportBehaviorXaml.bind

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
Height="200"
1515
Background="Gray">
1616
<interactivity:Interaction.Behaviors>
17-
<behaviors:ViewportBehavior x:Name="ViewportBehavior" />
17+
<behaviors:ViewportBehavior x:Name="ViewportBehavior" IsAlwaysOn="True" />
1818
</interactivity:Interaction.Behaviors>
1919
<Image x:Name="EffectElement"
2020
Width="100"

CommunityToolkit.WinUI.SampleApp/SamplePages/XamlOnlyPage.xaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
<ui:SurfaceDialOptions />
4545
</ui:TextBoxExtensions.SurfaceDialOptions>
4646
</TextBox>
47+
<TextBlock x:Key="OnDeviceExtension" Text="{ui:OnDevice Desktop=Desktop, Xbox=Xbox, Default=Default}" />
4748
<controls:SwitchPresenter x:Key="SwitchPresenterControl">
4849
<controls:CaseCollection>
4950
<controls:Case IsDefault="True" />
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using Microsoft.UI.Xaml;
7+
using Microsoft.Xaml.Interactivity;
8+
9+
namespace CommunityToolkit.WinUI.UI.Behaviors
10+
{
11+
/// <summary>
12+
/// A class for listening to an element enter or exit the ScrollViewer viewport
13+
/// </summary>
14+
public partial class ViewportBehavior
15+
{
16+
/// <summary>
17+
/// The IsFullyInViewport value of the associated element
18+
/// </summary>
19+
public static readonly DependencyProperty IsFullyInViewportProperty =
20+
DependencyProperty.Register(nameof(IsFullyInViewport), typeof(bool), typeof(ViewportBehavior), new PropertyMetadata(default(bool), OnIsFullyInViewportChanged));
21+
22+
/// <summary>
23+
/// The IsInViewport value of the associated element
24+
/// </summary>
25+
public static readonly DependencyProperty IsInViewportProperty =
26+
DependencyProperty.Register(nameof(IsInViewport), typeof(bool), typeof(ViewportBehavior), new PropertyMetadata(default(bool), OnIsInViewportChanged));
27+
28+
/// <summary>
29+
/// The IsAlwaysOn value of the associated element
30+
/// </summary>
31+
public static readonly DependencyProperty IsAlwaysOnProperty =
32+
DependencyProperty.Register(nameof(IsAlwaysOn), typeof(bool), typeof(ViewportBehavior), new PropertyMetadata(default(bool)));
33+
34+
/// <summary>
35+
/// Gets or sets a value indicating whether this behavior will remain attached after the associated element enters the viewport. When false, the behavior will remove itself after entering.
36+
/// </summary>
37+
public bool IsAlwaysOn
38+
{
39+
get { return (bool)GetValue(IsAlwaysOnProperty); }
40+
set { SetValue(IsAlwaysOnProperty, value); }
41+
}
42+
43+
/// <summary>
44+
/// Gets a value indicating whether associated element is fully in the ScrollViewer viewport
45+
/// </summary>
46+
public bool IsFullyInViewport
47+
{
48+
get { return (bool)GetValue(IsFullyInViewportProperty); }
49+
private set { SetValue(IsFullyInViewportProperty, value); }
50+
}
51+
52+
/// <summary>
53+
/// Gets a value indicating whether associated element is in the ScrollViewer viewport
54+
/// </summary>
55+
public bool IsInViewport
56+
{
57+
get { return (bool)GetValue(IsInViewportProperty); }
58+
private set { SetValue(IsInViewportProperty, value); }
59+
}
60+
61+
/// <summary>
62+
/// Event tracking when the object is fully within the viewport or not
63+
/// </summary>
64+
/// <param name="d">DependencyObject</param>
65+
/// <param name="e">EventArgs</param>
66+
private static void OnIsFullyInViewportChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
67+
{
68+
var obj = (ViewportBehavior)d;
69+
var value = (bool)e.NewValue;
70+
71+
if (value)
72+
{
73+
obj.EnteredViewport?.Invoke(obj.AssociatedObject, EventArgs.Empty);
74+
75+
if (!obj.IsAlwaysOn)
76+
{
77+
Interaction.GetBehaviors(obj.AssociatedObject).Remove(obj);
78+
}
79+
}
80+
else
81+
{
82+
obj.ExitingViewport?.Invoke(obj.AssociatedObject, EventArgs.Empty);
83+
}
84+
}
85+
86+
/// <summary>
87+
/// Event tracking the state of the object as it moves into and out of the viewport
88+
/// </summary>
89+
/// <param name="d">DependencyObject</param>
90+
/// <param name="e">EventArgs</param>
91+
private static void OnIsInViewportChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
92+
{
93+
var obj = (ViewportBehavior)d;
94+
var value = (bool)e.NewValue;
95+
96+
if (value)
97+
{
98+
obj.EnteringViewport?.Invoke(obj.AssociatedObject, EventArgs.Empty);
99+
}
100+
else
101+
{
102+
obj.ExitedViewport?.Invoke(obj.AssociatedObject, EventArgs.Empty);
103+
}
104+
}
105+
}
106+
}

CommunityToolkit.WinUI.UI.Behaviors/Viewport/ViewportBehavior.cs

Lines changed: 2 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -12,33 +12,15 @@
1212
namespace CommunityToolkit.WinUI.UI.Behaviors
1313
{
1414
/// <summary>
15-
/// A class for listening element enter or exit the ScrollViewer viewport
15+
/// A class for listening to an element enter or exit the ScrollViewer viewport
1616
/// </summary>
17-
public class ViewportBehavior : BehaviorBase<FrameworkElement>
17+
public partial class ViewportBehavior : BehaviorBase<FrameworkElement>
1818
{
1919
/// <summary>
2020
/// The ScrollViewer hosting this element.
2121
/// </summary>
2222
private ScrollViewer _hostScrollViewer;
2323

24-
/// <summary>
25-
/// The IsFullyInViewport value of the associated element
26-
/// </summary>
27-
public static readonly DependencyProperty IsFullyInViewportProperty =
28-
DependencyProperty.Register(nameof(IsFullyInViewport), typeof(bool), typeof(ViewportBehavior), new PropertyMetadata(default(bool), OnIsFullyInViewportChanged));
29-
30-
/// <summary>
31-
/// The IsInViewport value of the associated element
32-
/// </summary>
33-
public static readonly DependencyProperty IsInViewportProperty =
34-
DependencyProperty.Register(nameof(IsInViewport), typeof(bool), typeof(ViewportBehavior), new PropertyMetadata(default(bool), OnIsInViewportChanged));
35-
36-
/// <summary>
37-
/// The IsAlwaysOn value of the associated element
38-
/// </summary>
39-
public static readonly DependencyProperty IsAlwaysOnProperty =
40-
DependencyProperty.Register(nameof(IsAlwaysOn), typeof(bool), typeof(ViewportBehavior), new PropertyMetadata(default(bool)));
41-
4224
/// <summary>
4325
/// Associated element fully enter the ScrollViewer viewport event
4426
/// </summary>
@@ -59,33 +41,6 @@ public class ViewportBehavior : BehaviorBase<FrameworkElement>
5941
/// </summary>
6042
public event EventHandler ExitingViewport;
6143

62-
/// <summary>
63-
/// Gets or sets a value indicating whether this behavior will remain attached after the associated element enters the viewport. When false, the behavior will remove itself after entering.
64-
/// </summary>
65-
public bool IsAlwaysOn
66-
{
67-
get { return (bool)GetValue(IsAlwaysOnProperty); }
68-
set { SetValue(IsAlwaysOnProperty, value); }
69-
}
70-
71-
/// <summary>
72-
/// Gets a value indicating whether associated element is fully in the ScrollViewer viewport
73-
/// </summary>
74-
public bool IsFullyInViewport
75-
{
76-
get { return (bool)GetValue(IsFullyInViewportProperty); }
77-
private set { SetValue(IsFullyInViewportProperty, value); }
78-
}
79-
80-
/// <summary>
81-
/// Gets a value indicating whether associated element is in the ScrollViewer viewport
82-
/// </summary>
83-
public bool IsInViewport
84-
{
85-
get { return (bool)GetValue(IsInViewportProperty); }
86-
private set { SetValue(IsInViewportProperty, value); }
87-
}
88-
8944
/// <summary>
9045
/// Called after the behavior is attached to the <see cref="P:Microsoft.Xaml.Interactivity.Behavior.AssociatedObject" />.
9146
/// </summary>
@@ -120,39 +75,6 @@ protected override void OnDetaching()
12075
_hostScrollViewer = null;
12176
}
12277

123-
private static void OnIsFullyInViewportChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
124-
{
125-
var obj = (ViewportBehavior)d;
126-
var value = (bool)e.NewValue;
127-
if (value)
128-
{
129-
obj.EnteredViewport?.Invoke(obj.AssociatedObject, EventArgs.Empty);
130-
131-
if (!obj.IsAlwaysOn)
132-
{
133-
Interaction.GetBehaviors(obj.AssociatedObject).Remove(obj);
134-
}
135-
}
136-
else
137-
{
138-
obj.ExitingViewport?.Invoke(obj.AssociatedObject, EventArgs.Empty);
139-
}
140-
}
141-
142-
private static void OnIsInViewportChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
143-
{
144-
var obj = (ViewportBehavior)d;
145-
var value = (bool)e.NewValue;
146-
if (value)
147-
{
148-
obj.EnteringViewport?.Invoke(obj.AssociatedObject, EventArgs.Empty);
149-
}
150-
else
151-
{
152-
obj.ExitedViewport?.Invoke(obj.AssociatedObject, EventArgs.Empty);
153-
}
154-
}
155-
15678
private void ParentScrollViewer_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
15779
{
15880
var associatedElementRect = AssociatedObject.TransformToVisual(_hostScrollViewer)

CommunityToolkit.WinUI.UI.Controls.Primitives/ConstrainedBox/AspectRatio.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
using System;
56
using System.Globalization;
67

78
namespace CommunityToolkit.WinUI.UI.Controls
@@ -63,6 +64,13 @@ public AspectRatio(double ratio)
6364
/// <param name="ratio"><see cref="double"/> value representing the <see cref="AspectRatio"/>.</param>
6465
public static implicit operator AspectRatio(double ratio) => new AspectRatio(ratio);
6566

67+
/// <summary>
68+
/// Implicit conversion operator to convert a <see cref="int"/> to an <see cref="AspectRatio"/> value.
69+
/// Creates a simple aspect ratio of N:1, where N is int
70+
/// </summary>
71+
/// <param name="width"><see cref="int"/> value representing the <see cref="AspectRatio"/>.</param>
72+
public static implicit operator AspectRatio(int width) => new AspectRatio(width, 1.0);
73+
6674
/// <summary>
6775
/// Converter to take a string aspect ration like "16:9" and convert it to an <see cref="AspectRatio"/> struct.
6876
/// Used automatically by XAML.

UITests/UITests.App/UITests.App.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@
102102
<Project>{e9faabfb-d726-42c1-83c1-cb46a29fea81}</Project>
103103
<Name>CommunityToolkit.WinUI.UI.Controls.Core</Name>
104104
</ProjectReference>
105+
<ProjectReference Include="..\..\CommunityToolkit.WinUI.UI.Controls.Primitives\CommunityToolkit.WinUI.UI.Controls.Primitives.csproj">
106+
<Project>{84ab7dc5-95c9-4cf8-a370-d077e9e9ef1a}</Project>
107+
<Name>CommunityToolkit.WinUI.UI.Controls.Primitives</Name>
108+
</ProjectReference>
105109
<ProjectReference Include="..\..\CommunityToolkit.WinUI.UI.Media\CommunityToolkit.WinUI.UI.Media.csproj">
106110
<Project>{75f9ee44-3efa-47bc-aedd-351b9834a0af}</Project>
107111
<Name>CommunityToolkit.WinUI.UI.Media</Name>
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using Microsoft.UI.Xaml.Tests.MUXControls.InteractionTests.Common;
6+
using Microsoft.UI.Xaml.Tests.MUXControls.InteractionTests.Infra;
7+
using Microsoft.Windows.Apps.Test.Automation;
8+
using Microsoft.Windows.Apps.Test.Foundation;
9+
using Microsoft.Windows.Apps.Test.Foundation.Controls;
10+
11+
#if USING_TAEF
12+
using WEX.Logging.Interop;
13+
using WEX.TestExecution;
14+
using WEX.TestExecution.Markup;
15+
#else
16+
using Microsoft.VisualStudio.TestTools.UnitTesting;
17+
#endif
18+
19+
namespace UITests.Tests
20+
{
21+
[TestClass]
22+
public class ConstrainedBoxTest : UITestBase
23+
{
24+
[ClassInitialize]
25+
[TestProperty("RunAs", "User")]
26+
[TestProperty("Classification", "ScenarioTestSuite")]
27+
[TestProperty("Platform", "Any")]
28+
public static void ClassInitialize(TestContext testContext)
29+
{
30+
TestEnvironment.Initialize(testContext, UITestsAppSampleApp);
31+
}
32+
33+
[TestMethod]
34+
[TestPage("ConstrainedBoxTestPage")]
35+
public void Test_AspectRatioBoundToInteger_Placeholder()
36+
{
37+
// The test is if the AspectRatio can be bound to integer
38+
// This test method acts as a placeholder, to spawn the XAML test page
39+
// and test the binding to an integer
40+
}
41+
}
42+
}

0 commit comments

Comments
 (0)