* Map with ItemTemplateSelector

* Fixed Map test
This commit is contained in:
Andrei Nitescu 2019-04-01 21:12:40 +03:00 коммит произвёл Samantha Houts
Родитель 723f2de439
Коммит 740654ff56
4 изменённых файлов: 182 добавлений и 102 удалений

Просмотреть файл

@ -2,34 +2,41 @@
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:map="clr-namespace:Xamarin.Forms.Maps;assembly=Xamarin.Forms.Maps"
xmlns:local="clr-namespace:Xamarin.Forms.Controls.GalleryPages"
x:Class="Xamarin.Forms.Controls.GalleryPages.MapWithItemsSourceGallery">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<map:Map ItemsSource="{Binding Places}"
x:Name="_map">
<map:Map.ItemTemplate>
<DataTemplate>
<map:Pin Position="{Binding Position}"
Address="{Binding Address}"
Label="{Binding Description}" />
</DataTemplate>
</map:Map.ItemTemplate>
</map:Map>
<StackLayout Orientation="Horizontal"
Grid.Row="1">
<Button Text="Add"
Command="{Binding AddPlaceCommand}" />
<Button Text="Remove"
Command="{Binding RemovePlaceCommand}" />
<Button Text="Clear"
Command="{Binding ClearPlacesCommand}" />
<Button Text="Update"
Command="{Binding UpdatePlacesCommand}" />
<Button Text="Replace"
Command="{Binding ReplacePlaceCommand}" />
</StackLayout>
</Grid>
<ContentPage.Resources>
<ResourceDictionary>
<local:MapItemTemplateSelector x:Key="MapItemTemplateSelector">
<local:MapItemTemplateSelector.DataTemplate>
<DataTemplate>
<map:Pin Position="{Binding Position}"
Address="{Binding Address}"
Label="{Binding Description}" />
</DataTemplate>
</local:MapItemTemplateSelector.DataTemplate>
</local:MapItemTemplateSelector>
</ResourceDictionary>
</ContentPage.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<map:Map x:Name="_map"
ItemsSource="{Binding Places}"
ItemTemplateSelector="{StaticResource MapItemTemplateSelector}" />
<StackLayout Orientation="Horizontal"
Grid.Row="1">
<Button Text="Add"
Command="{Binding AddPlaceCommand}" />
<Button Text="Remove"
Command="{Binding RemovePlaceCommand}" />
<Button Text="Clear"
Command="{Binding ClearPlacesCommand}" />
<Button Text="Update"
Command="{Binding UpdatePlacesCommand}" />
<Button Text="Replace"
Command="{Binding ReplacePlaceCommand}" />
</StackLayout>
</Grid>
</ContentPage>

Просмотреть файл

@ -152,4 +152,14 @@ namespace Xamarin.Forms.Controls.GalleryPages
}
}
}
class MapItemTemplateSelector : DataTemplateSelector
{
public DataTemplate DataTemplate { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
return DataTemplate;
}
}
}

Просмотреть файл

