Use HorizontalGrid and VerticalGrid string values to specify GridItemsLayout in XAML (#8104)
* Convert HorizontalGrid and VerticalGrid strings to ItemsLayout (#5577) * Support GridLayout in ItemsLayoutDesignTypeConverter #5577 * Add Issue5577 control to test ItemsLayoutConverter * Optimize ItemsLayoutTypeConverter * Expect InvalidOperationException, when span is missing in ItemsLayoutTypeConverter Co-authored-by: E.Z. Hart <hartez@users.noreply.github.com>
This commit is contained in:
Родитель
3cf328628c
Коммит
f06cb1f652
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<controls:TestContentPage
|
||||
xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:controls="clr-namespace:Xamarin.Forms.Controls"
|
||||
x:Class="Xamarin.Forms.Controls.Issues.Issue5577">
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label Grid.Row="0" LineBreakMode="WordWrap" Text="Page should display 2 collection view with horizontal and vertical grid layouts"/>
|
||||
|
||||
<CollectionView Grid.Row="1" ItemsSource="{Binding Animals}" ItemsLayout="HorizontalGrid, 2" BackgroundColor="Yellow">
|
||||
<CollectionView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackLayout>
|
||||
<Label Text="{Binding Name}"/>
|
||||
<Label Text="{Binding Location}"/>
|
||||
</StackLayout>
|
||||
</DataTemplate>
|
||||
</CollectionView.ItemTemplate>
|
||||
</CollectionView>
|
||||
|
||||
<CollectionView Grid.Row="2" ItemsSource="{Binding Animals}" ItemsLayout="VerticalGrid, 4">
|
||||
<CollectionView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackLayout>
|
||||
<Label Text="{Binding Name}"/>
|
||||
<Label Text="{Binding Location}"/>
|
||||
</StackLayout>
|
||||
</DataTemplate>
|
||||
</CollectionView.ItemTemplate>
|
||||
</CollectionView>
|
||||
</Grid>
|
||||
</controls:TestContentPage>
|
|
@ -0,0 +1,113 @@
|
|||
using System.Collections.ObjectModel;
|
||||
using Xamarin.Forms.CustomAttributes;
|
||||
using Xamarin.Forms.Internals;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
#if UITEST
|
||||
using Xamarin.Forms.Core.UITests;
|
||||
#endif
|
||||
|
||||
namespace Xamarin.Forms.Controls.Issues
|
||||
{
|
||||
#if UITEST
|
||||
[NUnit.Framework.Category(UITestCategories.CollectionView)]
|
||||
#endif
|
||||
#if APP
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
#endif
|
||||
[Preserve(AllMembers = true)]
|
||||
[Issue(IssueTracker.Github, 5577, "CollectionView XAML API suggestion", PlatformAffected.All)]
|
||||
public partial class Issue5577 : TestContentPage
|
||||
{
|
||||
#if APP
|
||||
public Issue5577()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
BindingContext = new ViewModel5577();
|
||||
}
|
||||
#endif
|
||||
|
||||
protected override void Init()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[Preserve(AllMembers = true)]
|
||||
public class ViewModel5577
|
||||
{
|
||||
public ViewModel5577()
|
||||
{
|
||||
AddAnimals();
|
||||
}
|
||||
|
||||
public ObservableCollection<Model5577> Animals { get; private set; } = new ObservableCollection<Model5577>();
|
||||
|
||||
private void AddAnimals()
|
||||
{
|
||||
Animals.Add(new Model5577
|
||||
{
|
||||
Name = "Afghan Hound",
|
||||
Location = "Afghanistan",
|
||||
});
|
||||
Animals.Add(new Model5577
|
||||
{
|
||||
Name = "Alpine Dachsbracke",
|
||||
Location = "Austria",
|
||||
});
|
||||
Animals.Add(new Model5577
|
||||
{
|
||||
Name = "American Bulldog",
|
||||
Location = "United States",
|
||||
});
|
||||
Animals.Add(new Model5577
|
||||
{
|
||||
Name = "Bearded Collie",
|
||||
Location = "Scotland",
|
||||
});
|
||||
Animals.Add(new Model5577
|
||||
{
|
||||
Name = "Boston Terrier",
|
||||
Location = "United States",
|
||||
});
|
||||
Animals.Add(new Model5577
|
||||
{
|
||||
Name = "Canadian Eskimo",
|
||||
Location = "Canada",
|
||||
});
|
||||
Animals.Add(new Model5577
|
||||
{
|
||||
Name = "Eurohound",
|
||||
Location = "Scandinavia",
|
||||
});
|
||||
Animals.Add(new Model5577
|
||||
{
|
||||
Name = "Irish Terrier",
|
||||
Location = "Ireland",
|
||||
});
|
||||
Animals.Add(new Model5577
|
||||
{
|
||||
Name = "Kerry Beagle",
|
||||
Location = "Ireland",
|
||||
});
|
||||
Animals.Add(new Model5577
|
||||
{
|
||||
Name = "Norwegian Buhund",
|
||||
Location = "Norway",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[Preserve(AllMembers = true)]
|
||||
public class Model5577
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Location { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -121,6 +121,10 @@
|
|||
<DependentUpon>Issue7048.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue5577.xaml.cs">
|
||||
<DependentUpon>Issue5577.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue6804.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue7181.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue5367.cs" />
|
||||
|
@ -1945,6 +1949,12 @@
|
|||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue5577.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue8263.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
{
|
||||
if (Values == null)
|
||||
{
|
||||
var names = new List<string>() { "VerticalList", "HorizontalList" };
|
||||
var names = new List<string>() { "VerticalList", "HorizontalList", "VerticalGrid", "HorizontalGrid" };
|
||||
Values = new StandardValuesCollection(names);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,188 @@
|
|||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Xamarin.Forms.Core.UnitTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class ItemsLayoutTypeConverterTests : BaseTestFixture
|
||||
{
|
||||
[Test]
|
||||
public void HorizontalListShouldReturnLinearItemsLayout()
|
||||
{
|
||||
var converter = new ItemsLayoutTypeConverter();
|
||||
var result = converter.ConvertFromInvariantString("HorizontalList");
|
||||
Assert.AreSame(LinearItemsLayout.Horizontal, result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void VerticalListShouldReturnLinearItemsLayout()
|
||||
{
|
||||
var converter = new ItemsLayoutTypeConverter();
|
||||
var result = converter.ConvertFromInvariantString("VerticalList");
|
||||
Assert.AreSame(LinearItemsLayout.Vertical, result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HorizontalGridShouldReturnGridItemsLayout()
|
||||
{
|
||||
var converter = new ItemsLayoutTypeConverter();
|
||||
var result = converter.ConvertFromInvariantString("HorizontalGrid");
|
||||
|
||||
Assert.IsInstanceOf<GridItemsLayout>(result);
|
||||
var gridItemsLayout = (GridItemsLayout)result;
|
||||
Assert.AreEqual(ItemsLayoutOrientation.Horizontal, gridItemsLayout.Orientation);
|
||||
Assert.AreEqual(1, gridItemsLayout.Span);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void VerticalGridShouldReturnGridItemsLayout()
|
||||
{
|
||||
var converter = new ItemsLayoutTypeConverter();
|
||||
var result = converter.ConvertFromInvariantString("VerticalGrid");
|
||||
|
||||
Assert.IsInstanceOf<GridItemsLayout>(result);
|
||||
var gridItemsLayout = (GridItemsLayout)result;
|
||||
Assert.AreEqual(ItemsLayoutOrientation.Vertical, gridItemsLayout.Orientation);
|
||||
Assert.AreEqual(1, gridItemsLayout.Span);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HorizontalGridWithSpan4ShouldReturnGridItemsLayout()
|
||||
{
|
||||
var converter = new ItemsLayoutTypeConverter();
|
||||
var result = converter.ConvertFromInvariantString("HorizontalGrid, 4");
|
||||
|
||||
Assert.IsInstanceOf<GridItemsLayout>(result);
|
||||
var gridItemsLayout = (GridItemsLayout)result;
|
||||
Assert.AreEqual(ItemsLayoutOrientation.Horizontal, gridItemsLayout.Orientation);
|
||||
Assert.AreEqual(4, gridItemsLayout.Span);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void VerticalGridWithSpan2ShouldReturnGridItemsLayout()
|
||||
{
|
||||
var converter = new ItemsLayoutTypeConverter();
|
||||
var result = converter.ConvertFromInvariantString("VerticalGrid,\t\t2");
|
||||
|
||||
Assert.IsInstanceOf<GridItemsLayout>(result);
|
||||
var gridItemsLayout = (GridItemsLayout)result;
|
||||
Assert.AreEqual(ItemsLayoutOrientation.Vertical, gridItemsLayout.Orientation);
|
||||
Assert.AreEqual(2, gridItemsLayout.Span);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HorizontalGridWithSpan987654ShouldReturnGridItemsLayout()
|
||||
{
|
||||
var converter = new ItemsLayoutTypeConverter();
|
||||
var result = converter.ConvertFromInvariantString("HorizontalGrid,98654");
|
||||
|
||||
Assert.IsInstanceOf<GridItemsLayout>(result);
|
||||
var gridItemsLayout = (GridItemsLayout)result;
|
||||
Assert.AreEqual(ItemsLayoutOrientation.Horizontal, gridItemsLayout.Orientation);
|
||||
Assert.AreEqual(98654, gridItemsLayout.Span);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void VerticalGridWithSpan1234ShouldReturnGridItemsLayout()
|
||||
{
|
||||
var converter = new ItemsLayoutTypeConverter();
|
||||
var result = converter.ConvertFromInvariantString("VerticalGrid, \t 1234");
|
||||
|
||||
Assert.IsInstanceOf<GridItemsLayout>(result);
|
||||
var gridItemsLayout = (GridItemsLayout)result;
|
||||
Assert.AreEqual(ItemsLayoutOrientation.Vertical, gridItemsLayout.Orientation);
|
||||
Assert.AreEqual(1234, gridItemsLayout.Span);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HorizontalGridWithSpan0ShouldShouldThrowArgumentException()
|
||||
{
|
||||
var converter = new ItemsLayoutTypeConverter();
|
||||
Assert.Throws<ArgumentException>(() => converter.ConvertFromInvariantString("HorizontalGrid, 0"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void VerticalGridWithSpan0ShouldShouldThrowArgumentException()
|
||||
{
|
||||
var converter = new ItemsLayoutTypeConverter();
|
||||
Assert.Throws<ArgumentException>(() => converter.ConvertFromInvariantString("VerticalGrid, 0"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HorizontalGridWithoutSpanShouldShouldThrowFormatException()
|
||||
{
|
||||
var converter = new ItemsLayoutTypeConverter();
|
||||
Assert.Throws<InvalidOperationException>(() => converter.ConvertFromInvariantString("HorizontalGrid,"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void VerticalGridWithoutSpanShouldShouldThrowFormatException()
|
||||
{
|
||||
var converter = new ItemsLayoutTypeConverter();
|
||||
Assert.Throws<InvalidOperationException>(() => converter.ConvertFromInvariantString("VerticalGrid,"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HorizontalGridWithSpanIsNotStringShouldShouldThrowFormatException()
|
||||
{
|
||||
var converter = new ItemsLayoutTypeConverter();
|
||||
Assert.Throws<FormatException>(() => converter.ConvertFromInvariantString("HorizontalGrid,test"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void VerticalGridWithSpanIs1point5ShouldShouldThrowFormatException()
|
||||
{
|
||||
var converter = new ItemsLayoutTypeConverter();
|
||||
Assert.Throws<FormatException>(() => converter.ConvertFromInvariantString("VerticalGrid, 1.5"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void VerticalGridWith2ArgumentsShouldShouldThrowFormatException()
|
||||
{
|
||||
var converter = new ItemsLayoutTypeConverter();
|
||||
Assert.Throws<FormatException>(() => converter.ConvertFromInvariantString("VerticalGrid, 2, 3"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HorizontalGridWithSemicolonShouldShouldThrowInvalidOperationException()
|
||||
{
|
||||
var converter = new ItemsLayoutTypeConverter();
|
||||
Assert.Throws<InvalidOperationException>(() => converter.ConvertFromInvariantString("HorizontalGrid; 2"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LinearItemsLayoutShouldThrowInvalidOperationException()
|
||||
{
|
||||
var converter = new ItemsLayoutTypeConverter();
|
||||
Assert.Throws<InvalidOperationException>(() => converter.ConvertFromInvariantString("LinearItemsLayout"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HorizontalListWithArgumentShouldShouldThrowInvalidOperationException()
|
||||
{
|
||||
var converter = new ItemsLayoutTypeConverter();
|
||||
Assert.Throws<InvalidOperationException>(() => converter.ConvertFromInvariantString("HorizontalList, 1"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void VerticalGridWithArgumentShouldShouldThrowInvalidOperationException()
|
||||
{
|
||||
var converter = new ItemsLayoutTypeConverter();
|
||||
Assert.Throws<InvalidOperationException>(() => converter.ConvertFromInvariantString("VerticalList, 2"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EmptyStringShouldThrowInvalidOperationException()
|
||||
{
|
||||
var converter = new ItemsLayoutTypeConverter();
|
||||
Assert.Throws<InvalidOperationException>(() => converter.ConvertFromInvariantString(string.Empty));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NullShouldThrowArgumentNullException()
|
||||
{
|
||||
var converter = new ItemsLayoutTypeConverter();
|
||||
Assert.Throws<ArgumentNullException>(() => converter.ConvertFromInvariantString(null));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -76,6 +76,7 @@
|
|||
<Compile Include="CommandSourceTests.cs" />
|
||||
<Compile Include="CommandTests.cs" />
|
||||
<Compile Include="DependencyResolutionTests.cs" />
|
||||
<Compile Include="ItemsLayoutTypeConverterTests.cs" />
|
||||
<Compile Include="MultiBindingTests.cs" />
|
||||
<Compile Include="Markup\DefaultBindablePropertiesTests.cs" />
|
||||
<Compile Include="Markup\BindableObjectExtensionsTests.cs" />
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Xamarin.Forms
|
||||
{
|
||||
|
@ -7,15 +8,46 @@ namespace Xamarin.Forms
|
|||
{
|
||||
public override object ConvertFromInvariantString(string value)
|
||||
{
|
||||
if (value == "HorizontalList")
|
||||
if (value == null)
|
||||
{
|
||||
return LinearItemsLayout.Horizontal;
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
ItemsLayoutOrientation? orientation = default(ItemsLayoutOrientation?);
|
||||
int identifierLength = 0;
|
||||
|
||||
if (value == "VerticalList")
|
||||
{
|
||||
return LinearItemsLayout.Vertical;
|
||||
}
|
||||
else if (value == "HorizontalList")
|
||||
{
|
||||
return LinearItemsLayout.Horizontal;
|
||||
}
|
||||
else if (value.StartsWith("VerticalGrid", StringComparison.Ordinal))
|
||||
{
|
||||
orientation = ItemsLayoutOrientation.Vertical;
|
||||
identifierLength = "VerticalGrid".Length;
|
||||
}
|
||||
else if (value.StartsWith("HorizontalGrid", StringComparison.Ordinal))
|
||||
{
|
||||
orientation = ItemsLayoutOrientation.Horizontal;
|
||||
identifierLength = "HorizontalGrid".Length;
|
||||
}
|
||||
|
||||
if (orientation.HasValue)
|
||||
{
|
||||
if (value.Length == identifierLength)
|
||||
{
|
||||
return new GridItemsLayout(orientation.Value);
|
||||
}
|
||||
else if (value.Length > identifierLength + 1 && value[identifierLength] == ',')
|
||||
{
|
||||
var argument = value.Substring(identifierLength + 1);
|
||||
var span = int.Parse(argument, NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite, CultureInfo.InvariantCulture);
|
||||
return new GridItemsLayout(span, orientation.Value);
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(IItemsLayout)}");
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче