Skip to content

Commit 2745962

Browse files
Merge branch 'master' into feature/array3d-apis
2 parents bc6f70b + 06eed0d commit 2745962

File tree

19 files changed

+618
-455
lines changed

19 files changed

+618
-455
lines changed

Microsoft.Toolkit.HighPerformance/Streams/MemoryStream.Validate.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ namespace Microsoft.Toolkit.HighPerformance.Streams
1313
internal static partial class MemoryStream
1414
{
1515
/// <summary>
16-
/// Validates the <see cref="Stream.Position"/> argument.
16+
/// Validates the <see cref="Stream.Position"/> argument (it needs to be in the [0, length]) range.
1717
/// </summary>
1818
/// <param name="position">The new <see cref="Stream.Position"/> value being set.</param>
1919
/// <param name="length">The maximum length of the target <see cref="Stream"/>.</param>
2020
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2121
public static void ValidatePosition(long position, int length)
2222
{
23-
if ((ulong)position >= (ulong)length)
23+
if ((ulong)position > (ulong)length)
2424
{
2525
ThrowArgumentOutOfRangeExceptionForPosition();
2626
}

Microsoft.Toolkit.Uwp.SampleApp/SamplePages/WrapPanel/WrapPanel.bind

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,16 @@
4949
HorizontalSpacing="@[HorizontalSpacing:Slider:5:0-200]@" />
5050
</ItemsPanelTemplate>
5151
</ItemsControl.ItemsPanel>
52+
<ListView.ItemContainerStyle>
53+
<Style TargetType="ListViewItem">
54+
<!-- Change those values to change the WrapPanel's children alignment -->
55+
<Setter Property="VerticalContentAlignment" Value="Center" />
56+
<Setter Property="HorizontalContentAlignment" Value="Center" />
57+
<Setter Property="Padding" Value="0" />
58+
<Setter Property="MinWidth" Value="0" />
59+
<Setter Property="MinHeight" Value="0" />
60+
</Style>
61+
</ListView.ItemContainerStyle>
5262
</ListView>
5363
</Grid>
5464
</Page>

Microsoft.Toolkit.Uwp.SampleApp/SamplePages/WrapPanel/WrapPanelPage.xaml.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ private void AddButton_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
6464
{
6565
Category = "Remove",
6666
Thumbnail = "ms-appx:///Assets/Photos/BigFourSummerHeat.jpg",
67-
Width = Rand.Next(120, 180),
68-
Height = Rand.Next(80, 130)
67+
Width = Rand.Next(60, 180),
68+
Height = Rand.Next(40, 140)
6969
});
7070
}
7171

Microsoft.Toolkit.Uwp.SampleApp/readme.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
# How to add new samples
1+
For the latest info, [visit the wiki article here](https://github.com/windows-toolkit/WindowsCommunityToolkit/wiki/Sample-Development).
2+
3+
# How to add new samples
24

35
This document describes how to add a new sample page for a new control you want to add to the toolkit.
46

Microsoft.Toolkit.Uwp.UI.Controls/Expander/Expander.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System;
6+
using Microsoft.Toolkit.Uwp.UI.Automation.Peers;
67
using Windows.System;
78
using Windows.UI.Xaml;
9+
using Windows.UI.Xaml.Automation.Peers;
810
using Windows.UI.Xaml.Controls;
911
using Windows.UI.Xaml.Controls.Primitives;
1012
using Windows.UI.Xaml.Input;
@@ -76,6 +78,15 @@ protected virtual void OnCollapsed(EventArgs args)
7678
Collapsed?.Invoke(this, args);
7779
}
7880