@ -11,140 +11,148 @@ namespace Xamarin.Forms.Core.UnitTests
public class MapTests : BaseTestFixture
{
[Test]
public void AddPin ()
public void AddPin()
{
var map = new Map ();
var map = new Map();
var home = new Pin {
var home = new Pin
{
Label = "Home",
Position = new Position (88, 2),
Position = new Position(88, 2),
Type = PinType.Place,
Address = "123 My Place"
};
map.Pins.Add (home);
map.Pins.Add(home);
Assert.AreEqual (map.Pins.Count, 1);
Assert.AreEqual (map.Pins[0].Label, "Home");
var mall = new Pin {
Assert.AreEqual(map.Pins.Count, 1);
Assert.AreEqual(map.Pins[0].Label, "Home");
var mall = new Pin
{
Label = "Mall",
Position = new Position (-12, -67),
Position = new Position(-12, -67),
Type = PinType.Place,
Address = "123 Fun"
};
map.Pins.Add (mall);
map.Pins.Add(mall);
Assert.AreEqual (map.Pins.Count, 2);
Assert.AreEqual (map.Pins[1].Position.Latitude, -12);
Assert.AreEqual(map.Pins.Count, 2);
Assert.AreEqual(map.Pins[1].Position.Latitude, -12);
}
[Test]
public void AddPinWithoutName ()
public void AddPinWithoutName()
{
var map = new Map ();
var noNamePin = new Pin {
Position = new Position (50, 50),
var map = new Map();
var noNamePin = new Pin
{
Position = new Position(50, 50),
Type = PinType.Generic,
Address = "123 Fun"
};
var exception = Assert.Throws<ArgumentException> (() => map.Pins.Add (noNamePin));
Assert.That (exception.Message, Is.EqualTo ("Pin must have a Label to be added to a map"));
var exception = Assert.Throws<ArgumentException>(() => map.Pins.Add(noNamePin));
Assert.That(exception.Message, Is.EqualTo("Pin must have a Label to be added to a map"));
}
[Test]
public void AddPinWithoutAddress ()
public void AddPinWithoutAddress()
{
var map = new Map ();
var noAddressPin = new Pin {
Position = new Position (37.9, -20.87),
var map = new Map();
var noAddressPin = new Pin
{
Position = new Position(37.9, -20.87),
Label = "I have no address",
Type = PinType.SearchResult
};
map.Pins.Add (noAddressPin);
Assert.AreEqual (map.Pins.Count, 1);
Assert.AreEqual (map.Pins[0].Label, "I have no address");
Assert.AreEqual (map.Pins[0].Address, null);
map.Pins.Add(noAddressPin);
Assert.AreEqual(map.Pins.Count, 1);
Assert.AreEqual(map.Pins[0].Label, "I have no address");
Assert.AreEqual(map.Pins[0].Address, null);
}
[Test]
public void Constructor ()
public void Constructor()
{
var center = new Position (15.5, 176);
var span = new MapSpan (center, 1, 2);
var map = new Map (span);
var center = new Position(15.5, 176);
var span = new MapSpan(center, 1, 2);
var map = new Map(span);
Assert.AreEqual (1, map.LastMoveToRegion.LatitudeDegrees);
Assert.AreEqual (2, map.LastMoveToRegion.LongitudeDegrees);
var position = new Position (15.5, 176);
Assert.AreEqual (position, map.LastMoveToRegion.Center);
Assert.AreEqual(1, map.LastMoveToRegion.LatitudeDegrees);
Assert.AreEqual(2, map.LastMoveToRegion.LongitudeDegrees);
var position = new Position(15.5, 176);
Assert.AreEqual(position, map.LastMoveToRegion.Center);
}
[Test]
public void RemovePin ()
public void RemovePin()
{
var map = new Map ();
var genericPlace = new Pin {
var map = new Map();
var genericPlace = new Pin
{
Label = "Generic",
Position = new Position (-12, -67),
Position = new Position(-12, -67),
Type = PinType.Generic,
Address = "XXX"
};
var mall = new Pin {
var mall = new Pin
{
Label = "Mall",
Position = new Position (-29, -87),
Position = new Position(-29, -87),
Type = PinType.Place,
Address = "123 Fun"
};
map.Pins.Add (genericPlace);
Assert.AreEqual (map.Pins.Count, 1);
map.Pins.Add(genericPlace);
Assert.AreEqual(map.Pins.Count, 1);
map.Pins.Add (mall);
Assert.AreEqual (map.Pins.Count, 2);
map.Pins.Add(mall);
Assert.AreEqual(map.Pins.Count, 2);
map.Pins.Remove (genericPlace);
Assert.AreEqual (map.Pins.Count, 1);
map.Pins.Remove(genericPlace);
Assert.AreEqual(map.Pins.Count, 1);
Assert.True (map.Pins.Contains (mall));
Assert.False (map.Pins.Contains (genericPlace));
Assert.True(map.Pins.Contains(mall));
Assert.False(map.Pins.Contains(genericPlace));
}
[Test]
public void VisibleRegion ()
public void VisibleRegion()
{
var map = new Map (new MapSpan (new Position (), 0, 0));
map.MoveToRegion (new MapSpan (new Position (1, 2), 3, 4));
Assert.AreEqual (null, map.VisibleRegion);
var map = new Map(new MapSpan(new Position(), 0, 0));
map.MoveToRegion(new MapSpan(new Position(1, 2), 3, 4));
Assert.AreEqual(null, map.VisibleRegion);
bool signaled = false;
MessagingCenter.Subscribe<Map, MapSpan> (this, "MapMoveToRegion", (s, a) => {
MessagingCenter.Subscribe<Map, MapSpan>(this, "MapMoveToRegion", (s, a) =>
{
signaled = true;
map.SetVisibleRegion(a);
}, map);
map.MoveToRegion (new MapSpan (new Position (1, 2), 3, 4));
Assert.AreEqual (new MapSpan (new Position (1, 2), 3, 4), map.LastMoveToRegion);
Assert.True (signaled);
map.MoveToRegion(new MapSpan(new Position(1, 2), 3, 4));
Assert.AreEqual(new MapSpan(new Position(1, 2), 3, 4), map.LastMoveToRegion);
Assert.True(signaled);
}
[Test]
public void VisibleRegionDoubleSet ()
public void VisibleRegionDoubleSet()
{
var map = new Map ();
var map = new Map();
bool signaled = false;
map.PropertyChanged += (sender, args) => {
map.PropertyChanged += (sender, args) =>
{
if (args.PropertyName == "VisibleRegion")
signaled = true;
};
map.SetVisibleRegion(map.VisibleRegion);
Assert.False (signaled);
Assert.False(signaled);
}
[Test]
@ -292,12 +300,45 @@ namespace Xamarin.Forms.Core.UnitTests
map.ItemTemplate = GetItemTemplate("Address 2");
Assert.IsTrue(IsMapWithItemsSource(itemsSource, map));
foreach(Pin pin in map.Pins)
foreach (Pin pin in map.Pins)
{
Assert.IsTrue(pin.Address == "Address 2");
}
}
[Test]
public void ItemTemplateSelectorIsSet()
{
var map = new Map();
var itemsSource = new ObservableCollection<int>(Enumerable.Range(0, 3));
map.ItemsSource = itemsSource;
map.ItemTemplateSelector = new TestDataTemplateSelector("Address 2");
Assert.IsTrue(IsMapWithItemsSource(itemsSource, map));
foreach (Pin pin in map.Pins)
{
Assert.IsTrue(pin.Address == "Address 2");
}
}
[Test]
public void ItemTemplateTakesPrecendenceOverItemTemplateSelector()
{
var map = new Map();
var itemsSource = new ObservableCollection<int>(Enumerable.Range(0, 10));
map.ItemsSource = itemsSource;
map.ItemTemplate = GetItemTemplate("Address 1");
map.ItemTemplateSelector = new TestDataTemplateSelector("Address 2");
Assert.IsTrue(IsMapWithItemsSource(itemsSource, map));
foreach (Pin pin in map.Pins)
{
Assert.AreEqual(pin.Address, "Address 1");
}
}
[Test]
public void ItemsSourceTakePrecendenceOverPins()
{
@ -395,16 +436,16 @@ namespace Xamarin.Forms.Core.UnitTests
return true;
}
if (map.ItemTemplate == null)
if (map.ItemTemplate == null && map.ItemTemplateSelector == null)
{
// If ItemsSource is set but ItemTemplate is not, there should not be any Pins
// If ItemsSource is set but neither ItemTemplate and ItemTemplate is, there should not be any Pins
return !map.Pins.Any();
}
int i = 0;
foreach (object item in itemsSource)
{
// Pins collection order are not tracked, so just make sure a Pin for item exists
// Pins collection order is not tracked, so just make sure a Pin for item exists
if (!map.Pins.Any(p => Equals(item, p.BindingContext)))
{
return false;
@ -426,14 +467,19 @@ namespace Xamarin.Forms.Core.UnitTests
});
}
static DataTemplateSelector GetDataTemplateSelector()
static DataTemplateSelector GetDataTemplateSelector(string address = null)
{
return new TestDataTemplateSelector();
return new TestDataTemplateSelector(address);
}
class TestDataTemplateSelector : DataTemplateSelector
{
readonly DataTemplate dt = GetItemTemplate();
readonly DataTemplate dt;
public TestDataTemplateSelector(string address = null)
{
dt = GetItemTemplate(address);
}
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{

Просмотреть файл

@ -24,6 +24,9 @@ namespace Xamarin.Forms.Maps
public static readonly BindableProperty ItemTemplateProperty = BindableProperty.Create(nameof(ItemTemplate), typeof(DataTemplate), typeof(Map), default(DataTemplate),
propertyChanged: (b, o, n) => ((Map)b).OnItemTemplatePropertyChanged((DataTemplate)o, (DataTemplate)n));
public static readonly BindableProperty ItemTemplateSelectorProperty = BindableProperty.Create(nameof(ItemTemplateSelector), typeof(DataTemplateSelector), typeof(Map), default(DataTemplateSelector),
propertyChanged: (b, o, n) => ((Map)b).OnItemTemplateSelectorPropertyChanged());
readonly ObservableCollection<Pin> _pins = new ObservableCollection<Pin>();
MapSpan _visibleRegion;
@ -82,6 +85,12 @@ namespace Xamarin.Forms.Maps
set { SetValue(ItemTemplateProperty, value); }
}
public DataTemplateSelector ItemTemplateSelector
{
get { return (DataTemplateSelector)GetValue(ItemTemplateSelectorProperty); }
set { SetValue(ItemTemplateSelectorProperty, value); }
}
[EditorBrowsable(EditorBrowsableState.Never)]
public void SetVisibleRegion(MapSpan value) => VisibleRegion = value;
public MapSpan VisibleRegion
@ -153,6 +162,12 @@ namespace Xamarin.Forms.Maps
CreatePinItems();
}
void OnItemTemplateSelectorPropertyChanged()
{
_pins.Clear();
CreatePinItems();
}
void OnItemsSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
@ -190,7 +205,7 @@ namespace Xamarin.Forms.Maps
void CreatePinItems()
{
if (ItemsSource == null || ItemTemplate == null)
if (ItemsSource == null || (ItemTemplate == null && ItemTemplateSelector == null))
{
return;
}
@ -203,12 +218,14 @@ namespace Xamarin.Forms.Maps
void CreatePin(object newItem)
{
if (ItemTemplate == null)
{
return;
}
DataTemplate itemTemplate = ItemTemplate;
if (itemTemplate == null)
itemTemplate = ItemTemplateSelector?.SelectTemplate(newItem, this);
var pin = (Pin)ItemTemplate.CreateContent();
if (itemTemplate == null)
return;
var pin = (Pin)itemTemplate.CreateContent();
pin.BindingContext = newItem;
_pins.Add(pin);
}