Merge branch 'master' into aleader/notifications-registry
This commit is contained in:
Коммит
62bc118f23
|
@ -13,14 +13,14 @@ namespace Microsoft.Toolkit.HighPerformance.Streams
|
|||
internal static partial class MemoryStream
|
||||
{
|
||||
/// <summary>
|
||||
/// Validates the <see cref="Stream.Position"/> argument.
|
||||
/// Validates the <see cref="Stream.Position"/> argument (it needs to be in the [0, length]) range.
|
||||
/// </summary>
|
||||
/// <param name="position">The new <see cref="Stream.Position"/> value being set.</param>
|
||||
/// <param name="length">The maximum length of the target <see cref="Stream"/>.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void ValidatePosition(long position, int length)
|
||||
{
|
||||
if ((ulong)position >= (ulong)length)
|
||||
if ((ulong)position > (ulong)length)
|
||||
{
|
||||
ThrowArgumentOutOfRangeExceptionForPosition();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
# How to add new samples
|
||||
For the latest info, [visit the wiki article here](https://github.com/windows-toolkit/WindowsCommunityToolkit/wiki/Sample-Development).
|
||||
|
||||
# How to add new samples
|
||||
|
||||
This document describes how to add a new sample page for a new control you want to add to the toolkit.
|
||||
|
||||
|
|
|
@ -3,8 +3,10 @@
|
|||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using Microsoft.Toolkit.Uwp.UI.Automation.Peers;
|
||||
using Windows.System;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Automation.Peers;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Controls.Primitives;
|
||||
using Windows.UI.Xaml.Input;
|
||||
|
@ -76,6 +78,15 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
|
|||
Collapsed?.Invoke(this, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates AutomationPeer (<see cref="UIElement.OnCreateAutomationPeer"/>)
|
||||
/// </summary>
|
||||
/// <returns>An automation peer for this <see cref="Expander"/>.</returns>
|
||||
protected override AutomationPeer OnCreateAutomationPeer()
|
||||
{
|
||||
return new ExpanderAutomationPeer(this);
|
||||
}
|
||||
|
||||
private void ExpanderToggleButtonPart_KeyDown(object sender, KeyRoutedEventArgs e)
|
||||
{
|
||||
if (e.Key != VirtualKey.Enter)
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.Toolkit.Uwp.UI.Controls;
|
||||
using Windows.UI.Xaml.Automation;
|
||||
using Windows.UI.Xaml.Automation.Peers;
|
||||
using Windows.UI.Xaml.Automation.Provider;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Automation.Peers
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a framework element automation peer for the <see cref="Expander"/> control.
|
||||
/// </summary>
|
||||
public class ExpanderAutomationPeer : FrameworkElementAutomationPeer, IToggleProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ExpanderAutomationPeer"/> class.
|
||||
/// </summary>
|
||||
/// <param name="owner">
|
||||
/// The <see cref="Expander" /> that is associated with this <see cref="T:Windows.UI.Xaml.Automation.Peers.ExpanderAutomationPeer" />.
|
||||
/// </param>
|
||||
public ExpanderAutomationPeer(Expander owner)
|
||||
: base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>Gets the toggle state of the control.</summary>
|
||||
/// <returns>The toggle state of the control, as a value of the enumeration.</returns>
|
||||
public ToggleState ToggleState => OwningExpander.IsExpanded ? ToggleState.On : ToggleState.Off;
|
||||
|
||||
private Expander OwningExpander
|
||||
{
|
||||
get
|
||||
{
|
||||
return Owner as Expander;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Cycles through the toggle states of a control.</summary>
|
||||
public void Toggle()
|
||||
{
|
||||
if (!IsEnabled())
|
||||
{
|
||||
throw new ElementNotEnabledException();
|
||||
}
|
||||
|
||||
OwningExpander.IsExpanded = !OwningExpander.IsExpanded;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the control type for the element that is associated with the UI Automation peer.
|
||||
/// </summary>
|
||||
/// <returns>The control type.</returns>
|
||||
protected override AutomationControlType GetAutomationControlTypeCore()
|
||||
{
|
||||
return AutomationControlType.Custom;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by GetClassName that gets a human readable name that, in addition to AutomationControlType,
|
||||
/// differentiates the control represented by this AutomationPeer.
|
||||
/// </summary>
|
||||
/// <returns>The string that contains the name.</returns>
|
||||
protected override string GetClassNameCore()
|
||||
{
|
||||
return Owner.GetType().Name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by GetName.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// Returns the first of these that is not null or empty:
|
||||
/// - Value returned by the base implementation
|
||||
/// - Name of the owning Expander
|
||||
/// - Expander class name
|
||||
/// </returns>
|
||||
protected override string GetNameCore()
|
||||
{
|
||||
string name = base.GetNameCore();
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
if (this.OwningExpander != null)
|
||||
{
|
||||
name = this.OwningExpander.Name;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
name = this.GetClassName();
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the control pattern that is associated with the specified Windows.UI.Xaml.Automation.Peers.PatternInterface.
|
||||
/// </summary>
|
||||
/// <param name="patternInterface">A value from the Windows.UI.Xaml.Automation.Peers.PatternInterface enumeration.</param>
|
||||
/// <returns>The object that supports the specified pattern, or null if unsupported.</returns>
|
||||
protected override object GetPatternCore(PatternInterface patternInterface)
|
||||
{
|
||||
switch (patternInterface)
|
||||
{
|
||||
case PatternInterface.Toggle:
|
||||
return this;
|
||||
}
|
||||
|
||||
return base.GetPatternCore(patternInterface);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,11 +2,9 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections;
|
||||
using System.Drawing;
|
||||
using Microsoft.Toolkit.Diagnostics;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Controls
|
||||
{
|
||||
|
@ -16,23 +14,81 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
|
|||
/// <see cref="UniformGrid.GetFreeSpot"/> iterator.
|
||||
/// This is used so we can better isolate our logic and make it easier to test.
|
||||
/// </summary>
|
||||
internal class TakenSpotsReferenceHolder
|
||||
internal sealed class TakenSpotsReferenceHolder
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the array to hold taken spots.
|
||||
/// True value indicates an item in the layout is fixed to that position.
|
||||
/// False values indicate free openings where an item can be placed.
|
||||
/// The <see cref="BitArray"/> instance used to efficiently track empty spots.
|
||||
/// </summary>
|
||||
public bool[,] SpotsTaken { get; set; }
|
||||
private readonly BitArray spotsTaken;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TakenSpotsReferenceHolder"/> class.
|
||||
/// </summary>
|
||||
/// <param name="rows">The number of rows to track.</param>
|
||||
/// <param name="columns">The number of columns to track.</param>
|
||||
public TakenSpotsReferenceHolder(int rows, int columns)
|
||||
{
|
||||
SpotsTaken = new bool[rows, columns];
|
||||
Guard.IsGreaterThanOrEqualTo(rows, 0, nameof(rows));
|
||||
Guard.IsGreaterThanOrEqualTo(columns, 0, nameof(columns));
|
||||
|
||||
Height = rows;
|
||||
Width = columns;
|
||||
|
||||
this.spotsTaken = new BitArray(rows * columns);
|
||||
}
|
||||
|
||||
public TakenSpotsReferenceHolder(bool[,] array)
|
||||
/// <summary>
|
||||
/// Gets the height of the grid to monitor.
|
||||
/// </summary>
|
||||
public int Height { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the width of the grid to monitor.
|
||||
/// </summary>
|
||||
public int Width { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value of a specified grid cell.
|
||||
/// </summary>
|
||||
/// <param name="i">The vertical offset.</param>
|
||||
/// <param name="j">The horizontal offset.</param>
|
||||
public bool this[int i, int j]
|
||||
{
|
||||
SpotsTaken = array;
|
||||
get => this.spotsTaken[(i * Width) + j];
|
||||
set => this.spotsTaken[(i * Width) + j] = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fills the specified area in the current grid with a given value.
|
||||
/// If invalid coordinates are given, they will simply be ignored and no exception will be thrown.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to fill the target area with.</param>
|
||||
/// <param name="row">The row to start on (inclusive, 0-based index).</param>
|
||||
/// <param name="column">The column to start on (inclusive, 0-based index).</param>
|
||||
/// <param name="width">The positive width of area to fill.</param>
|
||||
/// <param name="height">The positive height of area to fill.</param>
|
||||
public void Fill(bool value, int row, int column, int width, int height)
|
||||
{
|
||||
Rectangle bounds = new Rectangle(0, 0, Width, Height);
|
||||
|
||||
// Precompute bounds to skip branching in main loop
|
||||
bounds.Intersect(new Rectangle(column, row, width, height));
|
||||
|
||||
for (int i = bounds.Top; i < bounds.Bottom; i++)
|
||||
{
|
||||
for (int j = bounds.Left; j < bounds.Right; j++)
|
||||
{
|
||||
this[i, j] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the current reference holder.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
this.spotsTaken.SetAll(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,16 +22,16 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
|
|||
{
|
||||
if (topdown)
|
||||
{
|
||||
var rows = arrayref.SpotsTaken.GetLength(0);
|
||||
var rows = arrayref.Height;
|
||||
|
||||
// Layout spots from Top-Bottom, Left-Right (right-left handled automatically by Grid with Flow-Direction).
|
||||
// Effectively transpose the Grid Layout.
|
||||
for (int c = 0; c < arrayref.SpotsTaken.GetLength(1); c++)
|
||||
for (int c = 0; c < arrayref.Width; c++)
|
||||
{
|
||||
int start = (c == 0 && firstcolumn > 0 && firstcolumn < rows) ? firstcolumn : 0;
|
||||
for (int r = start; r < rows; r++)
|
||||
{
|
||||
if (!arrayref.SpotsTaken[r, c])
|
||||
if (!arrayref[r, c])
|
||||
{
|
||||
yield return (r, c);
|
||||
}
|
||||
|
@ -40,17 +40,17 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
|
|||
}
|
||||
else
|
||||
{
|
||||
var columns = arrayref.SpotsTaken.GetLength(1);
|
||||
var columns = arrayref.Width;
|
||||
|
||||
// Layout spots as normal from Left-Right.
|
||||
// (right-left handled automatically by Grid with Flow-Direction
|
||||
// during its layout, internal model is always left-right).
|
||||
for (int r = 0; r < arrayref.SpotsTaken.GetLength(0); r++)
|
||||
for (int r = 0; r < arrayref.Height; r++)
|
||||
{
|
||||
int start = (r == 0 && firstcolumn > 0 && firstcolumn < columns) ? firstcolumn : 0;
|
||||
for (int c = start; c < columns; c++)
|
||||
{
|
||||
if (!arrayref.SpotsTaken[r, c])
|
||||
if (!arrayref[r, c])
|
||||
{
|
||||
yield return (r, c);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Toolkit.Extensions;
|
||||
using Windows.Foundation;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
@ -20,6 +19,11 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
|
|||
// Internal list we use to keep track of items that we don't have space to layout.
|
||||
private List<UIElement> _overflow = new List<UIElement>();
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="TakenSpotsReferenceHolder"/> instance in use, if any.
|
||||
/// </summary>
|
||||
private TakenSpotsReferenceHolder _spotref;
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
|
@ -36,7 +40,20 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
|
|||
SetupRowDefinitions(rows);
|
||||
SetupColumnDefinitions(columns);
|
||||
|
||||
var spotref = new TakenSpotsReferenceHolder(rows, columns);
|
||||
TakenSpotsReferenceHolder spotref;
|
||||
|
||||
// If the last spot holder matches the size currently in use, just reset
|
||||
// that instance and reuse it to avoid allocating a new bit array.
|
||||
if (_spotref != null && _spotref.Height == rows && _spotref.Width == columns)
|
||||
{
|
||||
spotref = _spotref;
|
||||
|
||||
spotref.Reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
spotref = _spotref = new TakenSpotsReferenceHolder(rows, columns);
|
||||
}
|
||||
|
||||
// Figure out which children we should automatically layout and where available openings are.
|
||||
foreach (var child in visible)
|
||||
|
@ -56,7 +73,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
|
|||
else
|
||||
{
|
||||
SetAutoLayout(child, false);
|
||||
spotref.SpotsTaken.Fill(true, row, col, colspan, rowspan); // row, col, width, height
|
||||
|
||||
spotref.Fill(true, row, col, colspan, rowspan);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,7 +118,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
|
|||
if (rowspan > 1 || colspan > 1)
|
||||
{
|
||||
// TODO: Need to tie this into iterator
|
||||
spotref.SpotsTaken.Fill(true, row, column, GetColumnSpan(child), GetRowSpan(child)); // row, col, width, height
|
||||
spotref.Fill(true, row, column, colspan, rowspan);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -135,7 +153,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
|
|||
}
|
||||
|
||||
// Return our desired size based on the largest child we found, our dimensions, and spacing.
|
||||
var desiredSize = new Size((maxWidth * (double)columns) + columnSpacingSize, (maxHeight * (double)rows) + rowSpacingSize);
|
||||
var desiredSize = new Size((maxWidth * columns) + columnSpacingSize, (maxHeight * rows) + rowSpacingSize);
|
||||
|
||||
// Required to perform regular grid measurement, but ignore result.
|
||||
base.MeasureOverride(desiredSize);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Toolkit.Extensions
|
||||
{
|
||||
|
@ -13,71 +14,6 @@ namespace Microsoft.Toolkit.Extensions
|
|||
/// </summary>
|
||||
public static class ArrayExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Fills elements of a rectangular array at the given position and size to a specific value.
|
||||
/// Ranges given will fill in as many elements as possible, ignoring positions outside the bounds of the array.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The element type of the array.</typeparam>
|
||||
/// <param name="array">The source array.</param>
|
||||
/// <param name="value">Value to fill with.</param>
|
||||
/// <param name="row">Row to start on (inclusive, zero-index).</param>
|
||||
/// <param name="col">Column to start on (inclusive, zero-index).</param>
|
||||
/// <param name="width">Positive width of area to fill.</param>
|
||||
/// <param name="height">Positive height of area to fill.</param>
|
||||
public static void Fill<T>(this T[,] array, T value, int row, int col, int width, int height)
|
||||
{
|
||||
for (int r = row; r < row + height; r++)
|
||||
{
|
||||
for (int c = col; c < col + width; c++)
|
||||
{
|
||||
if (r >= 0 && c >= 0 && r < array.GetLength(0) && c < array.GetLength(1))
|
||||
{
|
||||
array[r, c] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Yields a row from a rectangular array.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The element type of the array.</typeparam>
|
||||
/// <param name="rectarray">The source array.</param>
|
||||
/// <param name="row">Row record to retrieve, 0-based index.</param>
|
||||
/// <returns>Yielded row.</returns>
|
||||
public static IEnumerable<T> GetRow<T>(this T[,] rectarray, int row)
|
||||
{
|
||||
if (row < 0 || row >= rectarray.GetLength(0))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(row));
|
||||
}
|
||||
|
||||
for (int c = 0; c < rectarray.GetLength(1); c++)
|
||||
{
|
||||
yield return rectarray[row, c];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Yields a column from a rectangular array.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The element type of the array.</typeparam>
|
||||
/// <param name="rectarray">The source array.</param>
|
||||
/// <param name="column">Column record to retrieve, 0-based index.</param>
|
||||
/// <returns>Yielded column.</returns>
|
||||
public static IEnumerable<T> GetColumn<T>(this T[,] rectarray, int column)
|
||||
{
|
||||
if (column < 0 || column >= rectarray.GetLength(1))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(column));
|
||||
}
|
||||
|
||||
for (int r = 0; r < rectarray.GetLength(0); r++)
|
||||
{
|
||||
yield return rectarray[r, column];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Yields a column from a jagged array.
|
||||
/// An exception will be thrown if the column is out of bounds, and return default in places where there are no elements from inner arrays.
|
||||
|
@ -98,7 +34,7 @@ namespace Microsoft.Toolkit.Extensions
|
|||
{
|
||||
if (column >= rectarray[r].Length)
|
||||
{
|
||||
yield return default(T);
|
||||
yield return default;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
@ -112,10 +48,28 @@ namespace Microsoft.Toolkit.Extensions
|
|||
/// </summary>
|
||||
/// <typeparam name="T">The element type of the array.</typeparam>
|
||||
/// <param name="array">The source array.</param>
|
||||
/// <returns>String representation of the array.</returns>
|
||||
/// <returns>The <see cref="string"/> representation of the array.</returns>
|
||||
public static string ToArrayString<T>(this T[] array)
|
||||
{
|
||||
return "[" + string.Join(",\t", array) + "]";
|
||||
// The returned string will be in the following format:
|
||||
// [1, 2, 3]
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
builder.Append('[');
|
||||
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
if (i != 0)
|
||||
{
|
||||
builder.Append(",\t");
|
||||
}
|
||||
|
||||
builder.Append(array[i].ToString());
|
||||
}
|
||||
|
||||
builder.Append(']');
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -126,32 +80,89 @@ namespace Microsoft.Toolkit.Extensions
|
|||
/// <returns>String representation of the array.</returns>
|
||||
public static string ToArrayString<T>(this T[][] mdarray)
|
||||
{
|
||||
string[] inner = new string[mdarray.GetLength(0)];
|
||||
// The returned string uses the same format as the overload for 2D arrays
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
for (int r = 0; r < mdarray.GetLength(0); r++)
|
||||
builder.Append('[');
|
||||
|
||||
for (int i = 0; i < mdarray.Length; i++)
|
||||
{
|
||||
inner[r] = string.Join(",\t", mdarray[r]);
|
||||
if (i != 0)
|
||||
{
|
||||
builder.Append(',');
|
||||
builder.Append(Environment.NewLine);
|
||||
builder.Append(' ');
|
||||
}
|
||||
|
||||
builder.Append('[');
|
||||
|
||||
T[] row = mdarray[i];
|
||||
|
||||
for (int j = 0; j < row.Length; j++)
|
||||
{
|
||||
if (j != 0)
|
||||
{
|
||||
builder.Append(",\t");
|
||||
}
|
||||
|
||||
builder.Append(row[j].ToString());
|
||||
}
|
||||
|
||||
builder.Append(']');
|
||||
}
|
||||
|
||||
return "[[" + string.Join("]," + Environment.NewLine + " [", inner) + "]]";
|
||||
builder.Append(']');
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a simple string representation of a rectangular array.
|
||||
/// Returns a simple string representation of a 2D array.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The element type of the array.</typeparam>
|
||||
/// <param name="rectarray">The source array.</param>
|
||||
/// <returns>String representation of the array.</returns>
|
||||
public static string ToArrayString<T>(this T[,] rectarray)
|
||||
/// <param name="array">The source array.</param>
|
||||
/// <returns>The <see cref="string"/> representation of the array.</returns>
|
||||
public static string ToArrayString<T>(this T[,] array)
|
||||
{
|
||||
string[] inner = new string[rectarray.GetLength(0)];
|
||||
// The returned string will be in the following format:
|
||||
// [[1, 2, 3],
|
||||
// [4, 5, 6],
|
||||
// [7, 8, 9]]
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
for (int r = 0; r < rectarray.GetLength(0); r++)
|
||||
builder.Append('[');
|
||||
|
||||
int
|
||||
height = array.GetLength(0),
|
||||
width = array.GetLength(1);
|
||||
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
inner[r] = string.Join(",\t", rectarray.GetRow(r));
|
||||
if (i != 0)
|
||||
{
|
||||
builder.Append(',');
|
||||
builder.Append(Environment.NewLine);
|
||||
builder.Append(' ');
|
||||
}
|
||||
|
||||
builder.Append('[');
|
||||
|
||||
for (int j = 0; j < width; j++)
|
||||
{
|
||||
if (j != 0)
|
||||
{
|
||||
builder.Append(",\t");
|
||||
}
|
||||
|
||||
builder.Append(array[i, j].ToString());
|
||||
}
|
||||
|
||||
builder.Append(']');
|
||||
}
|
||||
|
||||
return "[[" + string.Join("]," + Environment.NewLine + " [", inner) + "]]";
|
||||
builder.Append(']');
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,6 +78,42 @@ namespace UnitTests.HighPerformance.Streams
|
|||
Assert.AreEqual(stream.Position, 32);
|
||||
}
|
||||
|
||||
// See https://github.com/windows-toolkit/WindowsCommunityToolkit/issues/3536
|
||||
[TestCategory("MemoryStream")]
|
||||
[TestMethod]
|
||||
public void Test_MemoryStream_WriteToEndAndRefreshPosition()
|
||||
{
|
||||
byte[]
|
||||
array = new byte[10],
|
||||
temp = new byte[1];
|
||||
ReadOnlyMemory<byte> memory = array;
|
||||
|
||||
using var stream = memory.AsStream();
|
||||
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
int read = stream.Read(temp, 0, 1);
|
||||
|
||||
Assert.AreEqual(read, 1);
|
||||
Assert.AreEqual(stream.Position, i + 1);
|
||||
}
|
||||
|
||||
Assert.AreEqual(stream.Position, array.Length);
|
||||
|
||||
// These should not throw, seeking to the end is valid
|
||||
stream.Position = stream.Position;
|
||||
Assert.AreEqual(stream.Position, array.Length);
|
||||
|
||||
stream.Seek(array.Length, SeekOrigin.Begin);
|
||||
Assert.AreEqual(stream.Position, array.Length);
|
||||
|
||||
stream.Seek(0, SeekOrigin.Current);
|
||||
Assert.AreEqual(stream.Position, array.Length);
|
||||
|
||||
stream.Seek(0, SeekOrigin.End);
|
||||
Assert.AreEqual(stream.Position, array.Length);
|
||||
}
|
||||
|
||||
[TestCategory("MemoryStream")]
|
||||
[TestMethod]
|
||||
public void Test_MemoryStream_ReadWrite_Array()
|
||||
|
|
|
@ -13,161 +13,6 @@ namespace UnitTests.Extensions
|
|||
[TestClass]
|
||||
public class Test_ArrayExtensions
|
||||
{
|
||||
[TestCategory("ArrayExtensions")]
|
||||
[TestMethod]
|
||||
public void Test_ArrayExtensions_FillArrayMid()
|
||||
{
|
||||
bool[,] test = new bool[4, 5];
|
||||
|
||||
test.Fill(true, 1, 1, 3, 2);
|
||||
|
||||
var expected = new bool[,]
|
||||
{
|
||||
{ false, false, false, false, false },
|
||||
{ false, true, true, true, false },
|
||||
{ false, true, true, true, false },
|
||||
{ false, false, false, false, false },
|
||||
};
|
||||
|
||||
CollectionAssert.AreEqual(
|
||||
expected,
|
||||
test,
|
||||
"Fill failed. Expected:\n{0}.\nActual:\n{1}",
|
||||
expected.ToArrayString(),
|
||||
test.ToArrayString());
|
||||
}
|
||||
|
||||
[TestCategory("ArrayExtensions")]
|
||||
[TestMethod]
|
||||
public void Test_ArrayExtensions_FillArrayTwice()
|
||||
{
|
||||
bool[,] test = new bool[4, 5];
|
||||
|
||||
test.Fill(true, 0, 0, 1, 2);
|
||||
test.Fill(true, 1, 3, 2, 2);
|
||||
|
||||
var expected = new bool[,]
|
||||
{
|
||||
{ true, false, false, false, false },
|
||||
{ true, false, false, true, true },
|
||||
{ false, false, false, true, true },
|
||||
{ false, false, false, false, false },
|
||||
};
|
||||
|
||||
CollectionAssert.AreEqual(
|
||||
expected,
|
||||
test,
|
||||
"Fill failed. Expected:\n{0}.\nActual:\n{1}",
|
||||
expected.ToArrayString(),
|
||||
test.ToArrayString());
|
||||
}
|
||||
|
||||
[TestCategory("ArrayExtensions")]
|
||||
[TestMethod]
|
||||
public void Test_ArrayExtensions_FillArrayNegativeSize()
|
||||
{
|
||||
bool[,] test = new bool[4, 5];
|
||||
|
||||
test.Fill(true, 3, 4, -3, -2);
|
||||
|
||||
// TODO: We may want to think about this pattern in the future:
|
||||
/*var expected = new bool[,]
|
||||
{
|
||||
{ false, false, false, false, false },
|
||||
{ false, false, false, false, false },
|
||||
{ false, false, true, true, true },
|
||||
{ false, false, true, true, true },
|
||||
};*/
|
||||
|
||||
var expected = new bool[,]
|
||||
{
|
||||
{ false, false, false, false, false },
|
||||
{ false, false, false, false, false },
|
||||
{ false, false, false, false, false },
|
||||
{ false, false, false, false, false },
|
||||
};
|
||||
|
||||
CollectionAssert.AreEqual(
|
||||
expected,
|
||||
test,
|
||||
"Fill failed. Expected:\n{0}.\nActual:\n{1}",
|
||||
expected.ToArrayString(),
|
||||
test.ToArrayString());
|
||||
}
|
||||
|
||||
[TestCategory("ArrayExtensions")]
|
||||
[TestMethod]
|
||||
public void Test_ArrayExtensions_FillArrayBottomEdgeBoundary()
|
||||
{
|
||||
bool[,] test = new bool[4, 5];
|
||||
|
||||
test.Fill(true, 1, 2, 2, 4);
|
||||
|
||||
var expected = new bool[,]
|
||||
{
|
||||
{ false, false, false, false, false },
|
||||
{ false, false, true, true, false },
|
||||
{ false, false, true, true, false },
|
||||
{ false, false, true, true, false },
|
||||
};
|
||||
|
||||
CollectionAssert.AreEqual(
|
||||
expected,
|
||||
test,
|
||||
"Fill failed. Expected:\n{0}.\nActual:\n{1}",
|
||||
expected.ToArrayString(),
|
||||
test.ToArrayString());
|
||||
}
|
||||
|
||||
[TestCategory("ArrayExtensions")]
|
||||
[TestMethod]
|
||||
public void Test_ArrayExtensions_FillArrayTopLeftCornerNegativeBoundary()
|
||||
{
|
||||
bool[,] test = new bool[4, 5];
|
||||
|
||||
test.Fill(true, -1, -1, 3, 3);
|
||||
|
||||
var expected = new bool[,]
|
||||
{
|
||||
{ true, true, false, false, false },
|
||||
{ true, true, false, false, false },
|
||||
{ false, false, false, false, false },
|
||||
{ false, false, false, false, false },
|
||||
};
|
||||
|
||||
CollectionAssert.AreEqual(
|
||||
expected,
|
||||
test,
|
||||
"Fill failed. Expected:\n{0}.\nActual:\n{1}",
|
||||
expected.ToArrayString(),
|
||||
test.ToArrayString());
|
||||
}
|
||||
|
||||
[TestCategory("ArrayExtensions")]
|
||||
[TestMethod]
|
||||
public void Test_ArrayExtensions_FillArrayBottomRightCornerBoundary()
|
||||
{
|
||||
bool[,] test = new bool[5, 4];
|
||||
|
||||
test.Fill(true, 3, 2, 3, 3);
|
||||
|
||||
var expected = new bool[,]
|
||||
{
|
||||
{ false, false, false, false },
|
||||
{ false, false, false, false },
|
||||
{ false, false, false, false },
|
||||
{ false, false, true, true },
|
||||
{ false, false, true, true },
|
||||
};
|
||||
|
||||
CollectionAssert.AreEqual(
|
||||
expected,
|
||||
test,
|
||||
"Fill failed. Expected:\n{0}.\nActual:\n{1}",
|
||||
expected.ToArrayString(),
|
||||
test.ToArrayString());
|
||||
}
|
||||
|
||||
[TestCategory("ArrayExtensions")]
|
||||
[TestMethod]
|
||||
public void Test_ArrayExtensions_Jagged_GetColumn()
|
||||
|
@ -206,82 +51,6 @@ namespace UnitTests.Extensions
|
|||
});
|
||||
}
|
||||
|
||||
[TestCategory("ArrayExtensions")]
|
||||
[TestMethod]
|
||||
public void Test_ArrayExtensions_Rectangular_GetColumn()
|
||||
{
|
||||
int[,] array =
|
||||
{
|
||||
{ 5, 2, 4 },
|
||||
{ 6, 3, 9 },
|
||||
{ 7, -1, 0 }
|
||||
};
|
||||
|
||||
var col = array.GetColumn(1).ToArray();
|
||||
|
||||
CollectionAssert.AreEquivalent(new int[] { 2, 3, -1 }, col);
|
||||
}
|
||||
|
||||
[TestCategory("ArrayExtensions")]
|
||||
[TestMethod]
|
||||
public void Test_ArrayExtensions_Rectangular_GetColumn_Exception()
|
||||
{
|
||||
int[,] array =
|
||||
{
|
||||
{ 5, 2, 4 },
|
||||
{ 6, 3, 0 },
|
||||
{ 7, 0, 0 }
|
||||
};
|
||||
|
||||
Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
|
||||
{
|
||||
array.GetColumn(-1).ToArray();
|
||||
});
|
||||
|
||||
Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
|
||||
{
|
||||
array.GetColumn(3).ToArray();
|
||||
});
|
||||
}
|
||||
|
||||
[TestCategory("ArrayExtensions")]
|
||||
[TestMethod]
|
||||
public void Test_ArrayExtensions_Rectangular_GetRow()
|
||||
{
|
||||
int[,] array =
|
||||
{
|
||||
{ 5, 2, 4 },
|
||||
{ 6, 3, 9 },
|
||||
{ 7, -1, 0 }
|
||||
};
|
||||
|
||||
var col = array.GetRow(1).ToArray();
|
||||
|
||||
CollectionAssert.AreEquivalent(new int[] { 6, 3, 9 }, col);
|
||||
}
|
||||
|
||||
[TestCategory("ArrayExtensions")]
|
||||
[TestMethod]
|
||||
public void Test_ArrayExtensions_Rectangular_GetRow_Exception()
|
||||
{
|
||||
int[,] array =
|
||||
{
|
||||
{ 5, 2, 4 },
|
||||
{ 6, 3, 0 },
|
||||
{ 7, 0, 0 }
|
||||
};
|
||||
|
||||
Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
|
||||
{
|
||||
array.GetRow(-1).ToArray();
|
||||
});
|
||||
|
||||
Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
|
||||
{
|
||||
array.GetRow(3).ToArray();
|
||||
});
|
||||
}
|
||||
|
||||
[TestCategory("ArrayExtensions")]
|
||||
[TestMethod]
|
||||
public void Test_ArrayExtensions_Rectangular_ToString()
|
||||
|
|
|
@ -13,11 +13,31 @@ namespace UnitTests.UI.Controls
|
|||
[TestClass]
|
||||
public class Test_UniformGrid_FreeSpots
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a <see cref="TakenSpotsReferenceHolder"/> instance with the specified values.
|
||||
/// </summary>
|
||||
/// <param name="array">The source array to populate the instance to return.</param>
|
||||
/// <returns>A <see cref="TakenSpotsReferenceHolder"/> with the given values.</returns>
|
||||
private static TakenSpotsReferenceHolder CreateTakenSpotsReferenceHolder(bool[,] array)
|
||||
{
|
||||
var refHolder = new TakenSpotsReferenceHolder(array.GetLength(0), array.GetLength(1));
|
||||
|
||||
for (int i = 0; i < array.GetLength(0); i++)
|
||||
{
|
||||
for (int j = 0; j < array.GetLength(1); j++)
|
||||
{
|
||||
refHolder[i, j] = array[i, j];
|
||||
}
|
||||
}
|
||||
|
||||
return refHolder;
|
||||
}
|
||||
|
||||
[TestCategory("UniformGrid")]
|
||||
[UITestMethod]
|
||||
public void Test_UniformGrid_GetFreeSpots_Basic()
|
||||
{
|
||||
var testRef = new TakenSpotsReferenceHolder(new bool[4, 5]
|
||||
var testRef = CreateTakenSpotsReferenceHolder(new bool[4, 5]
|
||||
{
|
||||
{ false, true, false, true, false },
|
||||
{ false, true, true, true, false },
|
||||
|
@ -47,7 +67,7 @@ namespace UnitTests.UI.Controls
|
|||
[UITestMethod]
|
||||
public void Test_UniformGrid_GetFreeSpots_FirstColumn()
|
||||
{
|
||||
var testRef = new TakenSpotsReferenceHolder(new bool[4, 5]
|
||||
var testRef = CreateTakenSpotsReferenceHolder(new bool[4, 5]
|
||||
{
|
||||
{ true, false, false, true, false },
|
||||
{ false, true, true, true, false },
|
||||
|
@ -77,7 +97,7 @@ namespace UnitTests.UI.Controls
|
|||
[UITestMethod]
|
||||
public void Test_UniformGrid_GetFreeSpots_FirstColumnEndBoundMinusOne()
|
||||
{
|
||||
var testRef = new TakenSpotsReferenceHolder(new bool[3, 3]
|
||||
var testRef = CreateTakenSpotsReferenceHolder(new bool[3, 3]
|
||||
{
|
||||
{ false, false, false },
|
||||
{ false, false, false },
|
||||
|
@ -105,7 +125,7 @@ namespace UnitTests.UI.Controls
|
|||
[UITestMethod]
|
||||
public void Test_UniformGrid_GetFreeSpots_FirstColumnEndBound()
|
||||
{
|
||||
var testRef = new TakenSpotsReferenceHolder(new bool[3, 3]
|
||||
var testRef = CreateTakenSpotsReferenceHolder(new bool[3, 3]
|
||||
{
|
||||
{ false, false, false },
|
||||
{ false, false, false },
|
||||
|
@ -133,7 +153,7 @@ namespace UnitTests.UI.Controls
|
|||
[UITestMethod]
|
||||
public void Test_UniformGrid_GetFreeSpots_FirstColumnEndBound_TopDown()
|
||||
{
|
||||
var testRef = new TakenSpotsReferenceHolder(new bool[3, 3]
|
||||
var testRef = CreateTakenSpotsReferenceHolder(new bool[3, 3]
|
||||
{
|
||||
{ false, false, false },
|
||||
{ false, false, false },
|
||||
|
@ -161,7 +181,7 @@ namespace UnitTests.UI.Controls
|
|||
[UITestMethod]
|
||||
public void Test_UniformGrid_GetFreeSpots_VerticalOrientation()
|
||||
{
|
||||
var testRef = new TakenSpotsReferenceHolder(new bool[4, 5]
|
||||
var testRef = CreateTakenSpotsReferenceHolder(new bool[4, 5]
|
||||
{
|
||||
{ false, false, false, true, false },
|
||||
{ false, true, true, false, false },
|
||||
|
|
Загрузка…
Ссылка в новой задаче