81+
/// <summary>
82+
/// Creates AutomationPeer (<see cref="UIElement.OnCreateAutomationPeer"/>)
83+
/// </summary>
84+
/// <returns>An automation peer for this <see cref="Expander"/>.</returns>
85+
protected override AutomationPeer OnCreateAutomationPeer()
86+
{
87+
return new ExpanderAutomationPeer(this);
88+
}
89+
7990
private void ExpanderToggleButtonPart_KeyDown(object sender, KeyRoutedEventArgs e)
8091
{
8192
if (e.Key != VirtualKey.Enter)
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
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.Toolkit.Uwp.UI.Controls;
6+
using Windows.UI.Xaml.Automation;
7+
using Windows.UI.Xaml.Automation.Peers;
8+
using Windows.UI.Xaml.Automation.Provider;
9+
10+
namespace Microsoft.Toolkit.Uwp.UI.Automation.Peers
11+
{
12+
/// <summary>
13+
/// Defines a framework element automation peer for the <see cref="Expander"/> control.
14+
/// </summary>
15+
public class ExpanderAutomationPeer : FrameworkElementAutomationPeer, IToggleProvider
16+
{
17+
/// <summary>
18+
/// Initializes a new instance of the <see cref="ExpanderAutomationPeer"/> class.
19+
/// </summary>
20+
/// <param name="owner">
21+
/// The <see cref="Expander" /> that is associated with this <see cref="T:Windows.UI.Xaml.Automation.Peers.ExpanderAutomationPeer" />.
22+
/// </param>
23+
public ExpanderAutomationPeer(Expander owner)
24+
: base(owner)
25+
{
26+
}
27+
28+
/// <summary>Gets the toggle state of the control.</summary>
29+
/// <returns>The toggle state of the control, as a value of the enumeration.</returns>
30+
public ToggleState ToggleState => OwningExpander.IsExpanded ? ToggleState.On : ToggleState.Off;
31+
32+
private Expander OwningExpander
33+
{
34+
get
35+
{
36+
return Owner as Expander;
37+
}
38+
}
39+
40+
/// <summary>Cycles through the toggle states of a control.</summary>
41+
public void Toggle()
42+
{
43+
if (!IsEnabled())
44+
{
45+
throw new ElementNotEnabledException();
46+
}
47+
48+
OwningExpander.IsExpanded = !OwningExpander.IsExpanded;
49+
}
50+
51+
/// <summary>
52+
/// Gets the control type for the element that is associated with the UI Automation peer.
53+
/// </summary>
54+
/// <returns>The control type.</returns>
55+
protected override AutomationControlType GetAutomationControlTypeCore()
56+
{
57+
return AutomationControlType.Custom;
58+
}
59+
60+
/// <summary>
61+
/// Called by GetClassName that gets a human readable name that, in addition to AutomationControlType,
62+
/// differentiates the control represented by this AutomationPeer.
63+
/// </summary>
64+
/// <returns>The string that contains the name.</returns>
65+
protected override string GetClassNameCore()
66+
{
67+
return Owner.GetType().Name;
68+
}
69+
70+
/// <summary>
71+
/// Called by GetName.
72+
/// </summary>
73+
/// <returns>
74+
/// Returns the first of these that is not null or empty:
75+
/// - Value returned by the base implementation
76+
/// - Name of the owning Expander
77+
/// - Expander class name
78+
/// </returns>
79+
protected override string GetNameCore()
80+
{
81+
string name = base.GetNameCore();
82+
if (!string.IsNullOrEmpty(name))
83+
{
84+
return name;
85+
}
86+
87+
if (this.OwningExpander != null)
88+
{
89+
name = this.OwningExpander.Name;
90+
}
91+
92+
if (string.IsNullOrEmpty(name))
93+
{
94+
name = this.GetClassName();
95+
}
96+
97+
return name;
98+
}
99+
100+
/// <summary>
101+
/// Gets the control pattern that is associated with the specified Windows.UI.Xaml.Automation.Peers.PatternInterface.
102+
/// </summary>
103+
/// <param name="patternInterface">A value from the Windows.UI.Xaml.Automation.Peers.PatternInterface enumeration.</param>
104+
/// <returns>The object that supports the specified pattern, or null if unsupported.</returns>
105+
protected override object GetPatternCore(PatternInterface patternInterface)
106+
{
107+
switch (patternInterface)
108+
{
109+
case PatternInterface.Toggle:
110+
return this;
111+
}
112+
113+
return base.GetPatternCore(patternInterface);
114+
}
115+
}
116+
}

Microsoft.Toolkit.Uwp.UI.Controls/RadialGauge/RadialGauge.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,11 @@ protected override void OnValueChanged(double oldValue, double newValue)
469469
{
470470
OnValueChanged(this);
471471
base.OnValueChanged(oldValue, newValue);
472+
if (AutomationPeer.ListenerExists(AutomationEvents.LiveRegionChanged))
473+
{
474+
var peer = FrameworkElementAutomationPeer.FromElement(this) as RadialGaugeAutomationPeer;
475+
peer?.RaiseValueChangedEvent(oldValue, newValue);
476+
}
472477
}
473478

474479
private static void OnValueChanged(DependencyObject d)

Microsoft.Toolkit.Uwp.UI.Controls/RadialGauge/RadialGaugeAutomationPeer.cs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System.Collections.Generic;
6+
using Windows.Foundation;
7+
using Windows.UI.Xaml.Automation;
68
using Windows.UI.Xaml.Automation.Peers;
79
using Windows.UI.Xaml.Automation.Provider;
810

@@ -12,7 +14,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
1214
/// Exposes <see cref="RadialGauge"/> to Microsoft UI Automation.
1315
/// </summary>
1416
public class RadialGaugeAutomationPeer :
15-
FrameworkElementAutomationPeer,
17+
RangeBaseAutomationPeer,
1618
IRangeValueProvider
1719
{
1820
/// <summary>
@@ -25,25 +27,25 @@ public RadialGaugeAutomationPeer(RadialGauge owner)
2527
}
2628

2729
/// <inheritdoc/>
28-
public bool IsReadOnly => !((RadialGauge)Owner).IsInteractive;
30+
public new bool IsReadOnly => !((RadialGauge)Owner).IsInteractive;
2931

3032
/// <inheritdoc/>
31-
public double LargeChange => ((RadialGauge)Owner).StepSize;
33+
public new double LargeChange => ((RadialGauge)Owner).StepSize;
3234

3335
/// <inheritdoc/>
34-
public double Maximum => ((RadialGauge)Owner).Maximum;
36+
public new double Maximum => ((RadialGauge)Owner).Maximum;
3537

3638
/// <inheritdoc/>
37-
public double Minimum => ((RadialGauge)Owner).Minimum;
39+
public new double Minimum => ((RadialGauge)Owner).Minimum;
3840

3941
/// <inheritdoc/>
40-
public double SmallChange => ((RadialGauge)Owner).StepSize;
42+
public new double SmallChange => ((RadialGauge)Owner).StepSize;
4143

4244
/// <inheritdoc/>
43-
public double Value => ((RadialGauge)Owner).Value;
45+
public new double Value => ((RadialGauge)Owner).Value;
4446

4547
/// <inheritdoc/>
46-
public void SetValue(double value)
48+
public new void SetValue(double value)
4749
{
4850
((RadialGauge)Owner).Value = value;
4951
}
@@ -58,7 +60,7 @@ protected override IList<AutomationPeer> GetChildrenCore()
5860
protected override string GetNameCore()
5961
{
6062
var gauge = (RadialGauge)Owner;
61-
return "radial gauge. " + (string.IsNullOrWhiteSpace(gauge.Unit) ? "no unit specified. " : "unit " + gauge.Unit + ". ");
63+
return "radial gauge. " + (string.IsNullOrWhiteSpace(gauge.Unit) ? "no unit specified, " : "unit " + gauge.Unit + ", ") + Value;
6264
}
6365

6466
/// <inheritdoc/>
@@ -78,5 +80,15 @@ protected override AutomationControlType GetAutomationControlTypeCore()
7880
{
7981
return AutomationControlType.Custom;
8082
}
83+
84+
/// <summary>
85+
/// Raises the property changed event for this AutomationPeer for the provided identifier.
86+
/// </summary>
87+
/// <param name="oldValue">Old value</param>
88+
/// <param name="newValue">New value</param>
89+
public void RaiseValueChangedEvent(double oldValue, double newValue)
90+
{
91+
RaisePropertyChangedEvent(RangeValuePatternIdentifiers.ValueProperty, PropertyValue.CreateDouble(oldValue), PropertyValue.CreateDouble(newValue));
92+
}
8193
}
8294
}

Microsoft.Toolkit.Uwp.UI.Controls/UniformGrid/TakenSpotsReferenceHolder.cs

Lines changed: 69 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@
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;
6-
using System.Collections.Generic;
7-
using System.Linq;
8-
using System.Text;
9-
using System.Threading.Tasks;
5+
using System.Collections;
6+
using System.Drawing;
7+
using Microsoft.Toolkit.Diagnostics;
108

119
namespace Microsoft.Toolkit.Uwp.UI.Controls
1210
{
@@ -16,23 +14,81 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
1614
/// <see cref="UniformGrid.GetFreeSpot"/> iterator.
1715
/// This is used so we can better isolate our logic and make it easier to test.
1816
/// </summary>
19-
internal class TakenSpotsReferenceHolder
17+
internal sealed class TakenSpotsReferenceHolder
2018
{
2119
/// <summary>
22-
/// Gets or sets the array to hold taken spots.
23-
/// True value indicates an item in the layout is fixed to that position.
24-
/// False values indicate free openings where an item can be placed.
20+
/// The <see cref="BitArray"/> instance used to efficiently track empty spots.
2521
/// </summary>
26-
public bool[,] SpotsTaken { get; set; }
22+
private readonly BitArray spotsTaken;
2723

24+
/// <summary>
25+
/// Initializes a new instance of the <see cref="TakenSpotsReferenceHolder"/> class.
26+
/// </summary>
27+
/// <param name="rows">The number of rows to track.</param>
28+
/// <param name="columns">The number of columns to track.</param>
2829
public TakenSpotsReferenceHolder(int rows, int columns)
2930
{
30-
SpotsTaken = new bool[rows, columns];
31+
Guard.IsGreaterThanOrEqualTo(rows, 0, nameof(rows));
32+
Guard.IsGreaterThanOrEqualTo(columns, 0, nameof(columns));
33+
34+
Height = rows;
35+
Width = columns;
36+
37+
this.spotsTaken = new BitArray(rows * columns);
38+
}
39+
40+
/// <summary>
41+
/// Gets the height of the grid to monitor.
42+
/// </summary>
43+
public int Height { get; }
44+
45+
/// <summary>
46+
/// Gets the width of the grid to monitor.
47+
/// </summary>
48+
public int Width { get; }
49+
50+
/// <summary>
51+
/// Gets or sets the value of a specified grid cell.
52+
/// </summary>
53+
/// <param name="i">The vertical offset.</param>
54+
/// <param name="j">The horizontal offset.</param>
55+
public bool this[int i, int j]
56+
{
57+
get => this.spotsTaken[(i * Width) + j];
58+
set => this.spotsTaken[(i * Width) + j] = value;
59+
}
60+
61+
/// <summary>
62+
/// Fills the specified area in the current grid with a given value.
63+
/// If invalid coordinates are given, they will simply be ignored and no exception will be thrown.
64+
/// </summary>
65+
/// <param name="value">The value to fill the target area with.</param>
66+
/// <param name="row">The row to start on (inclusive, 0-based index).</param>
67+
/// <param name="column">The column to start on (inclusive, 0-based index).</param>
68+
/// <param name="width">The positive width of area to fill.</param>
69+
/// <param name="height">The positive height of area to fill.</param>
70+
public void Fill(bool value, int row, int column, int width, int height)
71+
{
72+
Rectangle bounds = new Rectangle(0, 0, Width, Height);
73+
74+
// Precompute bounds to skip branching in main loop
75+
bounds.Intersect(new Rectangle(column, row, width, height));
76+
77+
for (int i = bounds.Top; i < bounds.Bottom; i++)
78+
{
79+
for (int j = bounds.Left; j < bounds.Right; j++)
80+
{
81+
this[i, j] = value;
82+
}
83+
}
3184
}
3285

33-
public TakenSpotsReferenceHolder(bool[,] array)
86+
/// <summary>
87+
/// Resets the current reference holder.
88+
/// </summary>
89+
public void Reset()
3490
{
35-
SpotsTaken = array;
91+
this.spotsTaken.SetAll(false);
3692
}
3793
}
3894
}

0 commit comments

Comments
 (0)