Merge 4.3.0 into master
This commit is contained in:
Коммит
fba3e9337b
|
@ -51,11 +51,7 @@ namespace Xamarin.Forms.Platform
|
|||
[RenderWith (typeof (ButtonRenderer))]
|
||||
internal class _ButtonRenderer { }
|
||||
|
||||
#if __ANDROID__
|
||||
[RenderWith(typeof(ImageButtonRenderer))]
|
||||
#elif !TIZEN4_0
|
||||
[RenderWith(typeof(ImageButtonRenderer))]
|
||||
#endif
|
||||
internal class _ImageButtonRenderer { }
|
||||
|
||||
[RenderWith (typeof (TableViewRenderer))]
|
||||
|
@ -63,12 +59,18 @@ namespace Xamarin.Forms.Platform
|
|||
|
||||
[RenderWith (typeof (ListViewRenderer))]
|
||||
internal class _ListViewRenderer { }
|
||||
#if !TIZEN4_0
|
||||
#if !TIZEN4_0
|
||||
[RenderWith (typeof (CollectionViewRenderer))]
|
||||
internal class _CollectionViewRenderer { }
|
||||
[RenderWith (typeof (CarouselViewRenderer))]
|
||||
internal class _CarouselViewRenderer { }
|
||||
#else
|
||||
[RenderWith (typeof (ItemsViewRenderer))]
|
||||
#endif
|
||||
internal class _CollectionViewRenderer { }
|
||||
|
||||
#if !TIZEN4_0
|
||||
[RenderWith (typeof (CarouselViewRenderer))]
|
||||
#endif
|
||||
internal class _CarouselViewRenderer { }
|
||||
|
||||
[RenderWith (typeof (SliderRenderer))]
|
||||
internal class _SliderRenderer { }
|
||||
|
||||
|
|
|
@ -495,7 +495,22 @@ namespace Xamarin.Forms.Build.Tasks
|
|||
if (indexArg != null) {
|
||||
var defaultMemberAttribute = previousPartTypeRef.GetCustomAttribute(module, ("mscorlib", "System.Reflection", "DefaultMemberAttribute"));
|
||||
var indexerName = defaultMemberAttribute?.ConstructorArguments?.FirstOrDefault().Value as string ?? "Item";
|
||||
var indexer = previousPartTypeRef.GetProperty(pd => pd.Name == indexerName && pd.GetMethod != null && pd.GetMethod.IsPublic, out var indexerDeclTypeRef);
|
||||
PropertyDefinition indexer = null;
|
||||
TypeReference indexerDeclTypeRef = null;
|
||||
if (int.TryParse(indexArg, out _))
|
||||
indexer = previousPartTypeRef.GetProperty(pd => pd.Name == indexerName
|
||||
&& pd.GetMethod != null
|
||||
&& TypeRefComparer.Default.Equals(pd.GetMethod.Parameters[0].ParameterType, module.ImportReference(("mscorlib", "System", "Int32")))
|
||||
&& pd.GetMethod.IsPublic, out indexerDeclTypeRef);
|
||||
indexer = indexer ?? previousPartTypeRef.GetProperty(pd => pd.Name == indexerName
|
||||
&& pd.GetMethod != null
|
||||
&& TypeRefComparer.Default.Equals(pd.GetMethod.Parameters[0].ParameterType, module.ImportReference(("mscorlib", "System", "String")))
|
||||
&& pd.GetMethod.IsPublic, out indexerDeclTypeRef);
|
||||
indexer = indexer ?? previousPartTypeRef.GetProperty(pd => pd.Name == indexerName
|
||||
&& pd.GetMethod != null
|
||||
&& TypeRefComparer.Default.Equals(pd.GetMethod.Parameters[0].ParameterType, module.ImportReference(("mscorlib", "System", "String")))
|
||||
&& pd.GetMethod.IsPublic, out indexerDeclTypeRef);
|
||||
|
||||
properties.Add((indexer, indexerDeclTypeRef, indexArg));
|
||||
var indexType = indexer.GetMethod.Parameters[0].ParameterType.ResolveGenericParameters(indexerDeclTypeRef);
|
||||
if (!TypeRefComparer.Default.Equals(indexType, module.TypeSystem.String) && !TypeRefComparer.Default.Equals(indexType, module.TypeSystem.Int32))
|
||||
|
|
|
@ -11,11 +11,9 @@ namespace Xamarin.Forms.Build.Tasks
|
|||
{
|
||||
static string GetAssembly(TypeReference typeRef)
|
||||
{
|
||||
var md = typeRef.Scope as ModuleDefinition;
|
||||
if (md != null)
|
||||
if (typeRef.Scope is ModuleDefinition md)
|
||||
return md.Assembly.FullName;
|
||||
var anr = typeRef.Scope as AssemblyNameReference;
|
||||
if (anr != null)
|
||||
if (typeRef.Scope is AssemblyNameReference anr)
|
||||
return anr.FullName;
|
||||
throw new ArgumentOutOfRangeException(nameof(typeRef));
|
||||
}
|
||||
|
|
|
@ -42,10 +42,11 @@
|
|||
<WarningLevel>4</WarningLevel>
|
||||
<AndroidLinkMode>None</AndroidLinkMode>
|
||||
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
||||
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
|
||||
<AndroidSupportedAbis>armeabi-v7a;x86</AndroidSupportedAbis>
|
||||
<Debugger>Xamarin</Debugger>
|
||||
<DevInstrumentationEnabled>True</DevInstrumentationEnabled>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<AndroidSupportedAbis>armeabi-v7a</AndroidSupportedAbis>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<Optimize>true</Optimize>
|
||||
|
@ -55,9 +56,15 @@
|
|||
<WarningLevel>4</WarningLevel>
|
||||
<AndroidLinkMode>SdkOnly</AndroidLinkMode>
|
||||
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
|
||||
<AndroidSupportedAbis>armeabi-v7a,x86</AndroidSupportedAbis>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(TF_BUILD)' == 'true' OR '$(CI)' == 'true'">
|
||||
<AndroidLinkMode>Full</AndroidLinkMode>
|
||||
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
|
||||
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
|
||||
<AndroidSupportedAbis>armeabi-v7a,x86</AndroidSupportedAbis>
|
||||
<AndroidEnableMultiDex>true</AndroidEnableMultiDex>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(CI)' == 'True' ">
|
||||
<AndroidLinkMode>Full</AndroidLinkMode>
|
||||
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
|
||||
|
@ -385,4 +392,4 @@
|
|||
</CreateItem>
|
||||
<Copy SourceFiles="@(MapsKey)" DestinationFiles="Properties\MapsKey.cs" Condition="!Exists('Properties\MapsKey.cs')" />
|
||||
</Target>
|
||||
</Project>
|
||||
</Project>
|
|
@ -0,0 +1,41 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Xamarin.Forms.CustomAttributes;
|
||||
using Xamarin.Forms.Internals;
|
||||
|
||||
#if UITEST
|
||||
using Xamarin.Forms.Core.UITests;
|
||||
using Xamarin.UITest;
|
||||
using NUnit.Framework;
|
||||
#endif
|
||||
|
||||
namespace Xamarin.Forms.Controls.Issues
|
||||
{
|
||||
#if UITEST
|
||||
[Category(UITestCategories.CollectionView)]
|
||||
#endif
|
||||
[Preserve(AllMembers = true)]
|
||||
[Issue(IssueTracker.Github, 6963, "[Bug] CollectionView multiple pre-selection throws ArgumentOutOfRangeException when SelectedItems is bound to an ObservableCollection initialized inside the constructor.",
|
||||
PlatformAffected.iOS | PlatformAffected.UWP)]
|
||||
public class Issue6963 : TestNavigationPage
|
||||
{
|
||||
protected override void Init()
|
||||
{
|
||||
#if APP
|
||||
FlagTestHelpers.SetCollectionViewTestFlag();
|
||||
|
||||
PushAsync(new GalleryPages.CollectionViewGalleries.SelectionGalleries.SelectionSynchronization());
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UITEST
|
||||
[Test]
|
||||
public void SelectedItemsNotInSourceDoesNotCrash()
|
||||
{
|
||||
// If this page didn't crash, then we're good
|
||||
RunningApp.WaitForElement("FirstLabel");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Xamarin.Forms.CustomAttributes;
|
||||
using Xamarin.Forms.Internals;
|
||||
|
||||
#if UITEST
|
||||
using NUnit.Framework;
|
||||
using Xamarin.Forms.Core.UITests;
|
||||
using System.Linq;
|
||||
#endif
|
||||
|
||||
namespace Xamarin.Forms.Controls.Issues
|
||||
{
|
||||
#if UITEST
|
||||
[Category(UITestCategories.CollectionView)]
|
||||
#endif
|
||||
[Preserve(AllMembers = true)]
|
||||
[Issue(IssueTracker.Github, 7742, "(iOS) Changing ItemTemplate does not work as expected", PlatformAffected.iOS)]
|
||||
public class Issue7742 : TestContentPage
|
||||
{
|
||||
CollectionView _collectionView;
|
||||
|
||||
public Issue7742()
|
||||
{
|
||||
Title = "Issue 7742";
|
||||
}
|
||||
|
||||
protected override void Init()
|
||||
{
|
||||
var instructions = new Label
|
||||
{
|
||||
Text = "Click the Button. If all cells render correctly, then the test passes."
|
||||
};
|
||||
|
||||
var button = new Button
|
||||
{
|
||||
Text = "Change ItemTemplate",
|
||||
AutomationId = "TemplateBtn"
|
||||
};
|
||||
|
||||
button.Clicked += OnButton1Clicked;
|
||||
|
||||
_collectionView = new CollectionView
|
||||
{
|
||||
BackgroundColor = Color.LightGreen,
|
||||
SelectionMode = SelectionMode.None,
|
||||
HeightRequest = 500
|
||||
};
|
||||
|
||||
var lines = new List<Issue7742Model>();
|
||||
|
||||
for (int i = 0; i < 30; i++)
|
||||
{
|
||||
lines.Add(new Issue7742Model() { Text = $"Item {i}" });
|
||||
}
|
||||
|
||||
_collectionView.ItemsSource = lines;
|
||||
|
||||
var stack = new StackLayout();
|
||||
|
||||
stack.Children.Add(instructions);
|
||||
stack.Children.Add(button);
|
||||
stack.Children.Add(_collectionView);
|
||||
|
||||
Content = stack;
|
||||
}
|
||||
|
||||
void OnButton1Clicked(object sender, EventArgs e)
|
||||
{
|
||||
_collectionView.ItemTemplate = CreateDataGridTemplate(2);
|
||||
}
|
||||
|
||||
DataTemplate CreateDataGridTemplate(int columns)
|
||||
{
|
||||
var template = new DataTemplate(() =>
|
||||
{
|
||||
var grid = new Grid() { Padding = new Thickness(0), Margin = 0, RowSpacing = 0, ColumnSpacing = 0 };
|
||||
|
||||
grid.RowDefinitions.Clear();
|
||||
grid.ColumnDefinitions.Clear();
|
||||
grid.Children.Clear();
|
||||
grid.RowDefinitions.Add(new RowDefinition() { Height = 40 });
|
||||
grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) });
|
||||
Label cell;
|
||||
cell = new Label() { };
|
||||
cell.SetBinding(Label.TextProperty, "Text");
|
||||
cell.FontSize = 20;
|
||||
cell.FontAttributes = FontAttributes.Bold;
|
||||
cell.BackgroundColor = Color.LightBlue;
|
||||
grid.Children.Add(cell, 0, 0);
|
||||
|
||||
for (int i = 0; i < columns; i++)
|
||||
{
|
||||
grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) });
|
||||
cell = new Label() { };
|
||||
cell.Text = "Col:" + i;
|
||||
cell.FontAttributes = FontAttributes.Bold;
|
||||
cell.BackgroundColor = Color.Beige;
|
||||
grid.Children.Add(cell, i + 1, 0);
|
||||
}
|
||||
return grid;
|
||||
});
|
||||
return template;
|
||||
}
|
||||
}
|
||||
|
||||
[Preserve(AllMembers = true)]
|
||||
public class Issue7742Model
|
||||
{
|
||||
public string Text { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
<?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:d="http://xamarin.com/schemas/2014/forms/design"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:controls="clr-namespace:Xamarin.Forms.Controls"
|
||||
mc:Ignorable="d"
|
||||
x:Class="Xamarin.Forms.Controls.Issues.Issue7758">
|
||||
<ContentPage.Resources>
|
||||
<ResourceDictionary>
|
||||
<Style TargetType="StackLayout" x:Key="StackLayoutStyle">
|
||||
<Setter Property="Orientation" Value="Vertical"/>
|
||||
<Setter Property="HorizontalOptions" Value="Center"/>
|
||||
<Setter Property="VerticalOptions" Value="Center"/>
|
||||
<Setter Property="Padding" Value="20, 0"/>
|
||||
<Setter Property="Spacing" Value="10"/>
|
||||
<Setter Property="BackgroundColor" Value="Wheat"/>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
</ContentPage.Resources>
|
||||
<Grid RowSpacing="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid Grid.Row="0" BackgroundColor="Black" Padding="10">
|
||||
<Label Text="If the red line is not between Item 3 and Item 4, the test has failed. Change device orientation to landscape. If the red line is not between Item 3 and Item 4, the test has failed. If there is a visible white background during orientation change, the test has failed." TextColor="White"/>
|
||||
</Grid>
|
||||
|
||||
<CollectionView Grid.Row="1">
|
||||
<CollectionView.EmptyView>
|
||||
<ContentView HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" BackgroundColor="Beige">
|
||||
<StackLayout Style="{x:StaticResource StackLayoutStyle}">
|
||||
<Label Text="Text1" HorizontalTextAlignment="Center" FontAttributes="Bold" FontSize="14.5"/>
|
||||
<Label Text="Text2" HorizontalTextAlignment="Center" TextColor="#636571" FontSize="14.5"/>
|
||||
<Label Text="Text3" HorizontalTextAlignment="Center" FontAttributes="Bold" FontSize="14.5"/>
|
||||
<Label Text="Text4" HorizontalTextAlignment="Center" TextColor="#636571" FontSize="14.5"/>
|
||||
<Label Text="Text5" HorizontalTextAlignment="Center" FontAttributes="Bold" FontSize="14.5"/>
|
||||
<Label Text="Text6" HorizontalTextAlignment="Center" TextColor="#636571" FontSize="14.5"/>
|
||||
</StackLayout>
|
||||
</ContentView>
|
||||
</CollectionView.EmptyView>
|
||||
</CollectionView>
|
||||
|
||||
<Grid Grid.Row="2" BackgroundColor="Black" HeightRequest="50"/>
|
||||
|
||||
<Grid Grid.Row="1" BackgroundColor="Red" HeightRequest="5" VerticalOptions="Center"/>
|
||||
</Grid>
|
||||
</controls:TestContentPage>
|
|
@ -0,0 +1,25 @@
|
|||
using System.Collections.Generic;
|
||||
using Xamarin.Forms.CustomAttributes;
|
||||
using Xamarin.Forms.Internals;
|
||||
|
||||
namespace Xamarin.Forms.Controls.Issues
|
||||
{
|
||||
[Preserve(AllMembers = true)]
|
||||
[Issue(IssueTracker.Github, 7758, "[iOS] EmptyView is not rendered in screen center", PlatformAffected.iOS)]
|
||||
public partial class Issue7758 : TestContentPage
|
||||
{
|
||||
public Issue7758()
|
||||
{
|
||||
#if APP
|
||||
Device.SetFlags(new List<string> { CollectionView.CollectionViewExperimental });
|
||||
|
||||
InitializeComponent();
|
||||
#endif
|
||||
}
|
||||
|
||||
protected override void Init()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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:d="http://xamarin.com/schemas/2014/forms/design"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:controls="clr-namespace:Xamarin.Forms.Controls"
|
||||
mc:Ignorable="d"
|
||||
x:Class="Xamarin.Forms.Controls.Issues.Issue7789">
|
||||
<ContentPage.Content>
|
||||
<StackLayout Margin="10">
|
||||
<Label
|
||||
Text="If the CarouselView below is rendered without problems, the test passes."/>
|
||||
<CarouselView
|
||||
BackgroundColor="GreenYellow">
|
||||
<CarouselView.ItemsSource>
|
||||
<x:Array Type="{x:Type x:String}">
|
||||
<x:String>Baboon</x:String>
|
||||
<x:String>Capuchin Monkey</x:String>
|
||||
<x:String>Blue Monkey</x:String>
|
||||
<x:String>Squirrel Monkey</x:String>
|
||||
<x:String>Golden Lion Tamarin</x:String>
|
||||
<x:String>Howler Monkey</x:String>
|
||||
<x:String>Japanese Macaque</x:String>
|
||||
<x:String>Mandrill</x:String>
|
||||
<x:String>Proboscis Monkey</x:String>
|
||||
<x:String>Red-shanked Douc</x:String>
|
||||
<x:String>Gray-shanked Douc</x:String>
|
||||
<x:String>Golden Snub-nosed Monkey</x:String>
|
||||
<x:String>Black Snub-nosed Monkey</x:String>
|
||||
<x:String>Tonkin Snub-nosed Monkey</x:String>
|
||||
<x:String>Thomas's Langur</x:String>
|
||||
<x:String>Purple-faced Langur</x:String>
|
||||
<x:String>Gelada</x:String>
|
||||
</x:Array>
|
||||
</CarouselView.ItemsSource>
|
||||
</CarouselView>
|
||||
</StackLayout>
|
||||
</ContentPage.Content>
|
||||
</controls:TestContentPage>
|
|
@ -0,0 +1,38 @@
|
|||
using Xamarin.Forms.CustomAttributes;
|
||||
using Xamarin.Forms.Internals;
|
||||
using Xamarin.Forms.Xaml;
|
||||
using System.Collections.Generic;
|
||||
|
||||
#if UITEST
|
||||
using Xamarin.UITest;
|
||||
using Xamarin.UITest.Queries;
|
||||
using NUnit.Framework;
|
||||
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, 7789, "CarouselView crash when displaying strings", PlatformAffected.iOS)]
|
||||
public partial class Issue7789 : TestContentPage
|
||||
{
|
||||
public Issue7789()
|
||||
{
|
||||
#if APP
|
||||
Device.SetFlags(new List<string> { CollectionView.CollectionViewExperimental });
|
||||
InitializeComponent();
|
||||
#endif
|
||||
}
|
||||
|
||||
protected override void Init()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<?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:d="http://xamarin.com/schemas/2014/forms/design"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:controls="clr-namespace:Xamarin.Forms.Controls"
|
||||
mc:Ignorable="d"
|
||||
x:Class="Xamarin.Forms.Controls.Issues.Issue7792"
|
||||
Title="Issue 7792" >
|
||||
<ContentPage.Content>
|
||||
<StackLayout>
|
||||
<Label
|
||||
Text="If you can see the text of the Carousel EmptyView below, the test passes."/>
|
||||
<CarouselView
|
||||
BackgroundColor="Yellow"
|
||||
ItemsSource="{Binding IteEmptyItemsms}"
|
||||
EmptyView="No items to display (EmptyView)." />
|
||||
</StackLayout>
|
||||
</ContentPage.Content>
|
||||
</controls:TestContentPage>
|
|
@ -0,0 +1,45 @@
|
|||
using System.Collections.Generic;
|
||||
using Xamarin.Forms.CustomAttributes;
|
||||
using Xamarin.Forms.Internals;
|
||||
using System.Windows.Input;
|
||||
|
||||
#if UITEST
|
||||
using Xamarin.UITest;
|
||||
using NUnit.Framework;
|
||||
using Xamarin.UITest.iOS;
|
||||
#endif
|
||||
|
||||
namespace Xamarin.Forms.Controls.Issues
|
||||
{
|
||||
[Preserve(AllMembers = true)]
|
||||
[Issue(IssueTracker.Github, 7792, "(Android) CarouselView string EmptyView not displayed", PlatformAffected.Android)]
|
||||
public partial class Issue7792 : TestContentPage
|
||||
{
|
||||
public Issue7792()
|
||||
{
|
||||
#if APP
|
||||
Device.SetFlags(new List<string> { CollectionView.CollectionViewExperimental });
|
||||
InitializeComponent();
|
||||
#endif
|
||||
BindingContext = new Issue7792ViewModel();
|
||||
}
|
||||
|
||||
protected override void Init()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[Preserve(AllMembers = true)]
|
||||
public class Issue7792Model
|
||||
{
|
||||
public string Text1 { get; set; }
|
||||
public string Text2 { get; set; }
|
||||
}
|
||||
|
||||
[Preserve(AllMembers = true)]
|
||||
public class Issue7792ViewModel : BindableObject
|
||||
{
|
||||
public IList<Issue7792Model> EmptyItems { get; private set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
<?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:d="http://xamarin.com/schemas/2014/forms/design"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:controls="clr-namespace:Xamarin.Forms.Controls"
|
||||
xmlns:local="clr-namespace:Xamarin.Forms.Controls.Issues"
|
||||
mc:Ignorable="d"
|
||||
x:Class="Xamarin.Forms.Controls.Issues.Issue7817">
|
||||
<ContentPage.Content>
|
||||
<Grid
|
||||
Margin="12">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid
|
||||
Grid.Row="0"
|
||||
BackgroundColor="Yellow">
|
||||
<Label
|
||||
LineBreakMode="WordWrap"
|
||||
Text="Change ItemsUpdatingScrollMode by selecting KeepLastItemInView in the Picker and verify that the behavior changes. The CarouselView must move the scroll to the latest item added."/>
|
||||
</Grid>
|
||||
<StackLayout
|
||||
Grid.Row="1"
|
||||
Orientation="Horizontal"
|
||||
HorizontalOptions="Center">
|
||||
<Label
|
||||
Text="UpdatingScrollMode: "
|
||||
VerticalTextAlignment="Center" />
|
||||
<local:EnumPicker x:Name="enumPicker"
|
||||
EnumType="{x:Type ItemsUpdatingScrollMode}"
|
||||
SelectedIndex="0"
|
||||
SelectedIndexChanged="OnItemsUpdatingScrollModeChanged" />
|
||||
</StackLayout>
|
||||
<CarouselView
|
||||
Grid.Row="2"
|
||||
x:Name="carouselView"
|
||||
ItemsSource="{Binding Monkeys}">
|
||||
<CarouselView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackLayout>
|
||||
<Frame HasShadow="True"
|
||||
BorderColor="DarkGray"
|
||||
CornerRadius="5"
|
||||
Margin="20"
|
||||
HeightRequest="300"
|
||||
HorizontalOptions="Center"
|
||||
VerticalOptions="CenterAndExpand">
|
||||
<StackLayout>
|
||||
<Label Text="{Binding Name}"
|
||||
FontAttributes="Bold"
|
||||
FontSize="Large"
|
||||
HorizontalOptions="Center"
|
||||
VerticalOptions="Center" />
|
||||
<Image Source="{Binding ImageUrl}"
|
||||
Aspect="AspectFill"
|
||||
HeightRequest="150"
|
||||
WidthRequest="150"
|
||||
HorizontalOptions="Center" />
|
||||
<Label Text="{Binding Location}"
|
||||
HorizontalOptions="Center" />
|
||||
<Label Text="{Binding Details}"
|
||||
FontAttributes="Italic"
|
||||
HorizontalOptions="Center"
|
||||
MaxLines="5"
|
||||
LineBreakMode="TailTruncation" />
|
||||
</StackLayout>
|
||||
</Frame>
|
||||
</StackLayout>
|
||||
</DataTemplate>
|
||||
</CarouselView.ItemTemplate>
|
||||
</CarouselView>
|
||||
</Grid>
|
||||
</ContentPage.Content>
|
||||
</controls:TestContentPage>
|
|
@ -0,0 +1,162 @@
|
|||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Xamarin.Forms.CustomAttributes;
|
||||
using Xamarin.Forms.Internals;
|
||||
using Xamarin.Forms.Xaml;
|
||||
using System.Reflection;
|
||||
|
||||
#if UITEST
|
||||
using Xamarin.UITest;
|
||||
using Xamarin.UITest.Queries;
|
||||
using NUnit.Framework;
|
||||
using Xamarin.Forms.Core.UITests;
|
||||
#endif
|
||||
|
||||
namespace Xamarin.Forms.Controls.Issues
|
||||
{
|
||||
#if UITEST
|
||||
[Category(UITestCategories.CarouselView)]
|
||||
#endif
|
||||
#if APP
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
#endif
|
||||
[Preserve(AllMembers = true)]
|
||||
[Issue(IssueTracker.Github, 7817, "[Android/iOS] Changing ItemsUpdatingScrollMode has no effect on CarouselView")]
|
||||
public partial class Issue7817 : TestContentPage
|
||||
{
|
||||
public Issue7817()
|
||||
{
|
||||
#if APP
|
||||
Device.SetFlags(new List<string> { CollectionView.CollectionViewExperimental });
|
||||
Title = "Issue 7817";
|
||||
InitializeComponent();
|
||||
#endif
|
||||
}
|
||||
|
||||
protected override async void Init()
|
||||
{
|
||||
BindingContext = new Issue7817ViewModel();
|
||||
await ((Issue7817ViewModel)BindingContext).CreateCollectionAsync();
|
||||
}
|
||||
|
||||
void OnItemsUpdatingScrollModeChanged(object sender, EventArgs e)
|
||||
{
|
||||
#if APP
|
||||
carouselView.ItemsUpdatingScrollMode = (ItemsUpdatingScrollMode)(sender as EnumPicker).SelectedItem;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
[Preserve(AllMembers = true)]
|
||||
public class EnumPicker : Picker
|
||||
{
|
||||
public static readonly BindableProperty EnumTypeProperty = BindableProperty.Create(nameof(EnumType), typeof(Type), typeof(EnumPicker),
|
||||
propertyChanged: (bindable, oldValue, newValue) =>
|
||||
{
|
||||
var picker = (EnumPicker)bindable;
|
||||
|
||||
if (oldValue != null)
|
||||
{
|
||||
picker.ItemsSource = null;
|
||||
}
|
||||
if (newValue != null)
|
||||
{
|
||||
if (!((Type)newValue).GetTypeInfo().IsEnum)
|
||||
throw new ArgumentException("EnumPicker: EnumType property must be enumeration type");
|
||||
|
||||
picker.ItemsSource = Enum.GetValues((Type)newValue);
|
||||
}
|
||||
});
|
||||
|
||||
public Type EnumType
|
||||
{
|
||||
set => SetValue(EnumTypeProperty, value);
|
||||
get => (Type)GetValue(EnumTypeProperty);
|
||||
}
|
||||
}
|
||||
|
||||
[Preserve(AllMembers = true)]
|
||||
public class Issue7817Model
|
||||
{
|
||||
public int Index { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Location { get; set; }
|
||||
public string Details { get; set; }
|
||||
public string ImageUrl { get; set; }
|
||||
}
|
||||
|
||||
[Preserve(AllMembers = true)]
|
||||
public class Issue7817ViewModel : BindableObject
|
||||
{
|
||||
const int AddItemDelay = 2000;
|
||||
|
||||
public ObservableCollection<Issue7817Model> Monkeys { get; private set; } = new ObservableCollection<Issue7817Model>();
|
||||
|
||||
public async Task CreateCollectionAsync()
|
||||
{
|
||||
Monkeys.Add(new Issue7817Model
|
||||
{
|
||||
Index = 0,
|
||||
Name = "Baboon",
|
||||
Location = "Africa & Asia",
|
||||
Details = "Baboons are African and Arabian Old World monkeys belonging to the genus Papio, part of the subfamily Cercopithecinae.",
|
||||
ImageUrl = "http://upload.wikimedia.org/wikipedia/commons/thumb/f/fc/Papio_anubis_%28Serengeti%2C_2009%29.jpg/200px-Papio_anubis_%28Serengeti%2C_2009%29.jpg"
|
||||
});
|
||||
|
||||
await Task.Delay(AddItemDelay);
|
||||
|
||||
Monkeys.Add(new Issue7817Model
|
||||
{
|
||||
Index = 1,
|
||||
Name = "Capuchin Monkey",
|
||||
Location = "Central & South America",
|
||||
Details = "The capuchin monkeys are New World monkeys of the subfamily Cebinae. Prior to 2011, the subfamily contained only a single genus, Cebus.",
|
||||
ImageUrl = "http://upload.wikimedia.org/wikipedia/commons/thumb/4/40/Capuchin_Costa_Rica.jpg/200px-Capuchin_Costa_Rica.jpg"
|
||||
});
|
||||
|
||||
await Task.Delay(AddItemDelay);
|
||||
|
||||
Monkeys.Add(new Issue7817Model
|
||||
{
|
||||
Index = 2,
|
||||
Name = "Blue Monkey",
|
||||
Location = "Central and East Africa",
|
||||
Details = "The blue monkey or diademed monkey is a species of Old World monkey native to Central and East Africa, ranging from the upper Congo River basin east to the East African Rift and south to northern Angola and Zambia",
|
||||
ImageUrl = "http://upload.wikimedia.org/wikipedia/commons/thumb/8/83/BlueMonkey.jpg/220px-BlueMonkey.jpg"
|
||||
});
|
||||
|
||||
Monkeys.Add(new Issue7817Model
|
||||
{
|
||||
Index = 3,
|
||||
Name = "Thomas's Langur",
|
||||
Location = "Indonesia",
|
||||
Details = "Thomas's langur is a species of primate in the family Cercopithecidae. It is endemic to North Sumatra, Indonesia. Its natural habitat is subtropical or tropical dry forests. It is threatened by habitat loss. Its native names are reungkah in Acehnese and kedih in Alas.",
|
||||
ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/3/31/Thomas%27s_langur_Presbytis_thomasi.jpg/142px-Thomas%27s_langur_Presbytis_thomasi.jpg"
|
||||
});
|
||||
|
||||
await Task.Delay(AddItemDelay);
|
||||
|
||||
Monkeys.Add(new Issue7817Model
|
||||
{
|
||||
Index = 4,
|
||||
Name = "Purple-faced Langur",
|
||||
Location = "Sri Lanka",
|
||||
Details = "The purple-faced langur, also known as the purple-faced leaf monkey, is a species of Old World monkey that is endemic to Sri Lanka. The animal is a long-tailed arboreal species, identified by a mostly brown appearance, dark face (with paler lower face) and a very shy nature. The species was once highly prevalent, found in suburban Colombo and the \"wet zone\" villages (areas with high temperatures and high humidity throughout the year, whilst rain deluges occur during the monsoon seasons), but rapid urbanization has led to a significant decrease in the population level of the monkeys.",
|
||||
ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/0/02/Semnopithèque_blanchâtre_mâle.JPG/192px-Semnopithèque_blanchâtre_mâle.JPG"
|
||||
});
|
||||
|
||||
await Task.Delay(AddItemDelay);
|
||||
|
||||
Monkeys.Add(new Issue7817Model
|
||||
{
|
||||
Index = 5,
|
||||
Name = "Gelada",
|
||||
Location = "Ethiopia",
|
||||
Details = "The gelada, sometimes called the bleeding-heart monkey or the gelada baboon, is a species of Old World monkey found only in the Ethiopian Highlands, with large populations in the Semien Mountains. Theropithecus is derived from the Greek root words for \"beast-ape.\" Like its close relatives the baboons, it is largely terrestrial, spending much of its time foraging in grasslands.",
|
||||
ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/1/13/Gelada-Pavian.jpg/320px-Gelada-Pavian.jpg"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
using Xamarin.Forms.CustomAttributes;
|
||||
using Xamarin.Forms.Internals;
|
||||
|
||||
namespace Xamarin.Forms.Controls.Issues
|
||||
{
|
||||
[Preserve(AllMembers = true)]
|
||||
[Issue(IssueTracker.Github, 7898, "navigation page doesn't hide previous page", PlatformAffected.macOS)]
|
||||
public class Issue7898 : TestNavigationPage
|
||||
{
|
||||
protected override void Init()
|
||||
{
|
||||
Navigation.PushAsync(new ContentPage
|
||||
{
|
||||
BackgroundColor = Color.Yellow,
|
||||
Content = new StackLayout()
|
||||
{
|
||||
Children = {
|
||||
new Button
|
||||
{
|
||||
HorizontalOptions = LayoutOptions.Start,
|
||||
Text = "push page",
|
||||
Command = new Command(async () => await Navigation.PushAsync(new PageWithTransparency(),false))
|
||||
},
|
||||
new Label
|
||||
{
|
||||
HorizontalOptions = LayoutOptions.Center,
|
||||
VerticalOptions = LayoutOptions.Center,
|
||||
Text = "This text should be invisible after second page pushed",
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
class PageWithTransparency : ContentPage
|
||||
{
|
||||
public PageWithTransparency()
|
||||
{
|
||||
this.BackgroundColor = Color.Red.MultiplyAlpha(0.2);
|
||||
Content = new Label
|
||||
{
|
||||
HorizontalOptions = LayoutOptions.Center,
|
||||
VerticalOptions = LayoutOptions.CenterAndExpand,
|
||||
Text = "Text on second page",
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
<?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:d="http://xamarin.com/schemas/2014/forms/design"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:controls="clr-namespace:Xamarin.Forms.Controls"
|
||||
mc:Ignorable="d"
|
||||
x:Class="Xamarin.Forms.Controls.Issues.Issue7943">
|
||||
<ContentPage.Content>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid
|
||||
Grid.Row="0"
|
||||
BackgroundColor="Black">
|
||||
<Label
|
||||
TextColor="White"
|
||||
Text="Press the buttons below to dynamically change the ItemTemplate and ItemsSource of the CollectionView. If change without problems, the test has passed."/>
|
||||
</Grid>
|
||||
<StackLayout
|
||||
Grid.Row="1">
|
||||
<Button
|
||||
Text="Change Template"
|
||||
Clicked="OnChangeTemplate"/>
|
||||
<Button
|
||||
Text="Change ItemsSource"
|
||||
Clicked="OnChangeItemsSource"/>
|
||||
<Button
|
||||
Text="Clear ItemsSource"
|
||||
Clicked="OnClearItemsSource"/>
|
||||
</StackLayout>
|
||||
<CollectionView
|
||||
Grid.Row="2"
|
||||
x:Name="collectionView">
|
||||
<CollectionView.EmptyView>
|
||||
<Grid
|
||||
BackgroundColor="GreenYellow">
|
||||
<Label
|
||||
Text="No data available"
|
||||
HorizontalOptions="Center"
|
||||
VerticalOptions="Center"/>
|
||||
</Grid>
|
||||
</CollectionView.EmptyView>
|
||||
</CollectionView>
|
||||
</Grid>
|
||||
</ContentPage.Content>
|
||||
</controls:TestContentPage>
|
|
@ -0,0 +1,94 @@
|
|||
using Xamarin.Forms.Xaml;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Xamarin.Forms.Internals;
|
||||
using Xamarin.Forms.CustomAttributes;
|
||||
|
||||
#if UITEST
|
||||
using Xamarin.UITest;
|
||||
using Xamarin.UITest.Queries;
|
||||
using NUnit.Framework;
|
||||
using Xamarin.Forms.Core.UITests;
|
||||
#endif
|
||||
|
||||
namespace Xamarin.Forms.Controls.Issues
|
||||
{
|
||||
#if UITEST
|
||||
[Category(UITestCategories.CollectionView)]
|
||||
#endif
|
||||
#if APP
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
#endif
|
||||
[Preserve(AllMembers = true)]
|
||||
[Issue(IssueTracker.Github, 7943, "[Android] Crashes if EmptyView defined and ItemsSource is changed after ItemTemplate is changed", PlatformAffected.Android)]
|
||||
public partial class Issue7943 : TestContentPage
|
||||
{
|
||||
public Issue7943()
|
||||
{
|
||||
#if APP
|
||||
Device.SetFlags(new List<string> { CollectionView.CollectionViewExperimental });
|
||||
Title = "Issue 7943";
|
||||
InitializeComponent();
|
||||
|
||||
collectionView.ItemTemplate = new DataTemplate(() =>
|
||||
{
|
||||
var grid = new Grid();
|
||||
var lbl1 = new Label();
|
||||
lbl1.SetBinding(Label.TextProperty, "Name");
|
||||
grid.Children.Add(lbl1);
|
||||
var lbl2 = new Label();
|
||||
lbl2.SetBinding(Label.TextProperty, "Age");
|
||||
lbl2.SetValue(Grid.ColumnProperty, 1);
|
||||
grid.Children.Add(lbl2);
|
||||
|
||||
return grid;
|
||||
});
|
||||
collectionView.ItemsSource = new List<Issue7943Model> { new Issue7943Model("John", 41), new Issue7943Model("Jane", 24) };
|
||||
#endif
|
||||
}
|
||||
|
||||
protected override void Init()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
#if APP
|
||||
void OnChangeTemplate(object sender, EventArgs e)
|
||||
{
|
||||
var random = new Random();
|
||||
|
||||
collectionView.ItemTemplate = new DataTemplate(() =>
|
||||
{
|
||||
var grid = new Grid();
|
||||
grid.BackgroundColor = Color.FromRgb(random.Next(0, 255), random.Next(0, 255), random.Next(0, 255));
|
||||
var lbl1 = new Label();
|
||||
lbl1.SetBinding(Label.TextProperty, "Name");
|
||||
grid.Children.Add(lbl1);
|
||||
return grid;
|
||||
});
|
||||
}
|
||||
void OnChangeItemsSource(object sender, EventArgs e)
|
||||
{
|
||||
collectionView.ItemsSource = new List<Issue7943Model> { new Issue7943Model("Paul", 35), new Issue7943Model("Lucy", 57) };
|
||||
}
|
||||
|
||||
void OnClearItemsSource(object sender, EventArgs e)
|
||||
{
|
||||
collectionView.ItemsSource = null;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
[Preserve(AllMembers = true)]
|
||||
class Issue7943Model
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Age { get; set; }
|
||||
public Issue7943Model(string name, int age)
|
||||
{
|
||||
Name = name;
|
||||
Age = age;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)Issue5354.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue6963.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue7253.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue7621.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
|
@ -55,9 +56,24 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)Issue7519Xaml.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue7758.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue7593.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue7792.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue7789.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue7817.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue7943.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)RefreshViewTests.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue7338.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ScrollToGroup.cs" />
|
||||
|
@ -1082,11 +1098,13 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)Issue7395.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue7582.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue7563.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue7742.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue7678.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue6491.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue6127.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue7283.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue5395.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue7898.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Bugzilla22229.xaml">
|
||||
|
@ -1404,7 +1422,19 @@
|
|||
<Compile Update="$(MSBuildThisFileDirectory)Issue7357.xaml.cs">
|
||||
<DependentUpon>Issue7357.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="C:\Users\hartez\Documents\Xamarin\Xamarin.Forms\Xamarin.Forms.Controls.Issues\Xamarin.Forms.Controls.Issues.Shared\Issue7519Xaml.xaml.cs">
|
||||
<Compile Update="$(MSBuildThisFileDirectory)Issue7792.xaml.cs">
|
||||
<DependentUpon>Issue7792.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="$(MSBuildThisFileDirectory)Issue7789.xaml.cs">
|
||||
<DependentUpon>Issue7789.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="$(MSBuildThisFileDirectory)Issue7519Xaml.xaml.cs">
|
||||
<DependentUpon>Issue7519Xaml.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="$(MSBuildThisFileDirectory)Issue7817.xaml.cs">
|
||||
<DependentUpon>Issue7817.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="$(MSBuildThisFileDirectory)Issue7519Xaml.xaml.cs">
|
||||
<DependentUpon>Issue7519Xaml.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="$(MSBuildThisFileDirectory)Issue5354.xaml.cs">
|
||||
|
@ -1419,6 +1449,12 @@
|
|||
<Compile Update="$(MSBuildThisFileDirectory)Issue7593.xaml.cs">
|
||||
<DependentUpon>Issue7593.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="$(MSBuildThisFileDirectory)Issue7758.xaml.cs">
|
||||
<DependentUpon>Issue7758.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="$(MSBuildThisFileDirectory)Issue7943.xaml.cs">
|
||||
<DependentUpon>Issue7943.xaml</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue1455.xaml">
|
||||
|
@ -1480,4 +1516,32 @@
|
|||
<Generator>MSBuild:Compile</Generator>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7792.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7758.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7789.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7817.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7943.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -13,7 +13,8 @@
|
|||
|
||||
<CollectionView x:Name="CollectionView" Grid.Row="1">
|
||||
<CollectionView.ItemsLayout>
|
||||
<GridItemsLayout Span="3" Orientation="Vertical"></GridItemsLayout>
|
||||
<!--GridItemsLayout Span="3" Orientation="Vertical"></GridItemsLayout>-->
|
||||
<LinearItemsLayout Orientation="Vertical"></LinearItemsLayout>
|
||||
</CollectionView.ItemsLayout>
|
||||
<CollectionView.EmptyView>
|
||||
No items match your filter.
|
||||
|
|
|
@ -56,7 +56,7 @@ namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.GroupingGa
|
|||
}
|
||||
));
|
||||
|
||||
Add(new Team("Fantastic Four",
|
||||
Add(new Team("Fantastic Four",
|
||||
new List<Member>
|
||||
{
|
||||
new Member("The Thing"),
|
||||
|
@ -66,7 +66,7 @@ namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.GroupingGa
|
|||
}
|
||||
));
|
||||
|
||||
Add(new Team("Defenders",
|
||||
Add(new Team("Defenders",
|
||||
new List<Member>
|
||||
{
|
||||
new Member("Doctor Strange"),
|
||||
|
@ -78,8 +78,8 @@ namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.GroupingGa
|
|||
new Member("Yellowjacket"),
|
||||
}
|
||||
));
|
||||
|
||||
Add(new Team("Heroes for Hire",
|
||||
|
||||
Add(new Team("Heroes for Hire",
|
||||
new List<Member>
|
||||
{
|
||||
new Member("Luke Cage"),
|
||||
|
@ -90,7 +90,7 @@ namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.GroupingGa
|
|||
}
|
||||
));
|
||||
|
||||
Add(new Team("West Coast Avengers",
|
||||
Add(new Team("West Coast Avengers",
|
||||
new List<Member>
|
||||
{
|
||||
new Member("Hawkeye"),
|
||||
|
@ -101,7 +101,7 @@ namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.GroupingGa
|
|||
}
|
||||
));
|
||||
|
||||
Add(new Team("Great Lakes Avengers",
|
||||
Add(new Team("Great Lakes Avengers",
|
||||
new List<Member>
|
||||
{
|
||||
new Member("Squirrel Girl"),
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
new SelectionChangedCommandParameter(), Navigation),
|
||||
GalleryBuilder.NavButton("Filterable Single Selection", () =>
|
||||
new FilterSelection(), Navigation),
|
||||
GalleryBuilder.NavButton("Selection Synchronization", () =>
|
||||
new SelectionSynchronization(), Navigation),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
x:Class="Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.SelectionGalleries.SelectionSynchronization">
|
||||
<ContentPage.Resources>
|
||||
<ResourceDictionary>
|
||||
<DataTemplate x:Key="TestTemplate">
|
||||
<Label Text="{Binding .}" Margin="0,3,0,3"></Label>
|
||||
</DataTemplate>
|
||||
<Style x:Key="CV" TargetType="CollectionView">
|
||||
<Setter Property="HeightRequest" Value="250"/>
|
||||
<Setter Property="ItemTemplate" Value="{StaticResource TestTemplate}"></Setter>
|
||||
<Setter Property="Margin" Value="5,2,5,5"></Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
</ContentPage.Resources>
|
||||
|
||||
<ContentPage.Content>
|
||||
<ScrollView>
|
||||
<StackLayout>
|
||||
|
||||
<Label AutomationId="FirstLabel" Text="Set ItemsSource then SelectedItems"/>
|
||||
<Label Text="Should have items 2 and 3 selected"/>
|
||||
<CollectionView Style="{StaticResource CV}" SelectionMode="Multiple"
|
||||
ItemsSource="{Binding Items}" SelectedItems="{Binding SelectedItems}">
|
||||
</CollectionView>
|
||||
|
||||
<Label Text="Set SelectedItems then ItemsSource"/>
|
||||
<Label Text="Should have items 2 and 3 selected"/>
|
||||
<CollectionView Style="{StaticResource CV}" SelectionMode="Multiple"
|
||||
SelectedItems="{Binding SelectedItems}" ItemsSource="{Binding Items}">
|
||||
|
||||
</CollectionView>
|
||||
|
||||
<Label Text="Set ItemsSource then SelectedItem"/>
|
||||
<Label Text="Should have item 2 selected"/>
|
||||
<CollectionView Style="{StaticResource CV}" SelectionMode="Single"
|
||||
ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}">
|
||||
|
||||
</CollectionView>
|
||||
|
||||
<Label Text="Set SelectedItem then ItemsSource"/>
|
||||
<Label Text="Should have item 2 selected"/>
|
||||
<CollectionView Style="{StaticResource CV}" SelectionMode="Single"
|
||||
SelectedItem="{Binding SelectedItem}" ItemsSource="{Binding Items}">
|
||||
|
||||
</CollectionView>
|
||||
|
||||
<Label Text="Set SelectedItems (not in source) then ItemsSource"/>
|
||||
<Label Text="Should have nothing selected"/>
|
||||
<CollectionView Style="{StaticResource CV}" SelectionMode="Multiple"
|
||||
SelectedItems="{Binding SelectedItemsNotInSource}" ItemsSource="{Binding Items}">
|
||||
|
||||
</CollectionView>
|
||||
|
||||
<Label Text="Set ItemsSource then SelectedItems (not in source)"/>
|
||||
<Label Text="Should have nothing selected"/>
|
||||
<CollectionView Style="{StaticResource CV}" SelectionMode="Multiple"
|
||||
ItemsSource="{Binding Items}" SelectedItems="{Binding SelectedItemsNotInSource}" >
|
||||
|
||||
</CollectionView>
|
||||
|
||||
<Label Text="Set SelectedItem (not in source) then ItemsSource"/>
|
||||
<Label Text="Should have nothing selected"/>
|
||||
<CollectionView Style="{StaticResource CV}" SelectionMode="Single"
|
||||
SelectedItem="{Binding SelectedItemNotInSource}" ItemsSource="{Binding Items}">
|
||||
|
||||
</CollectionView>
|
||||
|
||||
<Label Text="Set ItemsSource then SelectedItem (not in source)"/>
|
||||
<Label Text="Should have nothing selected"/>
|
||||
<CollectionView Style="{StaticResource CV}" SelectionMode="Single"
|
||||
ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItemNotInSource}">
|
||||
|
||||
</CollectionView>
|
||||
|
||||
<Label Text="Switch out ItemSource for one with only some of the SelectedItems"/>
|
||||
<Button x:Name="SwitchSource" Text="Switch Source" Clicked="SwitchSourceClicked"/>
|
||||
<Label Text="After hitting the button, should only have Item 3 selected"/>
|
||||
<CollectionView x:Name="CVSwitchSource" Style="{StaticResource CV}" SelectionMode="Multiple"
|
||||
ItemsSource="{Binding Items}" SelectedItems="{Binding SelectedItems}">
|
||||
|
||||
</CollectionView>
|
||||
</StackLayout>
|
||||
</ScrollView>
|
||||
</ContentPage.Content>
|
||||
</ContentPage>
|
|
@ -0,0 +1,54 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Internals;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.SelectionGalleries
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class SelectionSynchronization : ContentPage
|
||||
{
|
||||
public SelectionSynchronization()
|
||||
{
|
||||
InitializeComponent();
|
||||
BindingContext = new SelectionSyncModel();
|
||||
}
|
||||
|
||||
void SwitchSourceClicked(object sender, EventArgs e)
|
||||
{
|
||||
var newSource = new List<string> { "Item -1", "Item 0", "Item 1", "Item 3", "Item 4", "Item 5" };
|
||||
CVSwitchSource.ItemsSource = newSource;
|
||||
}
|
||||
}
|
||||
|
||||
[Preserve(AllMembers = true)]
|
||||
public class SelectionSyncModel
|
||||
{
|
||||
public SelectionSyncModel()
|
||||
{
|
||||
Items = new List<string>() {
|
||||
"Item 1", "Item 2", "Item 3", "Item 4"
|
||||
};
|
||||
|
||||
SelectedItem = "Item 2";
|
||||
SelectedItems = new ObservableCollection<object> { "Item 3", "Item 2" };
|
||||
|
||||
SelectedItemNotInSource = "Foo";
|
||||
SelectedItemsNotInSource = new ObservableCollection<object> { "Foo", "Bar", "Baz" };
|
||||
}
|
||||
|
||||
public List<string> Items { get; set; }
|
||||
|
||||
public string SelectedItem { get; set; }
|
||||
public ObservableCollection<object> SelectedItems { get; set; }
|
||||
|
||||
public string SelectedItemNotInSource { get; set; }
|
||||
public ObservableCollection<object> SelectedItemsNotInSource { get; set; }
|
||||
}
|
||||
}
|
|
@ -174,5 +174,14 @@ namespace Xamarin.Forms.Core.UnitTests
|
|||
datePicker.SetValue (DatePicker.DateProperty, nullableDateTime);
|
||||
Assert.AreEqual (dateTime, datePicker.Date);
|
||||
}
|
||||
|
||||
[Test]
|
||||
//https://github.com/xamarin/Xamarin.Forms/issues/5784
|
||||
public void SetMaxAndMinDateTimeToNow()
|
||||
{
|
||||
var datePicker = new DatePicker();
|
||||
datePicker.SetValue(DatePicker.MaximumDateProperty, DateTime.Now);
|
||||
Assert.DoesNotThrow(() => datePicker.SetValue(DatePicker.MinimumDateProperty, DateTime.Now));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -243,6 +243,54 @@ namespace Xamarin.Forms
|
|||
}
|
||||
}
|
||||
|
||||
PropertyInfo GetIndexer(TypeInfo sourceType, string indexerName, string content)
|
||||
{
|
||||
if (int.TryParse(content, out _)) { //try to find an indexer taking an int
|
||||
foreach (var pi in sourceType.DeclaredProperties) {
|
||||
if (pi.Name != indexerName)
|
||||
continue;
|
||||
if (pi.CanRead && pi.GetMethod.GetParameters()[0].ParameterType == typeof(int))
|
||||
return pi;
|
||||
if (pi.CanWrite && pi.SetMethod.ReturnType == typeof(int))
|
||||
return pi;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//property isn't an int, or there wasn't any int indexer
|
||||
foreach (var pi in sourceType.DeclaredProperties) {
|
||||
if (pi.Name != indexerName)
|
||||
continue;
|
||||
if (pi.CanRead && pi.GetMethod.GetParameters()[0].ParameterType == typeof(string))
|
||||
return pi;
|
||||
if (pi.CanWrite && pi.SetMethod.ReturnType == typeof(string))
|
||||
return pi;
|
||||
}
|
||||
|
||||
//try to fallback to an object indexer
|
||||
foreach (var pi in sourceType.DeclaredProperties)
|
||||
{
|
||||
if (pi.Name != indexerName)
|
||||
continue;
|
||||
if (pi.CanRead && pi.GetMethod.GetParameters()[0].ParameterType == typeof(object))
|
||||
return pi;
|
||||
if (pi.CanWrite && pi.SetMethod.ReturnType == typeof(object))
|
||||
return pi;
|
||||
}
|
||||
|
||||
//defined on an interface ?
|
||||
foreach (var face in sourceType.ImplementedInterfaces) {
|
||||
if (GetIndexer(face.GetTypeInfo(), indexerName, content) is PropertyInfo pi)
|
||||
return pi;
|
||||
}
|
||||
|
||||
//defined on a base class ?
|
||||
if (sourceType.BaseType is Type baseT && GetIndexer(baseT.GetTypeInfo(), indexerName, content) is PropertyInfo p)
|
||||
return p;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
void SetupPart(TypeInfo sourceType, BindingExpressionPart part)
|
||||
{
|
||||
part.Arguments = null;
|
||||
|
@ -254,8 +302,7 @@ namespace Xamarin.Forms
|
|||
{
|
||||
if (sourceType.IsArray)
|
||||
{
|
||||
int index;
|
||||
if (!int.TryParse(part.Content, out index))
|
||||
if (!int.TryParse(part.Content, out var index))
|
||||
Log.Warning("Binding", "{0} could not be parsed as an index for a {1}", part.Content, sourceType);
|
||||
else
|
||||
part.Arguments = new object[] { index };
|
||||
|
@ -265,46 +312,16 @@ namespace Xamarin.Forms
|
|||
part.SetterType = sourceType.GetElementType();
|
||||
}
|
||||
|
||||
DefaultMemberAttribute defaultMember = null;
|
||||
foreach (var attrib in sourceType.GetCustomAttributes(typeof(DefaultMemberAttribute), true))
|
||||
string indexerName = "Item";
|
||||
foreach (DefaultMemberAttribute attrib in sourceType.GetCustomAttributes(typeof(DefaultMemberAttribute), true))
|
||||
{
|
||||
if (attrib is DefaultMemberAttribute d)
|
||||
{
|
||||
defaultMember = d;
|
||||
break;
|
||||
}
|
||||
indexerName = attrib.MemberName;
|
||||
break;
|
||||
}
|
||||
|
||||
string indexerName = defaultMember != null ? defaultMember.MemberName : "Item";
|
||||
|
||||
part.IndexerName = indexerName;
|
||||
|
||||
#if NETSTANDARD2_0
|
||||
try {
|
||||
property = sourceType.GetDeclaredProperty(indexerName);
|
||||
}
|
||||
catch (AmbiguousMatchException) {
|
||||
// Get most derived instance of property
|
||||
foreach (var p in sourceType.GetProperties()) {
|
||||
if (p.Name == indexerName && (property == null || property.DeclaringType.IsAssignableFrom(property.DeclaringType)))
|
||||
property = p;
|
||||
}
|
||||
}
|
||||
#else
|
||||
property = sourceType.GetDeclaredProperty(indexerName);
|
||||
#endif
|
||||
|
||||
if (property == null) //is the indexer defined on the base class?
|
||||
property = sourceType.BaseType.GetProperty(indexerName);
|
||||
if (property == null) //is the indexer defined on implemented interface ?
|
||||
{
|
||||
foreach (var implementedInterface in sourceType.ImplementedInterfaces)
|
||||
{
|
||||
property = implementedInterface.GetProperty(indexerName);
|
||||
if (property != null)
|
||||
break;
|
||||
}
|
||||
}
|
||||
property = GetIndexer(sourceType, indexerName, part.Content);
|
||||
|
||||
if (property != null)
|
||||
{
|
||||
|
@ -312,9 +329,7 @@ namespace Xamarin.Forms
|
|||
ParameterInfo[] array = property.GetIndexParameters();
|
||||
|
||||
if (array.Length > 0)
|
||||
{
|
||||
parameter = array[0];
|
||||
}
|
||||
|
||||
if (parameter != null)
|
||||
{
|
||||
|
|
|
@ -154,12 +154,12 @@ namespace Xamarin.Forms
|
|||
|
||||
static bool ValidateMaximumDate(BindableObject bindable, object value)
|
||||
{
|
||||
return (DateTime)value >= ((DatePicker)bindable).MinimumDate;
|
||||
return ((DateTime)value).Date >= ((DatePicker)bindable).MinimumDate.Date;
|
||||
}
|
||||
|
||||
static bool ValidateMinimumDate(BindableObject bindable, object value)
|
||||
{
|
||||
return (DateTime)value <= ((DatePicker)bindable).MaximumDate;
|
||||
return ((DateTime)value).Date <= ((DatePicker)bindable).MaximumDate.Date;
|
||||
}
|
||||
|
||||
public IPlatformElementConfiguration<T, DatePicker> On<T>() where T : IConfigPlatform
|
||||
|
|
|
@ -13,7 +13,8 @@ namespace Xamarin.Forms
|
|||
|
||||
internal static readonly LinearItemsLayout CarouselDefault = new LinearItemsLayout(ItemsLayoutOrientation.Horizontal)
|
||||
{
|
||||
SnapPointsAlignment = SnapPointsAlignment.Center, SnapPointsType = SnapPointsType.Mandatory
|
||||
SnapPointsType = SnapPointsType.MandatorySingle,
|
||||
SnapPointsAlignment = SnapPointsAlignment.Center
|
||||
};
|
||||
|
||||
public static readonly BindableProperty ItemSpacingProperty =
|
||||
|
|
|
@ -50,13 +50,14 @@ namespace Xamarin.Forms.Platform.Android
|
|||
protected override void UpdateItemsSource()
|
||||
{
|
||||
UpdateAdapter();
|
||||
UpdateEmptyView();
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs changedProperty)
|
||||
{
|
||||
if (changedProperty.Is(ItemsView.ItemsSourceProperty))
|
||||
UpdateItemsSource();
|
||||
else if (changedProperty.Is(CarouselView.PeekAreaInsetsProperty))
|
||||
base.OnElementPropertyChanged(sender, changedProperty);
|
||||
|
||||
if (changedProperty.Is(CarouselView.PeekAreaInsetsProperty))
|
||||
UpdatePeekAreaInsets();
|
||||
else if (changedProperty.Is(CarouselView.IsSwipeEnabledProperty))
|
||||
UpdateIsSwipeEnabled();
|
||||
|
|
|
@ -28,7 +28,7 @@ namespace Xamarin.Forms.Platform.Android
|
|||
|
||||
public void Stop(Adapter adapter)
|
||||
{
|
||||
if (Observing && adapter != null)
|
||||
if (Observing && adapter != null && adapter.HasObservers)
|
||||
{
|
||||
adapter.UnregisterAdapterDataObserver(this);
|
||||
}
|
||||
|
|
|
@ -281,7 +281,11 @@ namespace Xamarin.Forms.Platform.Android
|
|||
|
||||
if (GetAdapter() != _emptyViewAdapter)
|
||||
{
|
||||
_emptyCollectionObserver.Stop(oldItemViewAdapter);
|
||||
_itemsUpdateScrollObserver.Stop(oldItemViewAdapter);
|
||||
|
||||
SetAdapter(null);
|
||||
|
||||
SwapAdapter(ItemsViewAdapter, true);
|
||||
}
|
||||
|
||||
|
|
|
@ -349,9 +349,10 @@ namespace Xamarin.Forms.Platform.MacOS
|
|||
var target = Platform.GetRenderer(page);
|
||||
var previousPage = _currentStack.Peek().Page;
|
||||
|
||||
var previousPageRenderer = CreateViewControllerForPage(previousPage);
|
||||
ShowView(previousPageRenderer.ViewController);
|
||||
if (animated)
|
||||
{
|
||||
var previousPageRenderer = CreateViewControllerForPage(previousPage);
|
||||
var transitionStyle = NavigationPage.OnThisPlatform().GetNavigationTransitionPopStyle();
|
||||
|
||||
return await this.HandleAsyncAnimation(target.ViewController, previousPageRenderer.ViewController,
|
||||
|
@ -382,6 +383,10 @@ namespace Xamarin.Forms.Platform.MacOS
|
|||
vc.NativeView.WantsLayer = true;
|
||||
AddChildViewController(vc.ViewController);
|
||||
View.AddSubview(vc.NativeView);
|
||||
if (oldPage != null)
|
||||
{
|
||||
HideView(Platform.GetRenderer(oldPage)?.ViewController);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
var vco = Platform.GetRenderer(oldPage);
|
||||
|
@ -389,7 +394,23 @@ namespace Xamarin.Forms.Platform.MacOS
|
|||
|
||||
var transitionStyle = NavigationPage.OnThisPlatform().GetNavigationTransitionPushStyle();
|
||||
return await this.HandleAsyncAnimation(vco.ViewController, vc.ViewController,
|
||||
ToViewControllerTransitionOptions(transitionStyle), () => page?.SendAppearing(), true);
|
||||
ToViewControllerTransitionOptions(transitionStyle), () =>
|
||||
{
|
||||
HideView(vco.ViewController);
|
||||
page?.SendAppearing();
|
||||
}, true);
|
||||
}
|
||||
|
||||
void HideView(NSViewController vc)
|
||||
{
|
||||
if (vc?.View != null)
|
||||
vc.View.Hidden = true;
|
||||
}
|
||||
|
||||
void ShowView(NSViewController vc)
|
||||
{
|
||||
if (vc?.View != null)
|
||||
vc.View.Hidden = false;
|
||||
}
|
||||
|
||||
void UpdateBackgroundColor()
|
||||
|
|
|
@ -12,7 +12,7 @@ using WScrollMode = Windows.UI.Xaml.Controls.ScrollMode;
|
|||
|
||||
namespace Xamarin.Forms.Platform.UWP
|
||||
{
|
||||
public class CarouselViewRenderer : ItemsViewRenderer
|
||||
public class CarouselViewRenderer : ItemsViewRenderer<CarouselView>
|
||||
{
|
||||
ScrollViewer _scrollViewer;
|
||||
public CarouselViewRenderer()
|
||||
|
@ -20,20 +20,19 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
CollectionView.VerifyCollectionViewFlagEnabled(nameof(CarouselView));
|
||||
}
|
||||
|
||||
CarouselView CarouselView => (CarouselView)Element;
|
||||
CarouselView CarouselView => Element;
|
||||
protected override IItemsLayout Layout => CarouselView?.ItemsLayout;
|
||||
UWPDataTemplate CarouselItemsViewTemplate => (UWPDataTemplate)UWPApp.Current.Resources["CarouselItemsViewDefaultTemplate"];
|
||||
LinearItemsLayout CarouselItemsLayout => CarouselView?.ItemsLayout;
|
||||
|
||||
double _itemWidth;
|
||||
double _itemHeight;
|
||||
UWPDataTemplate CarouselItemsViewTemplate => (UWPDataTemplate)UWPApp.Current.Resources["CarouselItemsViewDefaultTemplate"];
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs changedProperty)
|
||||
{
|
||||
base.OnElementPropertyChanged(sender, changedProperty);
|
||||
|
||||
if (changedProperty.IsOneOf(ItemsView.ItemsSourceProperty, CarouselView.NumberOfSideItemsProperty, LinearItemsLayout.ItemSpacingProperty))
|
||||
if (changedProperty.IsOneOf(CarouselView.ItemsSourceProperty, CarouselView.NumberOfSideItemsProperty, LinearItemsLayout.ItemSpacingProperty))
|
||||
UpdateItemsSource();
|
||||
else if (changedProperty.Is(ItemsView.ItemTemplateProperty))
|
||||
else if (changedProperty.Is(CarouselView.ItemTemplateProperty))
|
||||
UpdateItemTemplate();
|
||||
else if (changedProperty.Is(CarouselView.PeekAreaInsetsProperty))
|
||||
UpdatePeekAreaInsets();
|
||||
|
@ -43,9 +42,9 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
UpdateIsBounceEnabled();
|
||||
}
|
||||
|
||||
protected override void HandleLayoutPropertyChange(PropertyChangedEventArgs property)
|
||||
protected override void HandleLayoutPropertyChanged(PropertyChangedEventArgs property)
|
||||
{
|
||||
if (property.IsOneOf(LinearItemsLayout.ItemSpacingProperty, GridItemsLayout.HorizontalItemSpacingProperty, GridItemsLayout.VerticalItemSpacingProperty))
|
||||
if (property.IsOneOf(LinearItemsLayout.ItemSpacingProperty))
|
||||
UpdateItemSpacing();
|
||||
else if (property.Is(ItemsLayout.SnapPointsTypeProperty))
|
||||
UpdateSnapPointsType();
|
||||
|
@ -102,26 +101,14 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
return new CollectionViewSource
|
||||
{
|
||||
Source = TemplatedItemSourceFactory.Create(Element.ItemsSource, Element.ItemTemplate, Element,
|
||||
_itemHeight, _itemWidth, GetItemSpacing()),
|
||||
GetItemHeight(), GetItemWidth(), GetItemSpacing()),
|
||||
IsSourceGrouped = false
|
||||
};
|
||||
}
|
||||
|
||||
protected override ListViewBase SelectListViewBase()
|
||||
{
|
||||
ListViewBase listView = null;
|
||||
|
||||
switch (Layout)
|
||||
{
|
||||
case LinearItemsLayout listItemsLayout:
|
||||
listView = CreateCarouselListLayout(listItemsLayout.Orientation);
|
||||
break;
|
||||
}
|
||||
|
||||
if (listView == null)
|
||||
{
|
||||
listView = new FormsListView();
|
||||
}
|
||||
ListViewBase listView = CreateCarouselListLayout(CarouselItemsLayout.Orientation);
|
||||
|
||||
FindScrollViewer(listView);
|
||||
|
||||
|
@ -148,9 +135,9 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
|
||||
void OnListSizeChanged(object sender, Windows.UI.Xaml.SizeChangedEventArgs e)
|
||||
{
|
||||
_itemHeight = GetItemHeight();
|
||||
_itemWidth = GetItemWidth();
|
||||
UpdateItemsSource();
|
||||
UpdateSnapPointsType();
|
||||
UpdateSnapPointsAlignment();
|
||||
}
|
||||
|
||||
void OnScrollViewChanging(object sender, ScrollViewerViewChangingEventArgs e)
|
||||
|
@ -175,13 +162,13 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
|
||||
ListViewBase.IsSwipeEnabled = CarouselView.IsSwipeEnabled;
|
||||
|
||||
switch (Layout)
|
||||
switch (CarouselItemsLayout.Orientation)
|
||||
{
|
||||
case LinearItemsLayout listItemsLayout when listItemsLayout.Orientation == ItemsLayoutOrientation.Horizontal:
|
||||
case ItemsLayoutOrientation.Horizontal:
|
||||
ScrollViewer.SetHorizontalScrollMode(ListViewBase, CarouselView.IsSwipeEnabled ? WScrollMode.Auto : WScrollMode.Disabled);
|
||||
ScrollViewer.SetHorizontalScrollBarVisibility(ListViewBase, CarouselView.IsSwipeEnabled ? WScrollBarVisibility.Auto : WScrollBarVisibility.Disabled);
|
||||
break;
|
||||
case LinearItemsLayout listItemsLayout when listItemsLayout.Orientation == ItemsLayoutOrientation.Vertical:
|
||||
case ItemsLayoutOrientation.Vertical:
|
||||
ScrollViewer.SetVerticalScrollMode(ListViewBase, CarouselView.IsSwipeEnabled ? WScrollMode.Auto : WScrollMode.Disabled);
|
||||
ScrollViewer.SetVerticalScrollBarVisibility(ListViewBase, CarouselView.IsSwipeEnabled ? WScrollBarVisibility.Auto : WScrollBarVisibility.Disabled);
|
||||
break;
|
||||
|
@ -198,15 +185,12 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
{
|
||||
UpdateItemsSource();
|
||||
|
||||
if (Layout is LinearItemsLayout listItemsLayout)
|
||||
{
|
||||
var itemSpacing = listItemsLayout.ItemSpacing;
|
||||
if (listItemsLayout.Orientation == ItemsLayoutOrientation.Horizontal)
|
||||
_scrollViewer.Padding = new Windows.UI.Xaml.Thickness(0, 0, itemSpacing, 0);
|
||||
var itemSpacing = CarouselItemsLayout.ItemSpacing;
|
||||
if (CarouselItemsLayout.Orientation == ItemsLayoutOrientation.Horizontal)
|
||||
_scrollViewer.Padding = new Windows.UI.Xaml.Thickness(0, 0, itemSpacing, 0);
|
||||
|
||||
if (listItemsLayout.Orientation == ItemsLayoutOrientation.Vertical)
|
||||
_scrollViewer.Padding = new Windows.UI.Xaml.Thickness(0, 0, 0, itemSpacing);
|
||||
}
|
||||
if (CarouselItemsLayout.Orientation == ItemsLayoutOrientation.Vertical)
|
||||
_scrollViewer.Padding = new Windows.UI.Xaml.Thickness(0, 0, 0, itemSpacing);
|
||||
}
|
||||
|
||||
void UpdateSnapPointsType()
|
||||
|
@ -214,14 +198,11 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
if (_scrollViewer == null)
|
||||
return;
|
||||
|
||||
if (Layout is LinearItemsLayout listItemsLayout)
|
||||
{
|
||||
if (listItemsLayout.Orientation == ItemsLayoutOrientation.Horizontal)
|
||||
_scrollViewer.HorizontalSnapPointsType = GetWindowsSnapPointsType(listItemsLayout.SnapPointsType);
|
||||
if (CarouselItemsLayout.Orientation == ItemsLayoutOrientation.Horizontal)
|
||||
_scrollViewer.HorizontalSnapPointsType = GetWindowsSnapPointsType(CarouselItemsLayout.SnapPointsType);
|
||||
|
||||
if (listItemsLayout.Orientation == ItemsLayoutOrientation.Vertical)
|
||||
_scrollViewer.VerticalSnapPointsType = GetWindowsSnapPointsType(listItemsLayout.SnapPointsType);
|
||||
}
|
||||
if (CarouselItemsLayout.Orientation == ItemsLayoutOrientation.Vertical)
|
||||
_scrollViewer.VerticalSnapPointsType = GetWindowsSnapPointsType(CarouselItemsLayout.SnapPointsType);
|
||||
}
|
||||
|
||||
void UpdateSnapPointsAlignment()
|
||||
|
@ -229,14 +210,11 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
if (_scrollViewer == null)
|
||||
return;
|
||||
|
||||
if (Layout is LinearItemsLayout listItemsLayout)
|
||||
{
|
||||
if (listItemsLayout.Orientation == ItemsLayoutOrientation.Horizontal)
|
||||
_scrollViewer.HorizontalSnapPointsAlignment = GetWindowsSnapPointsAlignment(listItemsLayout.SnapPointsAlignment);
|
||||
if (CarouselItemsLayout.Orientation == ItemsLayoutOrientation.Horizontal)
|
||||
_scrollViewer.HorizontalSnapPointsAlignment = GetWindowsSnapPointsAlignment(CarouselItemsLayout.SnapPointsAlignment);
|
||||
|
||||
if (listItemsLayout.Orientation == ItemsLayoutOrientation.Vertical)
|
||||
_scrollViewer.VerticalSnapPointsAlignment = GetWindowsSnapPointsAlignment(listItemsLayout.SnapPointsAlignment);
|
||||
}
|
||||
if (CarouselItemsLayout.Orientation == ItemsLayoutOrientation.Vertical)
|
||||
_scrollViewer.VerticalSnapPointsAlignment = GetWindowsSnapPointsAlignment(CarouselItemsLayout.SnapPointsAlignment);
|
||||
}
|
||||
|
||||
ListViewBase CreateCarouselListLayout(ItemsLayoutOrientation layoutOrientation)
|
||||
|
@ -266,10 +244,10 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
{
|
||||
var itemWidth = ActualWidth;
|
||||
|
||||
if (Layout is LinearItemsLayout listItemsLayout && listItemsLayout.Orientation == ItemsLayoutOrientation.Horizontal)
|
||||
if (CarouselItemsLayout.Orientation == ItemsLayoutOrientation.Horizontal)
|
||||
{
|
||||
var numberOfVisibleItems = CarouselView.NumberOfSideItems * 2 + 1;
|
||||
itemWidth = (ActualWidth - CarouselView.PeekAreaInsets.Left - CarouselView.PeekAreaInsets.Right - listItemsLayout.ItemSpacing) / numberOfVisibleItems;
|
||||
itemWidth = (ActualWidth - CarouselView.PeekAreaInsets.Left - CarouselView.PeekAreaInsets.Right - CarouselItemsLayout.ItemSpacing) / numberOfVisibleItems;
|
||||
}
|
||||
|
||||
return Math.Max(itemWidth, 0);
|
||||
|
@ -279,10 +257,10 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
{
|
||||
var itemHeight = ActualHeight;
|
||||
|
||||
if (Layout is LinearItemsLayout listItemsLayout && listItemsLayout.Orientation == ItemsLayoutOrientation.Vertical)
|
||||
if (CarouselItemsLayout.Orientation == ItemsLayoutOrientation.Vertical)
|
||||
{
|
||||
var numberOfVisibleItems = CarouselView.NumberOfSideItems * 2 + 1;
|
||||
itemHeight = (ActualHeight - CarouselView.PeekAreaInsets.Top - CarouselView.PeekAreaInsets.Bottom - listItemsLayout.ItemSpacing) / numberOfVisibleItems;
|
||||
itemHeight = (ActualHeight - CarouselView.PeekAreaInsets.Top - CarouselView.PeekAreaInsets.Bottom - CarouselItemsLayout.ItemSpacing) / numberOfVisibleItems;
|
||||
}
|
||||
|
||||
return Math.Max(itemHeight, 0);
|
||||
|
@ -290,16 +268,13 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
|
||||
Thickness GetItemSpacing()
|
||||
{
|
||||
if (Layout is LinearItemsLayout listItemsLayout)
|
||||
{
|
||||
var itemSpacing = listItemsLayout.ItemSpacing;
|
||||
var itemSpacing = CarouselItemsLayout.ItemSpacing;
|
||||
|
||||
if (listItemsLayout.Orientation == ItemsLayoutOrientation.Horizontal)
|
||||
return new Thickness(itemSpacing, 0, 0, 0);
|
||||
if (CarouselItemsLayout.Orientation == ItemsLayoutOrientation.Horizontal)
|
||||
return new Thickness(itemSpacing, 0, 0, 0);
|
||||
|
||||
if (listItemsLayout.Orientation == ItemsLayoutOrientation.Vertical)
|
||||
return new Thickness(0, itemSpacing, 0, 0);
|
||||
}
|
||||
if (CarouselItemsLayout.Orientation == ItemsLayoutOrientation.Vertical)
|
||||
return new Thickness(0, itemSpacing, 0, 0);
|
||||
|
||||
return new Thickness(0);
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ using Xamarin.Forms.Platform.UAP;
|
|||
|
||||
namespace Xamarin.Forms.Platform.UWP
|
||||
{
|
||||
public class CollectionViewRenderer : SelectableItemsViewRenderer
|
||||
public class CollectionViewRenderer : GroupableItemsViewRenderer<GroupableItemsView>
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,60 +1,68 @@
|
|||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using UWPApp = Windows.UI.Xaml.Application;
|
||||
using UWPControlTemplate = Windows.UI.Xaml.Controls.ControlTemplate;
|
||||
using UWPControls = Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace Xamarin.Forms.Platform.UWP
|
||||
{
|
||||
internal class FormsGridView : GridView, IEmptyView
|
||||
{
|
||||
int _maximumRowsOrColumns;
|
||||
int _span;
|
||||
ItemsWrapGrid _wrapGrid;
|
||||
ContentControl _emptyViewContentControl;
|
||||
FrameworkElement _emptyView;
|
||||
Orientation _orientation;
|
||||
|
||||
public FormsGridView()
|
||||
{
|
||||
Template = (UWPControlTemplate)UWPApp.Current.Resources["FormsListViewTemplate"];
|
||||
// Using the full style for this control, because for some reason on 16299 we can't set the ControlTemplate
|
||||
// (it just fails silently saying it can't find the resource key)
|
||||
DefaultStyleKey = typeof(FormsGridView);
|
||||
|
||||
// TODO hartez 2018/06/06 09:52:16 Do we need to clean this up? If so, where?
|
||||
RegisterPropertyChangedCallback(ItemsPanelProperty, ItemsPanelChanged);
|
||||
Loaded += OnLoaded;
|
||||
}
|
||||
|
||||
public int MaximumRowsOrColumns
|
||||
public int Span
|
||||
{
|
||||
get => _maximumRowsOrColumns;
|
||||
get => _span;
|
||||
set
|
||||
{
|
||||
_maximumRowsOrColumns = value;
|
||||
_span = value;
|
||||
if (_wrapGrid != null)
|
||||
{
|
||||
_wrapGrid.MaximumRowsOrColumns = MaximumRowsOrColumns;
|
||||
UpdateItemSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty EmptyViewVisibilityProperty =
|
||||
DependencyProperty.Register(nameof(EmptyViewVisibility), typeof(Visibility),
|
||||
typeof(FormsGridView), new PropertyMetadata(Visibility.Collapsed));
|
||||
|
||||
public Visibility EmptyViewVisibility
|
||||
{
|
||||
get { return (Visibility)GetValue(EmptyViewVisibilityProperty); }
|
||||
set { SetValue(EmptyViewVisibilityProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty EmptyViewVisibilityProperty =
|
||||
DependencyProperty.Register(nameof(EmptyViewVisibility), typeof(Visibility),
|
||||
typeof(FormsGridView), new PropertyMetadata(Visibility.Collapsed));
|
||||
|
||||
// TODO hartez 2018/06/06 10:01:32 Probably should just create a local enum for this?
|
||||
public void UseHorizontalItemsPanel()
|
||||
public Orientation Orientation
|
||||
{
|
||||
ItemsPanel =
|
||||
(ItemsPanelTemplate)UWPApp.Current.Resources["HorizontalGridItemsPanel"];
|
||||
}
|
||||
|
||||
public void UseVerticalItemsPanel()
|
||||
{
|
||||
ItemsPanel =
|
||||
(ItemsPanelTemplate)UWPApp.Current.Resources["VerticalGridItemsPanel"];
|
||||
get => _orientation;
|
||||
set
|
||||
{
|
||||
_orientation = value;
|
||||
if (_orientation == Orientation.Horizontal)
|
||||
{
|
||||
ItemsPanel = (ItemsPanelTemplate)UWPApp.Current.Resources["HorizontalGridItemsPanel"];
|
||||
ScrollViewer.SetHorizontalScrollMode(this, ScrollMode.Auto);
|
||||
ScrollViewer.SetHorizontalScrollBarVisibility(this, UWPControls.ScrollBarVisibility.Auto);
|
||||
}
|
||||
else
|
||||
{
|
||||
ItemsPanel = (ItemsPanelTemplate)UWPApp.Current.Resources["VerticalGridItemsPanel"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FindItemsWrapGrid()
|
||||
|
@ -66,7 +74,25 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
return;
|
||||
}
|
||||
|
||||
_wrapGrid.MaximumRowsOrColumns = MaximumRowsOrColumns;
|
||||
_wrapGrid.SizeChanged -= WrapGridSizeChanged;
|
||||
_wrapGrid.SizeChanged += WrapGridSizeChanged;
|
||||
}
|
||||
|
||||
void WrapGridSizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
UpdateItemSize();
|
||||
}
|
||||
|
||||
void UpdateItemSize()
|
||||
{
|
||||
if (_orientation == Orientation.Horizontal)
|
||||
{
|
||||
_wrapGrid.ItemHeight = _wrapGrid.ActualHeight / Span;
|
||||
}
|
||||
else
|
||||
{
|
||||
_wrapGrid.ItemWidth = _wrapGrid.ActualWidth / Span;
|
||||
}
|
||||
}
|
||||
|
||||
void ItemsPanelChanged(DependencyObject sender, DependencyProperty dp)
|
||||
|
@ -100,5 +126,11 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
_emptyViewContentControl.Content = _emptyView;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
|
||||
{
|
||||
GroupFooterItemTemplateContext.EnsureSelectionDisabled(element, item);
|
||||
base.PrepareContainerForItemOverride(element, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,15 +15,16 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
Template = (UWPControlTemplate)UWPApp.Current.Resources["FormsListViewTemplate"];
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty EmptyViewVisibilityProperty =
|
||||
DependencyProperty.Register(nameof(EmptyViewVisibility), typeof(Visibility),
|
||||
typeof(FormsListView), new PropertyMetadata(Visibility.Collapsed));
|
||||
|
||||
public Visibility EmptyViewVisibility
|
||||
{
|
||||
get { return (Visibility)GetValue(EmptyViewVisibilityProperty); }
|
||||
set { SetValue(EmptyViewVisibilityProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty EmptyViewVisibilityProperty =
|
||||
DependencyProperty.Register(nameof(EmptyViewVisibility), typeof(Visibility), typeof(FormsListView), new PropertyMetadata(Visibility.Collapsed));
|
||||
|
||||
public void SetEmptyView(FrameworkElement emptyView)
|
||||
{
|
||||
_emptyView = emptyView;
|
||||
|
@ -45,5 +46,11 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
_emptyViewContentControl.Content = _emptyView;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
|
||||
{
|
||||
GroupFooterItemTemplateContext.EnsureSelectionDisabled(element, item);
|
||||
base.PrepareContainerForItemOverride(element, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
using Windows.UI.Xaml;
|
||||
|
||||
namespace Xamarin.Forms.Platform.UWP
|
||||
{
|
||||
internal class GroupFooterItemTemplateContext : ItemTemplateContext
|
||||
{
|
||||
public GroupFooterItemTemplateContext(DataTemplate formsDataTemplate, object item,
|
||||
BindableObject container, double? height = null, double? width = null, Thickness? itemSpacing = null)
|
||||
: base(formsDataTemplate, item, container, height, width, itemSpacing)
|
||||
{
|
||||
}
|
||||
|
||||
public static void EnsureSelectionDisabled(DependencyObject element, object item)
|
||||
{
|
||||
if (item is GroupFooterItemTemplateContext)
|
||||
{
|
||||
// Prevent the group footer from being selectable
|
||||
(element as FrameworkElement).IsHitTestVisible = false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
using Windows.UI.Xaml.Controls;
|
||||
using UWPApp = Windows.UI.Xaml.Application;
|
||||
using UWPDataTemplate = Windows.UI.Xaml.DataTemplate;
|
||||
|
||||
namespace Xamarin.Forms.Platform.UWP
|
||||
{
|
||||
internal class GroupHeaderStyleSelector : GroupStyleSelector
|
||||
{
|
||||
protected override GroupStyle SelectGroupStyleCore(object group, uint level)
|
||||
{
|
||||
return new GroupStyle
|
||||
{
|
||||
HeaderTemplate = (UWPDataTemplate)UWPApp.Current.Resources["GroupHeaderTemplate"]
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Xamarin.Forms.Platform.UWP
|
||||
{
|
||||
internal class GroupTemplateContext
|
||||
{
|
||||
public ItemTemplateContext HeaderItemTemplateContext { get; }
|
||||
public ItemTemplateContext FooterItemTemplateContext { get; }
|
||||
public object Items { get; }
|
||||
|
||||
public GroupTemplateContext(ItemTemplateContext headerItemTemplateContext,
|
||||
ItemTemplateContext footerItemTemplateContext, object items)
|
||||
{
|
||||
HeaderItemTemplateContext = headerItemTemplateContext;
|
||||
FooterItemTemplateContext = footerItemTemplateContext;
|
||||
|
||||
if (footerItemTemplateContext == null)
|
||||
{
|
||||
Items = items;
|
||||
}
|
||||
else
|
||||
{
|
||||
// UWP ListViewBase does not support group footers. So we're going to fake the footer by adding an
|
||||
// extra item to the ItemsSource so the footer shows up at the end of the group.
|
||||
|
||||
if (items is IList itemsList)
|
||||
{
|
||||
// If it's already an IList, we want to make sure to keep it that way
|
||||
itemsList.Add(footerItemTemplateContext);
|
||||
Items = itemsList;
|
||||
return;
|
||||
}
|
||||
|
||||
// If the group items are not an IList, then we'll have to append the footer the hard way
|
||||
|
||||
var listPlusFooter = new List<object>();
|
||||
|
||||
foreach (var item in (items as IEnumerable))
|
||||
{
|
||||
listPlusFooter.Add(item);
|
||||
}
|
||||
|
||||
listPlusFooter.Add(footerItemTemplateContext);
|
||||
|
||||
Items = listPlusFooter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
using System.ComponentModel;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Data;
|
||||
|
||||
namespace Xamarin.Forms.Platform.UWP
|
||||
{
|
||||
public class GroupableItemsViewRenderer<TItemsView> : SelectableItemsViewRenderer<TItemsView>
|
||||
where TItemsView : GroupableItemsView
|
||||
{
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs changedProperty)
|
||||
{
|
||||
base.OnElementPropertyChanged(sender, changedProperty);
|
||||
|
||||
if (changedProperty.IsOneOf(GroupableItemsView.IsGroupedProperty,
|
||||
GroupableItemsView.GroupFooterTemplateProperty, GroupableItemsView.GroupHeaderTemplateProperty))
|
||||
{
|
||||
UpdateItemsSource();
|
||||
}
|
||||
}
|
||||
|
||||
protected override CollectionViewSource CreateCollectionViewSource()
|
||||
{
|
||||
if (ItemsView != null && ItemsView.IsGrouped)
|
||||
{
|
||||
var itemTemplate = Element.ItemTemplate;
|
||||
var itemsSource = Element.ItemsSource;
|
||||
|
||||
return new CollectionViewSource
|
||||
{
|
||||
Source = TemplatedItemSourceFactory.CreateGrouped(itemsSource, itemTemplate,
|
||||
ItemsView.GroupHeaderTemplate, ItemsView.GroupFooterTemplate, Element),
|
||||
IsSourceGrouped = true,
|
||||
ItemsPath = new Windows.UI.Xaml.PropertyPath(nameof(GroupTemplateContext.Items))
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return base.CreateCollectionViewSource();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void UpdateItemTemplate()
|
||||
{
|
||||
base.UpdateItemTemplate();
|
||||
|
||||
ListViewBase.GroupStyleSelector = new GroupHeaderStyleSelector();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
using System.Collections;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
namespace Xamarin.Forms.Platform.UWP
|
||||
{
|
||||
internal class GroupedItemTemplateCollection : ObservableCollection<GroupTemplateContext>
|
||||
{
|
||||
readonly IEnumerable _itemsSource;
|
||||
readonly DataTemplate _itemTemplate;
|
||||
readonly DataTemplate _groupHeaderTemplate;
|
||||
readonly DataTemplate _groupFooterTemplate;
|
||||
readonly BindableObject _container;
|
||||
readonly IList _groupList;
|
||||
|
||||
public GroupedItemTemplateCollection(IEnumerable itemsSource, DataTemplate itemTemplate,
|
||||
DataTemplate groupHeaderTemplate, DataTemplate groupFooterTemplate, BindableObject container)
|
||||
{
|
||||
_itemsSource = itemsSource;
|
||||
_itemTemplate = itemTemplate;
|
||||
_groupHeaderTemplate = groupHeaderTemplate;
|
||||
_groupFooterTemplate = groupFooterTemplate;
|
||||
_container = container;
|
||||
|
||||
foreach (var group in _itemsSource)
|
||||
{
|
||||
var groupTemplateContext = CreateGroupTemplateContext(group);
|
||||
Add(groupTemplateContext);
|
||||
}
|
||||
|
||||
if (_itemsSource is IList groupList && _itemsSource is INotifyCollectionChanged incc)
|
||||
{
|
||||
_groupList = groupList;
|
||||
incc.CollectionChanged += GroupsChanged;
|
||||
}
|
||||
}
|
||||
|
||||
GroupTemplateContext CreateGroupTemplateContext(object group)
|
||||
{
|
||||
var groupHeaderTemplateContext = _groupHeaderTemplate != null
|
||||
? new ItemTemplateContext(_groupHeaderTemplate, group, _container) : null;
|
||||
|
||||
var groupFooterTemplateContext = _groupFooterTemplate != null
|
||||
? new GroupFooterItemTemplateContext(_groupFooterTemplate, group, _container) : null;
|
||||
|
||||
// This is where we'll eventually look at GroupItemPropertyName
|
||||
var groupItemsList = TemplatedItemSourceFactory.Create(group as IEnumerable, _itemTemplate, _container);
|
||||
|
||||
return new GroupTemplateContext(groupHeaderTemplateContext, groupFooterTemplateContext, groupItemsList);
|
||||
}
|
||||
|
||||
void GroupsChanged(object sender, NotifyCollectionChangedEventArgs args)
|
||||
{
|
||||
switch (args.Action)
|
||||
{
|
||||
case NotifyCollectionChangedAction.Add:
|
||||
Add(args);
|
||||
break;
|
||||
case NotifyCollectionChangedAction.Move:
|
||||
Move(args);
|
||||
break;
|
||||
case NotifyCollectionChangedAction.Remove:
|
||||
Remove(args);
|
||||
break;
|
||||
case NotifyCollectionChangedAction.Replace:
|
||||
Replace(args);
|
||||
break;
|
||||
case NotifyCollectionChangedAction.Reset:
|
||||
Reset();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Add(NotifyCollectionChangedEventArgs args)
|
||||
{
|
||||
var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : _groupList.IndexOf(args.NewItems[0]);
|
||||
|
||||
var count = args.NewItems.Count;
|
||||
|
||||
for (int n = 0; n < count; n++)
|
||||
{
|
||||
Insert(startIndex, CreateGroupTemplateContext(args.NewItems[n]));
|
||||
}
|
||||
}
|
||||
|
||||
void Move(NotifyCollectionChangedEventArgs args)
|
||||
{
|
||||
var count = args.NewItems.Count;
|
||||
|
||||
if (args.OldStartingIndex > args.NewStartingIndex)
|
||||
{
|
||||
for (int n = 0; n < count; n++)
|
||||
{
|
||||
Move(args.OldStartingIndex + n, args.NewStartingIndex + n);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (int n = count - 1; n >= 0; n--)
|
||||
{
|
||||
Move(args.OldStartingIndex + n, args.NewStartingIndex + n);
|
||||
}
|
||||
}
|
||||
|
||||
void Remove(NotifyCollectionChangedEventArgs args)
|
||||
{
|
||||
var startIndex = args.OldStartingIndex;
|
||||
|
||||
if (startIndex < 0)
|
||||
{
|
||||
// INCC implementation isn't giving us enough information to know where the removed items were in the
|
||||
// collection. So the best we can do is a full Reset.
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
var count = args.OldItems.Count;
|
||||
|
||||
for (int n = startIndex + count - 1; n >= startIndex; n--)
|
||||
{
|
||||
RemoveAt(n);
|
||||
}
|
||||
}
|
||||
|
||||
void Replace(NotifyCollectionChangedEventArgs args)
|
||||
{
|
||||
var newItemCount = args.NewItems.Count;
|
||||
|
||||
if (newItemCount == args.OldItems.Count)
|
||||
{
|
||||
for (int n = 0; n < newItemCount; n++)
|
||||
{
|
||||
var index = args.OldStartingIndex + n;
|
||||
var oldItem = this[index];
|
||||
var newItem = CreateGroupTemplateContext(args.NewItems[0]);
|
||||
Items[index] = newItem;
|
||||
var update = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, newItem, oldItem, index);
|
||||
OnCollectionChanged(update);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we're replacing one set with an equal size set, we can do a soft reset; if not, we have to completely
|
||||
// rebuild the collection
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
Items.Clear();
|
||||
_groupList.Clear();
|
||||
|
||||
foreach (var group in _itemsSource)
|
||||
{
|
||||
var groupTemplateContext = CreateGroupTemplateContext(group);
|
||||
_groupList.Add(group);
|
||||
Items.Add(groupTemplateContext);
|
||||
}
|
||||
|
||||
var reset = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
|
||||
OnCollectionChanged(reset);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
using Windows.UI.Xaml;
|
||||
using System;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Xamarin.Forms.Internals;
|
||||
using WThickness = Windows.UI.Xaml.Thickness;
|
||||
using WSize = Windows.Foundation.Size;
|
||||
|
||||
namespace Xamarin.Forms.Platform.UWP
|
||||
{
|
||||
|
@ -148,39 +150,54 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
InvalidateMeasure();
|
||||
}
|
||||
|
||||
protected override Windows.Foundation.Size MeasureOverride(Windows.Foundation.Size availableSize)
|
||||
protected override WSize MeasureOverride(WSize availableSize)
|
||||
{
|
||||
if (_renderer == null)
|
||||
{
|
||||
return base.MeasureOverride(availableSize);
|
||||
}
|
||||
|
||||
var frameworkElement = Content as FrameworkElement;
|
||||
|
||||
var formsElement = _renderer.Element;
|
||||
if (ItemHeight != default || ItemWidth != default)
|
||||
{
|
||||
formsElement.Layout(new Rectangle(0, 0, ItemWidth, ItemHeight));
|
||||
|
||||
var wsize = new Windows.Foundation.Size(ItemWidth, ItemHeight);
|
||||
var wsize = new WSize(ItemWidth, ItemHeight);
|
||||
|
||||
(Content as FrameworkElement).Margin = new WThickness(ItemSpacing.Left, ItemSpacing.Top, ItemSpacing.Right, ItemSpacing.Bottom);
|
||||
frameworkElement.Margin = new WThickness(ItemSpacing.Left, ItemSpacing.Top, ItemSpacing.Right, ItemSpacing.Bottom);
|
||||
|
||||
(Content as FrameworkElement).Measure(wsize);
|
||||
frameworkElement.Measure(wsize);
|
||||
|
||||
return base.MeasureOverride(wsize);
|
||||
}
|
||||
else
|
||||
{
|
||||
Size request = formsElement.Measure(availableSize.Width, availableSize.Height,
|
||||
MeasureFlags.IncludeMargins).Request;
|
||||
var (width, height) = formsElement.Measure(availableSize.Width, availableSize.Height,
|
||||
MeasureFlags.IncludeMargins).Request;
|
||||
|
||||
formsElement.Layout(new Rectangle(0, 0, request.Width, request.Height));
|
||||
width = Max(width, availableSize.Width);
|
||||
height = Max(height, availableSize.Height);
|
||||
|
||||
var wsize = new Windows.Foundation.Size(request.Width, request.Height);
|
||||
formsElement.Layout(new Rectangle(0, 0, width, height));
|
||||
|
||||
(Content as FrameworkElement).Measure(wsize);
|
||||
var wsize = new WSize(width, height);
|
||||
|
||||
frameworkElement.Measure(wsize);
|
||||
|
||||
return base.MeasureOverride(wsize);
|
||||
}
|
||||
}
|
||||
|
||||
double Max(double requested, double available)
|
||||
{
|
||||
return Math.Max(requested, ClampInfinity(available));
|
||||
}
|
||||
|
||||
double ClampInfinity(double value)
|
||||
{
|
||||
return double.IsInfinity(value) ? 0 : value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,13 @@
|
|||
{
|
||||
internal class ItemTemplateContext
|
||||
{
|
||||
public DataTemplate FormsDataTemplate { get; }
|
||||
public object Item { get; }
|
||||
public BindableObject Container { get; }
|
||||
public double ItemHeight { get; }
|
||||
public double ItemWidth { get; }
|
||||
public Thickness ItemSpacing { get; }
|
||||
|
||||
public ItemTemplateContext(DataTemplate formsDataTemplate, object item, BindableObject container,
|
||||
double? height = null, double? width = null, Thickness? itemSpacing = null)
|
||||
{
|
||||
|
@ -18,12 +25,5 @@
|
|||
if (itemSpacing.HasValue)
|
||||
ItemSpacing = itemSpacing.Value;
|
||||
}
|
||||
|
||||
public DataTemplate FormsDataTemplate { get; }
|
||||
public object Item { get; }
|
||||
public BindableObject Container { get; }
|
||||
public double ItemHeight { get; }
|
||||
public double ItemWidth { get; }
|
||||
public Thickness ItemSpacing { get; }
|
||||
}
|
||||
}
|
|
@ -67,7 +67,7 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
internal class ItemTemplateContextListEnumerator : IEnumerator<ItemTemplateContext>
|
||||
{
|
||||
public ItemTemplateContext Current { get; private set; }
|
||||
object IEnumerator.Current { get; }
|
||||
object IEnumerator.Current => Current;
|
||||
int _currentIndex = -1;
|
||||
private ItemTemplateContextList _itemTemplateContextList;
|
||||
|
||||
|
|
|
@ -1,16 +1,9 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Foundation;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Controls.Primitives;
|
||||
using Windows.UI.Xaml.Data;
|
||||
using Xamarin.Forms.Internals;
|
||||
using Xamarin.Forms.Platform.UAP;
|
||||
using UwpScrollBarVisibility = Windows.UI.Xaml.Controls.ScrollBarVisibility;
|
||||
using UWPApp = Windows.UI.Xaml.Application;
|
||||
using UWPDataTemplate = Windows.UI.Xaml.DataTemplate;
|
||||
|
@ -18,7 +11,8 @@ using System.Collections.Specialized;
|
|||
|
||||
namespace Xamarin.Forms.Platform.UWP
|
||||
{
|
||||
public abstract class ItemsViewRenderer : ViewRenderer<ItemsView, ListViewBase>
|
||||
public abstract class ItemsViewRenderer<TItemsView> : ViewRenderer<TItemsView, ListViewBase>
|
||||
where TItemsView : ItemsView
|
||||
{
|
||||
protected CollectionViewSource CollectionViewSource;
|
||||
|
||||
|
@ -32,9 +26,10 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
FrameworkElement _emptyView;
|
||||
View _formsEmptyView;
|
||||
|
||||
protected TItemsView ItemsView => Element;
|
||||
protected ItemsControl ItemsControl { get; private set; }
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<ItemsView> args)
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<TItemsView> args)
|
||||
{
|
||||
base.OnElementChanged(args);
|
||||
TearDownOldElement(args.OldElement);
|
||||
|
@ -45,30 +40,31 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
{
|
||||
base.OnElementPropertyChanged(sender, changedProperty);
|
||||
|
||||
if (changedProperty.Is(ItemsView.ItemsSourceProperty))
|
||||
if (changedProperty.Is(Xamarin.Forms.ItemsView.ItemsSourceProperty))
|
||||
{
|
||||
UpdateItemsSource();
|
||||
}
|
||||
else if (changedProperty.Is(ItemsView.ItemTemplateProperty))
|
||||
else if (changedProperty.Is(Xamarin.Forms.ItemsView.ItemTemplateProperty))
|
||||
{
|
||||
UpdateItemTemplate();
|
||||
}
|
||||
else if (changedProperty.Is(ItemsView.HorizontalScrollBarVisibilityProperty))
|
||||
else if (changedProperty.Is(Xamarin.Forms.ItemsView.HorizontalScrollBarVisibilityProperty))
|
||||
{
|
||||
UpdateHorizontalScrollBarVisibility();
|
||||
}
|
||||
else if (changedProperty.Is(ItemsView.VerticalScrollBarVisibilityProperty))
|
||||
else if (changedProperty.Is(Xamarin.Forms.ItemsView.VerticalScrollBarVisibilityProperty))
|
||||
{
|
||||
UpdateVerticalScrollBarVisibility();
|
||||
}
|
||||
else if (changedProperty.IsOneOf(ItemsView.EmptyViewProperty, ItemsView.EmptyViewTemplateProperty))
|
||||
else if (changedProperty.IsOneOf(Xamarin.Forms.ItemsView.EmptyViewProperty,
|
||||
Xamarin.Forms.ItemsView.EmptyViewTemplateProperty))
|
||||
{
|
||||
UpdateEmptyView();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract ListViewBase SelectListViewBase();
|
||||
protected abstract void HandleLayoutPropertyChange(PropertyChangedEventArgs property);
|
||||
protected abstract void HandleLayoutPropertyChanged(PropertyChangedEventArgs property);
|
||||
protected abstract IItemsLayout Layout { get; }
|
||||
|
||||
protected virtual void UpdateItemsSource()
|
||||
|
@ -78,7 +74,6 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
return;
|
||||
}
|
||||
|
||||
// TODO hartez 2018-05-22 12:59 PM Handle grouping
|
||||
|
||||
CleanUpCollectionViewSource();
|
||||
|
||||
|
@ -109,7 +104,7 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
}
|
||||
}
|
||||
|
||||
if (Element.ItemsSource == null)
|
||||
if (Element?.ItemsSource == null)
|
||||
{
|
||||
if (CollectionViewSource?.Source is INotifyCollectionChanged incc)
|
||||
{
|
||||
|
@ -167,7 +162,7 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
|
||||
void LayoutPropertyChanged(object sender, PropertyChangedEventArgs property)
|
||||
{
|
||||
HandleLayoutPropertyChange(property);
|
||||
HandleLayoutPropertyChanged(property);
|
||||
}
|
||||
|
||||
protected virtual void SetUpNewElement(ItemsView newElement)
|
||||
|
@ -213,16 +208,15 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
// Stop listening for ScrollTo requests
|
||||
oldElement.ScrollToRequested -= ScrollToRequested;
|
||||
|
||||
if (CollectionViewSource != null)
|
||||
{
|
||||
CleanUpCollectionViewSource();
|
||||
}
|
||||
|
||||
if (ListViewBase != null)
|
||||
{
|
||||
ListViewBase.ItemsSource = null;
|
||||
}
|
||||
|
||||
if (CollectionViewSource != null)
|
||||
{
|
||||
CollectionViewSource.Source = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void UpdateVerticalScrollBarVisibility()
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Xamarin.Forms.Platform.UWP">
|
||||
|
||||
<ItemsPanelTemplate x:Key="HorizontalListItemsPanel">
|
||||
<ItemsStackPanel Orientation="Horizontal" />
|
||||
</ItemsPanelTemplate>
|
||||
|
||||
<ItemsPanelTemplate x:Key="HorizontalListItemsPanel">
|
||||
<ItemsStackPanel Orientation="Horizontal" />
|
||||
</ItemsPanelTemplate>
|
||||
|
||||
<ItemsPanelTemplate x:Key="HorizontalGridItemsPanel">
|
||||
<!-- Yes, this is counterintuitive. Orientation here means "direction we lay out the items until we hit the
|
||||
|
@ -27,6 +27,14 @@
|
|||
</local:ItemContentControl>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="GroupHeaderTemplate">
|
||||
<local:ItemContentControl
|
||||
x:Name="ItemContentControl" DataContext="{Binding HeaderItemTemplateContext}"
|
||||
FormsDataTemplate="{Binding FormsDataTemplate}" FormsDataContext="{Binding Item}"
|
||||
FormsContainer="{Binding Container}">
|
||||
</local:ItemContentControl>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="CarouselItemsViewDefaultTemplate">
|
||||
<local:ItemContentControl
|
||||
x:Name="ItemContentControl"
|
||||
|
@ -79,35 +87,77 @@
|
|||
</Border>
|
||||
</ControlTemplate>
|
||||
|
||||
<ControlTemplate x:Key="FormsGridViewTemplate" TargetType="local:FormsGridView">
|
||||
<Border BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}">
|
||||
<Grid>
|
||||
<ContentControl x:Name="EmptyViewContentControl" Visibility="{TemplateBinding EmptyViewVisibility}"></ContentControl>
|
||||
<ScrollViewer x:Name="ScrollViewer"
|
||||
TabNavigation="{TemplateBinding TabNavigation}"
|
||||
HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}"
|
||||
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
|
||||
IsHorizontalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsHorizontalScrollChainingEnabled}"
|
||||
VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}"
|
||||
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
|
||||
IsVerticalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsVerticalScrollChainingEnabled}"
|
||||
IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}"
|
||||
IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}"
|
||||
ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}"
|
||||
IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}"
|
||||
BringIntoViewOnFocusChange="{TemplateBinding ScrollViewer.BringIntoViewOnFocusChange}"
|
||||
AutomationProperties.AccessibilityView="Raw">
|
||||
<ItemsPresenter Header="{TemplateBinding Header}"
|
||||
HeaderTemplate="{TemplateBinding HeaderTemplate}"
|
||||
HeaderTransitions="{TemplateBinding HeaderTransitions}"
|
||||
Footer="{TemplateBinding Footer}"
|
||||
FooterTemplate="{TemplateBinding FooterTemplate}"
|
||||
FooterTransitions="{TemplateBinding FooterTransitions}"
|
||||
Padding="{TemplateBinding Padding}" />
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
<!-- We much rather just use a ControlTemplate for this the way we do with FormsListView, but unfortunately
|
||||
16299 (and presumably lower) can't find and set the control template. So we use the entire style instead. If we
|
||||
get to a point where we don't have to support these earlier versions, we can replace this style with just the
|
||||
template. (See also FormsGridView.cs) -->
|
||||
<Style TargetType="local:FormsGridView">
|
||||
<Setter Property="Padding" Value="0,0,0,10" />
|
||||
<Setter Property="IsTabStop" Value="False" />
|
||||
<Setter Property="TabNavigation" Value="Once" />
|
||||
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
|
||||
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
|
||||
<Setter Property="ScrollViewer.HorizontalScrollMode" Value="Disabled" />
|
||||
<Setter Property="ScrollViewer.IsHorizontalRailEnabled" Value="False" />
|
||||
<Setter Property="ScrollViewer.VerticalScrollMode" Value="Enabled" />
|
||||
<Setter Property="ScrollViewer.IsVerticalRailEnabled" Value="True" />
|
||||
<Setter Property="ScrollViewer.ZoomMode" Value="Disabled" />
|
||||
<Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="False" />
|
||||
<Setter Property="ScrollViewer.BringIntoViewOnFocusChange" Value="True" />
|
||||
<Setter Property="IsSwipeEnabled" Value="True" />
|
||||
<Setter Property="UseSystemFocusVisuals" Value="True" />
|
||||
<Setter Property="FocusVisualMargin" Value="-2" />
|
||||
<Setter Property="ItemContainerTransitions">
|
||||
<Setter.Value>
|
||||
<TransitionCollection>
|
||||
<AddDeleteThemeTransition />
|
||||
<ContentThemeTransition />
|
||||
<ReorderThemeTransition />
|
||||
<EntranceThemeTransition IsStaggeringEnabled="False" />
|
||||
</TransitionCollection>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="ItemsPanel">
|
||||
<Setter.Value>
|
||||
<ItemsPanelTemplate>
|
||||
<ItemsWrapGrid Orientation="Horizontal" />
|
||||
</ItemsPanelTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="local:FormsGridView">
|
||||
<Border BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}">
|
||||
<Grid>
|
||||
<ContentControl x:Name="EmptyViewContentControl" Visibility="{TemplateBinding EmptyViewVisibility}"></ContentControl>
|
||||
<ScrollViewer x:Name="ScrollViewer"
|
||||
TabNavigation="{TemplateBinding TabNavigation}"
|
||||
HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}"
|
||||
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
|
||||
IsHorizontalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsHorizontalScrollChainingEnabled}"
|
||||
VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}"
|
||||
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
|
||||
IsVerticalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsVerticalScrollChainingEnabled}"
|
||||
IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}"
|
||||
IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}"
|
||||
ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}"
|
||||
IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}"
|
||||
BringIntoViewOnFocusChange="{TemplateBinding ScrollViewer.BringIntoViewOnFocusChange}"
|
||||
AutomationProperties.AccessibilityView="Raw">
|
||||
<ItemsPresenter Header="{TemplateBinding Header}"
|
||||
HeaderTemplate="{TemplateBinding HeaderTemplate}"
|
||||
HeaderTransitions="{TemplateBinding HeaderTransitions}"
|
||||
Footer="{TemplateBinding Footer}"
|
||||
FooterTemplate="{TemplateBinding FooterTemplate}"
|
||||
FooterTransitions="{TemplateBinding FooterTransitions}"
|
||||
Padding="{TemplateBinding Padding}" />
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="HorizontalCarouselListStyle" TargetType="local:FormsListView">
|
||||
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden" />
|
||||
|
@ -142,5 +192,61 @@
|
|||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- Custom version of the style which removes the horizontal rule below the header -->
|
||||
<Style TargetType="ListViewHeaderItem">
|
||||
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
|
||||
<Setter Property="FontSize" Value="{ThemeResource ListViewHeaderItemThemeFontSize}" />
|
||||
<Setter Property="Background" Value="{ThemeResource ListViewHeaderItemBackground}" />
|
||||
<Setter Property="Margin" Value="0,0,0,4" />
|
||||
<Setter Property="Padding" Value="12,8,12,0" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Left" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Top" />
|
||||
<Setter Property="MinHeight" Value="{ThemeResource ListViewHeaderItemMinHeight}" />
|
||||
<Setter Property="UseSystemFocusVisuals" Value="True" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ListViewHeaderItem">
|
||||
<StackPanel Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
|
||||
<ContentPresenter x:Name="ContentPresenter"
|
||||
Margin="{TemplateBinding Padding}"
|
||||
Content="{TemplateBinding Content}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
ContentTransitions="{TemplateBinding ContentTransitions}"
|
||||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
|
||||
</StackPanel>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- Custom version of the style which removes the horizontal rule below the header -->
|
||||
<Style TargetType="GridViewHeaderItem">
|
||||
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
|
||||
<Setter Property="FontSize" Value="{ThemeResource GridViewHeaderItemThemeFontSize}" />
|
||||
<Setter Property="Background" Value="{ThemeResource GridViewHeaderItemBackground}" />
|
||||
<Setter Property="Margin" Value="0,0,0,4" />
|
||||
<Setter Property="Padding" Value="12,8,12,0" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Left" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Top" />
|
||||
<Setter Property="MinHeight" Value="{ThemeResource GridViewHeaderItemMinHeight}" />
|
||||
<Setter Property="UseSystemFocusVisuals" Value="True" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="GridViewHeaderItem">
|
||||
<StackPanel Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
|
||||
<ContentPresenter x:Name="ContentPresenter"
|
||||
Margin="{TemplateBinding Padding}"
|
||||
Content="{TemplateBinding Content}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
ContentTransitions="{TemplateBinding ContentTransitions}"
|
||||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
|
||||
</StackPanel>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
||||
|
||||
|
|
|
@ -5,9 +5,9 @@ using UWPListViewSelectionMode = Windows.UI.Xaml.Controls.ListViewSelectionMode;
|
|||
|
||||
namespace Xamarin.Forms.Platform.UWP
|
||||
{
|
||||
public class SelectableItemsViewRenderer : StructuredItemsViewRenderer
|
||||
public class SelectableItemsViewRenderer<TItemsView> : StructuredItemsViewRenderer<TItemsView>
|
||||
where TItemsView : SelectableItemsView
|
||||
{
|
||||
SelectableItemsView _selectableItemsView;
|
||||
bool _ignoreNativeSelectionChange;
|
||||
|
||||
protected override void TearDownOldElement(ItemsView oldElement)
|
||||
|
@ -19,9 +19,9 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
oldListViewBase.SelectionChanged -= OnNativeSelectionChanged;
|
||||
}
|
||||
|
||||
if (_selectableItemsView != null)
|
||||
if (ItemsView != null)
|
||||
{
|
||||
_selectableItemsView.SelectionChanged -= OnSelectionChanged;
|
||||
ItemsView.SelectionChanged -= OnSelectionChanged;
|
||||
}
|
||||
|
||||
base.TearDownOldElement(oldElement);
|
||||
|
@ -36,11 +36,9 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
return;
|
||||
}
|
||||
|
||||
_selectableItemsView = newElement as SelectableItemsView;
|
||||
|
||||
if (_selectableItemsView != null)
|
||||
if (ItemsView != null)
|
||||
{
|
||||
_selectableItemsView.SelectionChanged += OnSelectionChanged;
|
||||
ItemsView.SelectionChanged += OnSelectionChanged;
|
||||
}
|
||||
|
||||
var newListViewBase = ListViewBase;
|
||||
|
@ -50,7 +48,7 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
newListViewBase.SetBinding(ListViewBase.SelectionModeProperty,
|
||||
new Windows.UI.Xaml.Data.Binding
|
||||
{
|
||||
Source = _selectableItemsView,
|
||||
Source = ItemsView,
|
||||
Path = new Windows.UI.Xaml.PropertyPath("SelectionMode"),
|
||||
Converter = new SelectionModeConvert(),
|
||||
Mode = Windows.UI.Xaml.Data.BindingMode.TwoWay
|
||||
|
@ -67,6 +65,7 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
_ignoreNativeSelectionChange = true;
|
||||
|
||||
base.UpdateItemsSource();
|
||||
UpdateNativeSelection();
|
||||
|
||||
_ignoreNativeSelectionChange = false;
|
||||
}
|
||||
|
@ -80,24 +79,24 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
case UWPListViewSelectionMode.None:
|
||||
break;
|
||||
case UWPListViewSelectionMode.Single:
|
||||
if (_selectableItemsView != null)
|
||||
if (ItemsView != null)
|
||||
{
|
||||
if (_selectableItemsView.SelectedItem == null)
|
||||
if (ItemsView.SelectedItem == null)
|
||||
{
|
||||
ListViewBase.SelectedItem = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
ListViewBase.SelectedItem =
|
||||
ListViewBase.Items.First(item =>
|
||||
ListViewBase.Items.FirstOrDefault(item =>
|
||||
{
|
||||
if (item is ItemTemplateContext itemPair)
|
||||
{
|
||||
return itemPair.Item == _selectableItemsView.SelectedItem;
|
||||
return itemPair.Item == ItemsView.SelectedItem;
|
||||
}
|
||||
else
|
||||
{
|
||||
return item == _selectableItemsView.SelectedItem;
|
||||
return item == ItemsView.SelectedItem;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -108,11 +107,11 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
ListViewBase.SelectedItems.Clear();
|
||||
foreach (var nativeItem in ListViewBase.Items)
|
||||
{
|
||||
if (nativeItem is ItemTemplateContext itemPair && _selectableItemsView.SelectedItems.Contains(itemPair.Item))
|
||||
if (nativeItem is ItemTemplateContext itemPair && ItemsView.SelectedItems.Contains(itemPair.Item))
|
||||
{
|
||||
ListViewBase.SelectedItems.Add(nativeItem);
|
||||
}
|
||||
else if (_selectableItemsView.SelectedItems.Contains(nativeItem))
|
||||
else if (ItemsView.SelectedItems.Contains(nativeItem))
|
||||
{
|
||||
ListViewBase.SelectedItems.Add(nativeItem);
|
||||
}
|
||||
|
@ -155,7 +154,7 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
case UWPListViewSelectionMode.Multiple:
|
||||
selectableItemsView.SelectionChanged -= OnSelectionChanged;
|
||||
|
||||
_selectableItemsView.SelectedItems.Clear();
|
||||
ItemsView.SelectedItems.Clear();
|
||||
var selectedItems =
|
||||
ListViewBase.SelectedItems
|
||||
.Select(a =>
|
||||
|
@ -167,7 +166,7 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
|
||||
foreach (var item in selectedItems)
|
||||
{
|
||||
_selectableItemsView.SelectedItems.Add(item);
|
||||
ItemsView.SelectedItems.Add(item);
|
||||
}
|
||||
|
||||
selectableItemsView.SelectionChanged += OnSelectionChanged;
|
||||
|
|
|
@ -1,22 +1,21 @@
|
|||
using System.ComponentModel;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using UWPApp = Windows.UI.Xaml.Application;
|
||||
using Xamarin.Forms.Platform.UAP;
|
||||
using WScrollMode = Windows.UI.Xaml.Controls.ScrollMode;
|
||||
|
||||
namespace Xamarin.Forms.Platform.UWP
|
||||
{
|
||||
public class StructuredItemsViewRenderer : ItemsViewRenderer
|
||||
public class StructuredItemsViewRenderer<TItemsView> : ItemsViewRenderer<TItemsView>
|
||||
where TItemsView : StructuredItemsView
|
||||
{
|
||||
StructuredItemsView _structuredItemsView;
|
||||
View _currentHeader;
|
||||
View _currentFooter;
|
||||
|
||||
protected override IItemsLayout Layout { get => _structuredItemsView.ItemsLayout; }
|
||||
protected override IItemsLayout Layout { get => ItemsView?.ItemsLayout; }
|
||||
|
||||
protected override void SetUpNewElement(ItemsView newElement)
|
||||
{
|
||||
_structuredItemsView = newElement as StructuredItemsView;
|
||||
|
||||
base.SetUpNewElement(newElement);
|
||||
|
||||
if (newElement == null)
|
||||
|
@ -70,7 +69,7 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
_currentHeader = null;
|
||||
}
|
||||
|
||||
var header = _structuredItemsView.Header;
|
||||
var header = ItemsView.Header;
|
||||
|
||||
switch (header)
|
||||
{
|
||||
|
@ -91,7 +90,7 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
break;
|
||||
|
||||
default:
|
||||
var headerTemplate = _structuredItemsView.HeaderTemplate;
|
||||
var headerTemplate = ItemsView.HeaderTemplate;
|
||||
if (headerTemplate != null)
|
||||
{
|
||||
ListViewBase.HeaderTemplate = ItemsViewTemplate;
|
||||
|
@ -119,7 +118,7 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
_currentFooter = null;
|
||||
}
|
||||
|
||||
var footer = _structuredItemsView.Footer;
|
||||
var footer = ItemsView.Footer;
|
||||
|
||||
switch (footer)
|
||||
{
|
||||
|
@ -140,7 +139,7 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
break;
|
||||
|
||||
default:
|
||||
var footerTemplate = _structuredItemsView.FooterTemplate;
|
||||
var footerTemplate = ItemsView.FooterTemplate;
|
||||
if (footerTemplate != null)
|
||||
{
|
||||
ListViewBase.FooterTemplate = ItemsViewTemplate;
|
||||
|
@ -155,48 +154,35 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
}
|
||||
}
|
||||
|
||||
protected override void HandleLayoutPropertyChange(PropertyChangedEventArgs property)
|
||||
protected override void HandleLayoutPropertyChanged(PropertyChangedEventArgs property)
|
||||
{
|
||||
if (property.Is(GridItemsLayout.SpanProperty))
|
||||
{
|
||||
if (ListViewBase is FormsGridView formsGridView)
|
||||
{
|
||||
formsGridView.MaximumRowsOrColumns = ((GridItemsLayout)Layout).Span;
|
||||
formsGridView.Span = ((GridItemsLayout)Layout).Span;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ListViewBase CreateGridView(GridItemsLayout gridItemsLayout)
|
||||
{
|
||||
var gridView = new FormsGridView();
|
||||
|
||||
if (gridItemsLayout.Orientation == ItemsLayoutOrientation.Horizontal)
|
||||
return new FormsGridView
|
||||
{
|
||||
gridView.UseHorizontalItemsPanel();
|
||||
Orientation = gridItemsLayout.Orientation == ItemsLayoutOrientation.Horizontal
|
||||
? Orientation.Horizontal
|
||||
: Orientation.Vertical,
|
||||
|
||||
// TODO hartez 2018/06/06 12:13:38 Should this logic just be built into FormsGridView?
|
||||
ScrollViewer.SetHorizontalScrollMode(gridView, WScrollMode.Auto);
|
||||
ScrollViewer.SetHorizontalScrollBarVisibility(gridView,
|
||||
Windows.UI.Xaml.Controls.ScrollBarVisibility.Auto);
|
||||
}
|
||||
else
|
||||
{
|
||||
gridView.UseVerticalItemsPanel();
|
||||
}
|
||||
|
||||
gridView.MaximumRowsOrColumns = gridItemsLayout.Span;
|
||||
|
||||
return gridView;
|
||||
Span = gridItemsLayout.Span
|
||||
};
|
||||
}
|
||||
|
||||
static ListViewBase CreateHorizontalListView()
|
||||
{
|
||||
// TODO hartez 2018/06/05 16:18:57 Is there any performance benefit to caching the ItemsPanelTemplate lookup?
|
||||
// TODO hartez 2018/05/29 15:38:04 Make sure the ItemsViewStyles.xaml xbf gets into the nuspec
|
||||
var horizontalListView = new Windows.UI.Xaml.Controls.ListView()
|
||||
{
|
||||
ItemsPanel =
|
||||
(ItemsPanelTemplate)Windows.UI.Xaml.Application.Current.Resources["HorizontalListItemsPanel"]
|
||||
(ItemsPanelTemplate)UWPApp.Current.Resources["HorizontalListItemsPanel"]
|
||||
};
|
||||
|
||||
ScrollViewer.SetHorizontalScrollMode(horizontalListView, WScrollMode.Auto);
|
||||
|
|
|
@ -5,7 +5,8 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
{
|
||||
internal static class TemplatedItemSourceFactory
|
||||
{
|
||||
internal static object Create(IEnumerable itemsSource, DataTemplate itemTemplate, BindableObject container, double? itemHeight = null, double? itemWidth = null, Thickness? itemSpacing = null)
|
||||
internal static object Create(IEnumerable itemsSource, DataTemplate itemTemplate, BindableObject container,
|
||||
double? itemHeight = null, double? itemWidth = null, Thickness? itemSpacing = null)
|
||||
{
|
||||
switch (itemsSource)
|
||||
{
|
||||
|
@ -17,5 +18,11 @@ namespace Xamarin.Forms.Platform.UWP
|
|||
|
||||
return new ItemTemplateContextEnumerable(itemsSource, itemTemplate, container, itemHeight, itemWidth, itemSpacing);
|
||||
}
|
||||
|
||||
internal static object CreateGrouped(IEnumerable itemsSource, DataTemplate itemTemplate,
|
||||
DataTemplate groupHeaderTemplate, DataTemplate groupFooterTemplate, BindableObject container)
|
||||
{
|
||||
return new GroupedItemTemplateCollection(itemsSource, itemTemplate, groupHeaderTemplate, groupFooterTemplate, container);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion>10.0.16299.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.16299.0</TargetPlatformMinVersion>
|
||||
<SkipMicrosoftUIXamlCheckTargetPlatformVersion>true</SkipMicrosoftUIXamlCheckTargetPlatformVersion>
|
||||
<SkipMicrosoftUIXamlCheckTargetPlatformVersion>true</SkipMicrosoftUIXamlCheckTargetPlatformVersion>
|
||||
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
|
@ -47,6 +47,11 @@
|
|||
<Compile Include="CollectionView\ItemsViewRenderer.cs" />
|
||||
<Compile Include="CollectionView\ItemTemplateContextList.cs" />
|
||||
<Compile Include="CollectionView\ScrollHelpers.cs" />
|
||||
<Compile Include="CollectionView\GroupedItemTemplateCollection.cs" />
|
||||
<Compile Include="CollectionView\GroupFooterItemTemplateContext.cs" />
|
||||
<Compile Include="CollectionView\GroupHeaderStyleSelector.cs" />
|
||||
<Compile Include="CollectionView\GroupTemplateContext.cs" />
|
||||
<Compile Include="CollectionView\GroupableItemsViewRenderer.cs" />
|
||||
<Compile Include="CollectionView\SelectableItemsViewRenderer.cs" />
|
||||
<Compile Include="CollectionView\StructuredItemsViewRenderer.cs" />
|
||||
<Compile Include="ColorExtensions.cs" />
|
||||
|
@ -213,6 +218,10 @@
|
|||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="CollectionView\ItemsViewStyles.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="FormsCheckBoxStyle.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
|
@ -234,10 +243,6 @@
|
|||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="CollectionView\ItemsViewStyles.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="MasterDetailControlStyle.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
|
|
@ -7,21 +7,23 @@ using UIKit;
|
|||
|
||||
namespace Xamarin.Forms.Platform.iOS
|
||||
{
|
||||
public class CarouselViewController : ItemsViewController
|
||||
public class CarouselViewController : ItemsViewController<CarouselView>
|
||||
{
|
||||
CarouselView _carouselView;
|
||||
ItemsViewLayout _layout;
|
||||
bool _viewInitialized;
|
||||
|
||||
public CarouselViewController(CarouselView itemsView, ItemsViewLayout layout) : base(itemsView, layout)
|
||||
{
|
||||
_carouselView = itemsView;
|
||||
_layout = layout;
|
||||
Delegator.CarouselViewController = this;
|
||||
CollectionView.AllowsSelection = false;
|
||||
CollectionView.AllowsMultipleSelection = false;
|
||||
}
|
||||
|
||||
protected override UICollectionViewDelegateFlowLayout CreateDelegator()
|
||||
{
|
||||
return new CarouselViewDelegator(ItemsViewLayout, this);
|
||||
}
|
||||
|
||||
public override UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath)
|
||||
{
|
||||
var cell = base.GetCell(collectionView, indexPath);
|
||||
|
@ -60,6 +62,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
protected override void RegisterViewTypes()
|
||||
{
|
||||
CollectionView.RegisterClassForCell(typeof(CarouselTemplatedCell), CarouselTemplatedCell.ReuseId);
|
||||
base.RegisterViewTypes();
|
||||
}
|
||||
|
||||
internal void TearDown()
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
using UIKit;
|
||||
|
||||
namespace Xamarin.Forms.Platform.iOS
|
||||
{
|
||||
public class CarouselViewDelegator : ItemsViewDelegator<CarouselView, CarouselViewController>
|
||||
{
|
||||
public CarouselViewDelegator(ItemsViewLayout itemsViewLayout, CarouselViewController itemsViewController)
|
||||
: base(itemsViewLayout, itemsViewController)
|
||||
{
|
||||
}
|
||||
|
||||
public override void DraggingStarted(UIScrollView scrollView)
|
||||
{
|
||||
ViewController?.DraggingStarted(scrollView);
|
||||
|
||||
PreviousHorizontalOffset = (float)scrollView.ContentOffset.X;
|
||||
PreviousVerticalOffset = (float)scrollView.ContentOffset.Y;
|
||||
}
|
||||
|
||||
public override void DraggingEnded(UIScrollView scrollView, bool willDecelerate)
|
||||
{
|
||||
PreviousHorizontalOffset = 0;
|
||||
PreviousVerticalOffset = 0;
|
||||
|
||||
ViewController?.DraggingEnded(scrollView, willDecelerate);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,20 +2,18 @@
|
|||
|
||||
namespace Xamarin.Forms.Platform.iOS
|
||||
{
|
||||
public class CarouselViewRenderer : ItemsViewRenderer
|
||||
public class CarouselViewRenderer : ItemsViewRenderer<CarouselView, CarouselViewController>
|
||||
{
|
||||
CarouselView CarouselView => (CarouselView)Element;
|
||||
|
||||
CarouselViewController CarouselViewController => (CarouselViewController)ItemsViewController;
|
||||
CarouselView CarouselView => Element;
|
||||
|
||||
public CarouselViewRenderer()
|
||||
{
|
||||
CollectionView.VerifyCollectionViewFlagEnabled(nameof(CarouselViewRenderer));
|
||||
}
|
||||
|
||||
protected override ItemsViewController CreateController(ItemsView newElement, ItemsViewLayout layout)
|
||||
protected override CarouselViewController CreateController(CarouselView newElement, ItemsViewLayout layout)
|
||||
{
|
||||
return new CarouselViewController(newElement as CarouselView, layout);
|
||||
return new CarouselViewController(newElement, layout);
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs changedProperty)
|
||||
|
@ -24,8 +22,8 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
|
||||
if (changedProperty.IsOneOf(CarouselView.PeekAreaInsetsProperty, CarouselView.NumberOfSideItemsProperty))
|
||||
{
|
||||
(CarouselViewController.Layout as CarouselViewLayout).UpdateConstraints(Frame.Size);
|
||||
CarouselViewController.Layout.InvalidateLayout();
|
||||
(Controller.Layout as CarouselViewLayout).UpdateConstraints(Frame.Size);
|
||||
Controller.Layout.InvalidateLayout();
|
||||
}
|
||||
else if (changedProperty.Is(CarouselView.IsSwipeEnabledProperty))
|
||||
UpdateIsSwipeEnabled();
|
||||
|
@ -38,16 +36,16 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
return new CarouselViewLayout(CarouselView.ItemsLayout, CarouselView.ItemSizingStrategy, CarouselView);
|
||||
}
|
||||
|
||||
protected override void SetUpNewElement(ItemsView newElement)
|
||||
protected override void SetUpNewElement(CarouselView newElement)
|
||||
{
|
||||
base.SetUpNewElement(newElement);
|
||||
UpdateIsSwipeEnabled();
|
||||
UpdateIsBounceEnabled();
|
||||
}
|
||||
|
||||
protected override void TearDownOldElement(ItemsView oldElement)
|
||||
protected override void TearDownOldElement(CarouselView oldElement)
|
||||
{
|
||||
CarouselViewController?.TearDown();
|
||||
Controller?.TearDown();
|
||||
base.TearDownOldElement(oldElement);
|
||||
}
|
||||
|
||||
|
@ -56,7 +54,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
if (CarouselView == null)
|
||||
return;
|
||||
|
||||
CarouselViewController.CollectionView.ScrollEnabled = CarouselView.IsSwipeEnabled;
|
||||
Controller.CollectionView.ScrollEnabled = CarouselView.IsSwipeEnabled;
|
||||
}
|
||||
|
||||
void UpdateIsBounceEnabled()
|
||||
|
@ -64,7 +62,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
if (CarouselView == null)
|
||||
return;
|
||||
|
||||
CarouselViewController.CollectionView.Bounces = CarouselView.IsBounceEnabled;
|
||||
Controller.CollectionView.Bounces = CarouselView.IsBounceEnabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace Xamarin.Forms.Platform.iOS
|
||||
{
|
||||
public class CollectionViewRenderer : GroupableItemsViewRenderer { }
|
||||
public class CollectionViewRenderer : GroupableItemsViewRenderer<GroupableItemsView, GroupableItemsViewController<GroupableItemsView>> { }
|
||||
}
|
|
@ -5,28 +5,32 @@ using UIKit;
|
|||
|
||||
namespace Xamarin.Forms.Platform.iOS
|
||||
{
|
||||
public class GroupableItemsViewController : SelectableItemsViewController
|
||||
public class GroupableItemsViewController<TItemsView> : SelectableItemsViewController<TItemsView>
|
||||
where TItemsView : GroupableItemsView
|
||||
{
|
||||
GroupableItemsView GroupableItemsView => (GroupableItemsView)ItemsView;
|
||||
|
||||
// Keep a cached value for the current state of grouping around so we can avoid hitting the
|
||||
// BindableProperty all the time
|
||||
bool _isGrouped;
|
||||
|
||||
Action _scrollAnimationEndedCallback;
|
||||
|
||||
public GroupableItemsViewController(GroupableItemsView groupableItemsView, ItemsViewLayout layout)
|
||||
public GroupableItemsViewController(TItemsView groupableItemsView, ItemsViewLayout layout)
|
||||
: base(groupableItemsView, layout)
|
||||
{
|
||||
_isGrouped = GroupableItemsView.IsGrouped;
|
||||
_isGrouped = ItemsView.IsGrouped;
|
||||
}
|
||||
|
||||
protected override UICollectionViewDelegateFlowLayout CreateDelegator()
|
||||
{
|
||||
return new GroupableItemsViewDelegator<TItemsView, GroupableItemsViewController<TItemsView>>(ItemsViewLayout, this);
|
||||
}
|
||||
|
||||
protected override IItemsViewSource CreateItemsViewSource()
|
||||
{
|
||||
// Use the BindableProperty here (instead of _isGroupingEnabled) because the cached value might not be set yet
|
||||
if (GroupableItemsView.IsGrouped)
|
||||
if (ItemsView.IsGrouped)
|
||||
{
|
||||
return ItemsSourceFactory.CreateGrouped(GroupableItemsView.ItemsSource, CollectionView);
|
||||
return ItemsSourceFactory.CreateGrouped(ItemsView.ItemsSource, CollectionView);
|
||||
}
|
||||
|
||||
return base.CreateItemsViewSource();
|
||||
|
@ -34,7 +38,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
|
||||
public override void UpdateItemsSource()
|
||||
{
|
||||
_isGrouped = GroupableItemsView.IsGrouped;
|
||||
_isGrouped = ItemsView.IsGrouped;
|
||||
base.UpdateItemsSource();
|
||||
}
|
||||
|
||||
|
@ -91,8 +95,8 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
void UpdateTemplatedSupplementaryView(TemplatedCell cell, NSString elementKind, NSIndexPath indexPath)
|
||||
{
|
||||
DataTemplate template = elementKind == UICollectionElementKindSectionKey.Header
|
||||
? GroupableItemsView.GroupHeaderTemplate
|
||||
: GroupableItemsView.GroupFooterTemplate;
|
||||
? ItemsView.GroupHeaderTemplate
|
||||
: ItemsView.GroupFooterTemplate;
|
||||
|
||||
var bindingContext = ItemsSource.Group(indexPath);
|
||||
|
||||
|
@ -108,10 +112,10 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
{
|
||||
if (elementKind == UICollectionElementKindSectionKey.Header)
|
||||
{
|
||||
return DetermineViewReuseId(GroupableItemsView.GroupHeaderTemplate);
|
||||
return DetermineViewReuseId(ItemsView.GroupHeaderTemplate);
|
||||
}
|
||||
|
||||
return DetermineViewReuseId(GroupableItemsView.GroupFooterTemplate);
|
||||
return DetermineViewReuseId(ItemsView.GroupFooterTemplate);
|
||||
}
|
||||
|
||||
string DetermineViewReuseId(DataTemplate template)
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
using CoreGraphics;
|
||||
using UIKit;
|
||||
|
||||
namespace Xamarin.Forms.Platform.iOS
|
||||
{
|
||||
public class GroupableItemsViewDelegator<TItemsView, TViewController> : SelectableItemsViewDelegator<TItemsView, TViewController>
|
||||
where TItemsView : GroupableItemsView
|
||||
where TViewController : GroupableItemsViewController<TItemsView>
|
||||
{
|
||||
public GroupableItemsViewDelegator(ItemsViewLayout itemsViewLayout, TViewController itemsViewController)
|
||||
: base(itemsViewLayout, itemsViewController)
|
||||
{
|
||||
}
|
||||
|
||||
public override CGSize GetReferenceSizeForHeader(UICollectionView collectionView, UICollectionViewLayout layout, nint section)
|
||||
{
|
||||
return ViewController.GetReferenceSizeForHeader(collectionView, layout, section);
|
||||
}
|
||||
|
||||
public override CGSize GetReferenceSizeForFooter(UICollectionView collectionView, UICollectionViewLayout layout, nint section)
|
||||
{
|
||||
return ViewController.GetReferenceSizeForFooter(collectionView, layout, section);
|
||||
}
|
||||
|
||||
public override void ScrollAnimationEnded(UIScrollView scrollView)
|
||||
{
|
||||
ViewController?.HandleScrollAnimationEnded();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,14 +2,13 @@
|
|||
|
||||
namespace Xamarin.Forms.Platform.iOS
|
||||
{
|
||||
public class GroupableItemsViewRenderer : SelectableItemsViewRenderer
|
||||
public class GroupableItemsViewRenderer<TItemsView, TViewController> : SelectableItemsViewRenderer<TItemsView, TViewController>
|
||||
where TItemsView : GroupableItemsView
|
||||
where TViewController : GroupableItemsViewController<TItemsView>
|
||||
{
|
||||
GroupableItemsView GroupableItemsView => (GroupableItemsView)Element;
|
||||
GroupableItemsViewController GroupableItemsViewController => (GroupableItemsViewController)ItemsViewController;
|
||||
|
||||
protected override ItemsViewController CreateController(ItemsView itemsView, ItemsViewLayout layout)
|
||||
protected override TViewController CreateController(TItemsView itemsView, ItemsViewLayout layout)
|
||||
{
|
||||
return new GroupableItemsViewController(itemsView as GroupableItemsView, layout);
|
||||
return new GroupableItemsViewController<TItemsView>(itemsView, layout) as TViewController;
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs changedProperty)
|
||||
|
@ -18,7 +17,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
|
||||
if (changedProperty.Is(GroupableItemsView.IsGroupedProperty))
|
||||
{
|
||||
GroupableItemsViewController?.UpdateItemsSource();
|
||||
Controller?.UpdateItemsSource();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,7 +44,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
{
|
||||
if (args.IsAnimated)
|
||||
{
|
||||
GroupableItemsViewController.SetScrollAnimationEndedCallback(() => base.ScrollToRequested(sender, args));
|
||||
Controller.SetScrollAnimationEndedCallback(() => base.ScrollToRequested(sender, args));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -58,8 +57,8 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
|
||||
bool WillNeedScrollAdjustment(ScrollToRequestEventArgs args)
|
||||
{
|
||||
return GroupableItemsView.ItemSizingStrategy == ItemSizingStrategy.MeasureAllItems
|
||||
&& GroupableItemsView.IsGrouped
|
||||
return ItemsView.ItemSizingStrategy == ItemSizingStrategy.MeasureAllItems
|
||||
&& ItemsView.IsGrouped
|
||||
&& (args.ScrollToPosition == ScrollToPosition.End || args.ScrollToPosition == ScrollToPosition.MakeVisible);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,10 +9,11 @@ using Xamarin.Forms.Internals;
|
|||
namespace Xamarin.Forms.Platform.iOS
|
||||
{
|
||||
// TODO hartez 2018/06/01 14:21:24 Add a method for updating the layout
|
||||
public abstract class ItemsViewController : UICollectionViewController
|
||||
public abstract class ItemsViewController<TItemsView> : UICollectionViewController
|
||||
where TItemsView : ItemsView
|
||||
{
|
||||
public IItemsViewSource ItemsSource { get; protected set; }
|
||||
public ItemsView ItemsView { get; }
|
||||
public TItemsView ItemsView { get; }
|
||||
protected ItemsViewLayout ItemsViewLayout { get; set; }
|
||||
bool _initialConstraintsSet;
|
||||
bool _isEmpty;
|
||||
|
@ -23,9 +24,9 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
UIView _emptyUIView;
|
||||
VisualElement _emptyViewFormsElement;
|
||||
|
||||
protected UICollectionViewDelegator Delegator { get; set; }
|
||||
protected UICollectionViewDelegateFlowLayout Delegator { get; set; }
|
||||
|
||||
public ItemsViewController(ItemsView itemsView, ItemsViewLayout layout) : base(layout)
|
||||
public ItemsViewController(TItemsView itemsView, ItemsViewLayout layout) : base(layout)
|
||||
{
|
||||
ItemsView = itemsView;
|
||||
ItemsSource = CreateItemsViewSource();
|
||||
|
@ -38,8 +39,6 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
ItemsViewLayout = layout;
|
||||
ItemsViewLayout.GetPrototype = GetPrototype;
|
||||
|
||||
// If we're updating from a previous layout, we should keep any settings for the SelectableItemsViewController around
|
||||
var selectableItemsViewController = Delegator?.SelectableItemsViewController;
|
||||
Delegator = CreateDelegator();
|
||||
|
||||
CollectionView.Delegate = Delegator;
|
||||
|
@ -140,13 +139,18 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
if (!_initialConstraintsSet)
|
||||
{
|
||||
ItemsViewLayout.ConstrainTo(CollectionView.Bounds.Size);
|
||||
UpdateEmptyView();
|
||||
_initialConstraintsSet = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ResizeEmptyView();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual UICollectionViewDelegator CreateDelegator()
|
||||
protected virtual UICollectionViewDelegateFlowLayout CreateDelegator()
|
||||
{
|
||||
return new UICollectionViewDelegator(ItemsViewLayout, this);
|
||||
return new ItemsViewDelegator<TItemsView, ItemsViewController<TItemsView>>(ItemsViewLayout, this);
|
||||
}
|
||||
|
||||
protected virtual IItemsViewSource CreateItemsViewSource()
|
||||
|
@ -267,6 +271,15 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
UpdateEmptyViewVisibility(ItemsSource?.ItemCount == 0);
|
||||
}
|
||||
|
||||
void ResizeEmptyView()
|
||||
{
|
||||
if (_emptyUIView != null)
|
||||
_emptyUIView.Frame = CollectionView.Frame;
|
||||
|
||||
if (_emptyViewFormsElement != null)
|
||||
_emptyViewFormsElement.Layout(CollectionView.Frame.ToRectangle());
|
||||
}
|
||||
|
||||
protected void UpdateSubview(object view, DataTemplate viewTemplate, ref UIView uiView, ref VisualElement formsElement)
|
||||
{
|
||||
uiView?.RemoveFromSuperview();
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using CoreGraphics;
|
||||
using Foundation;
|
||||
using UIKit;
|
||||
|
||||
namespace Xamarin.Forms.Platform.iOS
|
||||
{
|
||||
public class ItemsViewDelegator<TItemsView, TViewController> : UICollectionViewDelegateFlowLayout
|
||||
where TItemsView : ItemsView
|
||||
where TViewController : ItemsViewController<TItemsView>
|
||||
{
|
||||
public ItemsViewLayout ItemsViewLayout { get; }
|
||||
public TViewController ViewController { get; }
|
||||
|
||||
protected float PreviousHorizontalOffset, PreviousVerticalOffset;
|
||||
|
||||
public ItemsViewDelegator(ItemsViewLayout itemsViewLayout, TViewController itemsViewController)
|
||||
{
|
||||
ItemsViewLayout = itemsViewLayout;
|
||||
ViewController = itemsViewController;
|
||||
}
|
||||
|
||||
public override void Scrolled(UIScrollView scrollView)
|
||||
{
|
||||
var indexPathsForVisibleItems = ViewController.CollectionView.IndexPathsForVisibleItems.OrderBy(x => x.Row).ToList();
|
||||
|
||||
if (indexPathsForVisibleItems.Count == 0)
|
||||
return;
|
||||
|
||||
var contentInset = scrollView.ContentInset;
|
||||
var contentOffsetX = scrollView.ContentOffset.X + contentInset.Left;
|
||||
var contentOffsetY = scrollView.ContentOffset.Y + contentInset.Top;
|
||||
|
||||
var firstVisibleItemIndex = (int)indexPathsForVisibleItems.First().Item;
|
||||
|
||||
var collectionView = ViewController.CollectionView;
|
||||
var centerPoint = new CGPoint(collectionView.Center.X + collectionView.ContentOffset.X, collectionView.Center.Y + collectionView.ContentOffset.Y);
|
||||
var centerIndexPath = collectionView.IndexPathForItemAtPoint(centerPoint);
|
||||
var centerItemIndex = centerIndexPath?.Row ?? firstVisibleItemIndex;
|
||||
var lastVisibleItemIndex = (int)indexPathsForVisibleItems.Last().Item;
|
||||
var itemsViewScrolledEventArgs = new ItemsViewScrolledEventArgs
|
||||
{
|
||||
HorizontalDelta = contentOffsetX - PreviousHorizontalOffset,
|
||||
VerticalDelta = contentOffsetY - PreviousVerticalOffset,
|
||||
HorizontalOffset = contentOffsetX,
|
||||
VerticalOffset = contentOffsetY,
|
||||
FirstVisibleItemIndex = firstVisibleItemIndex,
|
||||
CenterItemIndex = centerItemIndex,
|
||||
LastVisibleItemIndex = lastVisibleItemIndex
|
||||
};
|
||||
|
||||
var itemsView = ViewController.ItemsView;
|
||||
var source = ViewController.ItemsSource;
|
||||
itemsView.SendScrolled(itemsViewScrolledEventArgs);
|
||||
|
||||
PreviousHorizontalOffset = (float)contentOffsetX;
|
||||
PreviousVerticalOffset = (float)contentOffsetY;
|
||||
|
||||
switch (itemsView.RemainingItemsThreshold)
|
||||
{
|
||||
case -1:
|
||||
return;
|
||||
case 0:
|
||||
if (lastVisibleItemIndex == source.ItemCount - 1)
|
||||
itemsView.SendRemainingItemsThresholdReached();
|
||||
break;
|
||||
default:
|
||||
if (source.ItemCount - 1 - lastVisibleItemIndex <= itemsView.RemainingItemsThreshold)
|
||||
itemsView.SendRemainingItemsThresholdReached();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override UIEdgeInsets GetInsetForSection(UICollectionView collectionView, UICollectionViewLayout layout,
|
||||
nint section)
|
||||
{
|
||||
if (ItemsViewLayout == null)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return ItemsViewLayout.GetInsetForSection(collectionView, layout, section);
|
||||
}
|
||||
|
||||
public override nfloat GetMinimumInteritemSpacingForSection(UICollectionView collectionView,
|
||||
UICollectionViewLayout layout, nint section)
|
||||
{
|
||||
if (ItemsViewLayout == null)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return ItemsViewLayout.GetMinimumInteritemSpacingForSection(collectionView, layout, section);
|
||||
}
|
||||
|
||||
public override nfloat GetMinimumLineSpacingForSection(UICollectionView collectionView,
|
||||
UICollectionViewLayout layout, nint section)
|
||||
{
|
||||
if (ItemsViewLayout == null)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return ItemsViewLayout.GetMinimumLineSpacingForSection(collectionView, layout, section);
|
||||
}
|
||||
|
||||
public override void CellDisplayingEnded(UICollectionView collectionView, UICollectionViewCell cell, NSIndexPath indexPath)
|
||||
{
|
||||
if (ItemsViewLayout.ScrollDirection == UICollectionViewScrollDirection.Horizontal)
|
||||
{
|
||||
var actualWidth = collectionView.ContentSize.Width - collectionView.Bounds.Size.Width;
|
||||
if (collectionView.ContentOffset.X >= actualWidth || collectionView.ContentOffset.X < 0)
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
var actualHeight = collectionView.ContentSize.Height - collectionView.Bounds.Size.Height;
|
||||
|
||||
if (collectionView.ContentOffset.Y >= actualHeight || collectionView.ContentOffset.Y < 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -484,7 +484,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
|
||||
if (ItemsUpdatingScrollMode == ItemsUpdatingScrollMode.KeepLastItemInView)
|
||||
{
|
||||
ForceScrollToLastItem(CollectionView);
|
||||
ForceScrollToLastItem(CollectionView, _itemsLayout);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -551,7 +551,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
return false;
|
||||
}
|
||||
|
||||
static void ForceScrollToLastItem(UICollectionView collectionView)
|
||||
static void ForceScrollToLastItem(UICollectionView collectionView, ItemsLayout itemsLayout)
|
||||
{
|
||||
var sections = (int)collectionView.NumberOfSections();
|
||||
|
||||
|
@ -566,7 +566,12 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
if (itemCount > 0)
|
||||
{
|
||||
var lastIndexPath = NSIndexPath.FromItemSection(itemCount - 1, section);
|
||||
collectionView.ScrollToItem(lastIndexPath, UICollectionViewScrollPosition.Bottom, true);
|
||||
|
||||
if (itemsLayout.Orientation == ItemsLayoutOrientation.Vertical)
|
||||
collectionView.ScrollToItem(lastIndexPath, UICollectionViewScrollPosition.Bottom, true);
|
||||
else
|
||||
collectionView.ScrollToItem(lastIndexPath, UICollectionViewScrollPosition.Right, true);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,28 +4,32 @@ using UIKit;
|
|||
|
||||
namespace Xamarin.Forms.Platform.iOS
|
||||
{
|
||||
public abstract class ItemsViewRenderer : ViewRenderer<ItemsView, UIView>
|
||||
public abstract class ItemsViewRenderer<TItemsView, TViewController> : ViewRenderer<TItemsView, UIView>
|
||||
where TItemsView : ItemsView
|
||||
where TViewController : ItemsViewController<TItemsView>
|
||||
{
|
||||
ItemsViewLayout _layout;
|
||||
bool _disposed;
|
||||
bool? _defaultHorizontalScrollVisibility;
|
||||
bool? _defaultVerticalScrollVisibility;
|
||||
|
||||
protected TItemsView ItemsView => Element;
|
||||
|
||||
public ItemsViewRenderer()
|
||||
{
|
||||
CollectionView.VerifyCollectionViewFlagEnabled(nameof(ItemsViewRenderer));
|
||||
CollectionView.VerifyCollectionViewFlagEnabled(nameof(ItemsViewRenderer<TItemsView, TViewController>));
|
||||
}
|
||||
|
||||
public override UIViewController ViewController => ItemsViewController;
|
||||
public override UIViewController ViewController => Controller;
|
||||
|
||||
protected ItemsViewController ItemsViewController { get; private set; }
|
||||
protected TViewController Controller { get; private set; }
|
||||
|
||||
public override SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint)
|
||||
{
|
||||
return Control.GetSizeRequest(widthConstraint, heightConstraint, 0, 0);
|
||||
}
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<ItemsView> e)
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<TItemsView> e)
|
||||
{
|
||||
TearDownOldElement(e.OldElement);
|
||||
SetUpNewElement(e.NewElement);
|
||||
|
@ -37,27 +41,32 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
{
|
||||
base.OnElementPropertyChanged(sender, changedProperty);
|
||||
|
||||
if (changedProperty.Is(ItemsView.ItemsSourceProperty))
|
||||
if (changedProperty.Is(Xamarin.Forms.ItemsView.ItemsSourceProperty))
|
||||
{
|
||||
ItemsViewController.UpdateItemsSource();
|
||||
UpdateItemsSource();
|
||||
}
|
||||
else if (changedProperty.IsOneOf(ItemsView.EmptyViewProperty, ItemsView.EmptyViewTemplateProperty))
|
||||
else if (changedProperty.Is(Xamarin.Forms.ItemsView.ItemTemplateProperty))
|
||||
{
|
||||
ItemsViewController.UpdateEmptyView();
|
||||
UpdateLayout();
|
||||
}
|
||||
else if (changedProperty.Is(ItemsView.ItemSizingStrategyProperty))
|
||||
else if (changedProperty.IsOneOf(Xamarin.Forms.ItemsView.EmptyViewProperty,
|
||||
Xamarin.Forms.ItemsView.EmptyViewTemplateProperty))
|
||||
{
|
||||
Controller.UpdateEmptyView();
|
||||
}
|
||||
else if (changedProperty.Is(Xamarin.Forms.ItemsView.ItemSizingStrategyProperty))
|
||||
{
|
||||
UpdateItemSizingStrategy();
|
||||
}
|
||||
else if (changedProperty.Is(ItemsView.HorizontalScrollBarVisibilityProperty))
|
||||
else if (changedProperty.Is(Xamarin.Forms.ItemsView.HorizontalScrollBarVisibilityProperty))
|
||||
{
|
||||
UpdateHorizontalScrollBarVisibility();
|
||||
}
|
||||
else if (changedProperty.Is(ItemsView.VerticalScrollBarVisibilityProperty))
|
||||
else if (changedProperty.Is(Xamarin.Forms.ItemsView.VerticalScrollBarVisibilityProperty))
|
||||
{
|
||||
UpdateVerticalScrollBarVisibility();
|
||||
}
|
||||
else if (changedProperty.Is(ItemsView.ItemsUpdatingScrollModeProperty))
|
||||
else if (changedProperty.Is(Xamarin.Forms.ItemsView.ItemsUpdatingScrollModeProperty))
|
||||
{
|
||||
UpdateItemsUpdatingScrollMode();
|
||||
}
|
||||
|
@ -65,7 +74,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
|
||||
protected abstract ItemsViewLayout SelectLayout();
|
||||
|
||||
protected virtual void TearDownOldElement(ItemsView oldElement)
|
||||
protected virtual void TearDownOldElement(TItemsView oldElement)
|
||||
{
|
||||
if (oldElement == null)
|
||||
{
|
||||
|
@ -76,7 +85,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
oldElement.ScrollToRequested -= ScrollToRequested;
|
||||
}
|
||||
|
||||
protected virtual void SetUpNewElement(ItemsView newElement)
|
||||
protected virtual void SetUpNewElement(TItemsView newElement)
|
||||
{
|
||||
if (newElement == null)
|
||||
{
|
||||
|
@ -84,7 +93,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
}
|
||||
|
||||
UpdateLayout();
|
||||
ItemsViewController = CreateController(newElement, _layout);
|
||||
Controller = CreateController(newElement, _layout);
|
||||
|
||||
if (Forms.IsiOS11OrNewer)
|
||||
{
|
||||
|
@ -92,12 +101,11 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
// CollectionView content when we're in landscape mode (to avoid the notch)
|
||||
// The SetUseSafeArea Platform Specific is already taking care of this for us
|
||||
// That said, at some point it's possible folks will want a PS for controlling this behavior
|
||||
ItemsViewController.CollectionView.ContentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentBehavior.Never;
|
||||
Controller.CollectionView.ContentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentBehavior.Never;
|
||||
}
|
||||
|
||||
SetNativeControl(ItemsViewController.View);
|
||||
ItemsViewController.CollectionView.BackgroundColor = UIColor.Clear;
|
||||
ItemsViewController.UpdateEmptyView();
|
||||
SetNativeControl(Controller.View);
|
||||
Controller.CollectionView.BackgroundColor = UIColor.Clear;
|
||||
UpdateHorizontalScrollBarVisibility();
|
||||
UpdateVerticalScrollBarVisibility();
|
||||
|
||||
|
@ -109,9 +117,9 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
{
|
||||
_layout = SelectLayout();
|
||||
|
||||
if (ItemsViewController != null)
|
||||
if (Controller != null)
|
||||
{
|
||||
ItemsViewController.UpdateLayout(_layout);
|
||||
Controller.UpdateLayout(_layout);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,10 +130,15 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
|
||||
protected virtual void UpdateItemsUpdatingScrollMode()
|
||||
{
|
||||
_layout.ItemsUpdatingScrollMode = Element.ItemsUpdatingScrollMode;
|
||||
_layout.ItemsUpdatingScrollMode = ItemsView.ItemsUpdatingScrollMode;
|
||||
}
|
||||
|
||||
protected abstract ItemsViewController CreateController(ItemsView newElement, ItemsViewLayout layout);
|
||||
protected virtual void UpdateItemsSource()
|
||||
{
|
||||
Controller.UpdateItemsSource();
|
||||
}
|
||||
|
||||
protected abstract TViewController CreateController(TItemsView newElement, ItemsViewLayout layout);
|
||||
|
||||
NSIndexPath DetermineIndex(ScrollToRequestEventArgs args)
|
||||
{
|
||||
|
@ -139,24 +152,24 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
return NSIndexPath.Create(args.GroupIndex, args.Index);
|
||||
}
|
||||
|
||||
return ItemsViewController.GetIndexForItem(args.Item);
|
||||
return Controller.GetIndexForItem(args.Item);
|
||||
}
|
||||
|
||||
void UpdateVerticalScrollBarVisibility()
|
||||
{
|
||||
if (_defaultVerticalScrollVisibility == null)
|
||||
_defaultVerticalScrollVisibility = ItemsViewController.CollectionView.ShowsVerticalScrollIndicator;
|
||||
_defaultVerticalScrollVisibility = Controller.CollectionView.ShowsVerticalScrollIndicator;
|
||||
|
||||
switch (Element.VerticalScrollBarVisibility)
|
||||
{
|
||||
case ScrollBarVisibility.Always:
|
||||
ItemsViewController.CollectionView.ShowsVerticalScrollIndicator = true;
|
||||
Controller.CollectionView.ShowsVerticalScrollIndicator = true;
|
||||
break;
|
||||
case ScrollBarVisibility.Never:
|
||||
ItemsViewController.CollectionView.ShowsVerticalScrollIndicator = false;
|
||||
Controller.CollectionView.ShowsVerticalScrollIndicator = false;
|
||||
break;
|
||||
case ScrollBarVisibility.Default:
|
||||
ItemsViewController.CollectionView.ShowsVerticalScrollIndicator = _defaultVerticalScrollVisibility.Value;
|
||||
Controller.CollectionView.ShowsVerticalScrollIndicator = _defaultVerticalScrollVisibility.Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -164,18 +177,18 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
void UpdateHorizontalScrollBarVisibility()
|
||||
{
|
||||
if (_defaultHorizontalScrollVisibility == null)
|
||||
_defaultHorizontalScrollVisibility = ItemsViewController.CollectionView.ShowsHorizontalScrollIndicator;
|
||||
_defaultHorizontalScrollVisibility = Controller.CollectionView.ShowsHorizontalScrollIndicator;
|
||||
|
||||
switch (Element.HorizontalScrollBarVisibility)
|
||||
{
|
||||
case ScrollBarVisibility.Always:
|
||||
ItemsViewController.CollectionView.ShowsHorizontalScrollIndicator = true;
|
||||
Controller.CollectionView.ShowsHorizontalScrollIndicator = true;
|
||||
break;
|
||||
case ScrollBarVisibility.Never:
|
||||
ItemsViewController.CollectionView.ShowsHorizontalScrollIndicator = false;
|
||||
Controller.CollectionView.ShowsHorizontalScrollIndicator = false;
|
||||
break;
|
||||
case ScrollBarVisibility.Default:
|
||||
ItemsViewController.CollectionView.ShowsHorizontalScrollIndicator = _defaultHorizontalScrollVisibility.Value;
|
||||
Controller.CollectionView.ShowsHorizontalScrollIndicator = _defaultHorizontalScrollVisibility.Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -190,7 +203,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
return;
|
||||
}
|
||||
|
||||
ItemsViewController.CollectionView.ScrollToItem(indexPath,
|
||||
Controller.CollectionView.ScrollToItem(indexPath,
|
||||
args.ScrollToPosition.ToCollectionViewScrollPosition(_layout.ScrollDirection), args.IsAnimated);
|
||||
}
|
||||
}
|
||||
|
@ -208,8 +221,8 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
{
|
||||
TearDownOldElement(Element);
|
||||
|
||||
ItemsViewController?.Dispose();
|
||||
ItemsViewController = null;
|
||||
Controller?.Dispose();
|
||||
Controller = null;
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
|
@ -222,7 +235,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
return false;
|
||||
}
|
||||
|
||||
var collectionView = ItemsViewController.CollectionView;
|
||||
var collectionView = Controller.CollectionView;
|
||||
if (indexPath.Section >= collectionView.NumberOfSections())
|
||||
{
|
||||
return false;
|
||||
|
|
|
@ -5,15 +5,19 @@ using UIKit;
|
|||
|
||||
namespace Xamarin.Forms.Platform.iOS
|
||||
{
|
||||
public class SelectableItemsViewController : StructuredItemsViewController
|
||||
public class SelectableItemsViewController<TItemsView> : StructuredItemsViewController<TItemsView>
|
||||
where TItemsView : SelectableItemsView
|
||||
{
|
||||
SelectableItemsView SelectableItemsView => (SelectableItemsView)ItemsView;
|
||||
|
||||
public SelectableItemsViewController(SelectableItemsView selectableItemsView, ItemsViewLayout layout)
|
||||
public SelectableItemsViewController(TItemsView selectableItemsView, ItemsViewLayout layout)
|
||||
: base(selectableItemsView, layout)
|
||||
{
|
||||
}
|
||||
|
||||
protected override UICollectionViewDelegateFlowLayout CreateDelegator()
|
||||
{
|
||||
return new SelectableItemsViewDelegator<TItemsView, SelectableItemsViewController<TItemsView>>(ItemsViewLayout, this);
|
||||
}
|
||||
|
||||
// _Only_ called if the user initiates the selection change; will not be called for programmatic selection
|
||||
public override void ItemSelected(UICollectionView collectionView, NSIndexPath indexPath)
|
||||
{
|
||||
|
@ -30,7 +34,11 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
internal void SelectItem(object selectedItem)
|
||||
{
|
||||
var index = GetIndexForItem(selectedItem);
|
||||
CollectionView.SelectItem(index, true, UICollectionViewScrollPosition.None);
|
||||
|
||||
if (index.Section > -1 && index.Item > -1)
|
||||
{
|
||||
CollectionView.SelectItem(index, true, UICollectionViewScrollPosition.None);
|
||||
}
|
||||
}
|
||||
|
||||
// Called by Forms to clear the native selection
|
||||
|
@ -46,24 +54,24 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
|
||||
void FormsSelectItem(NSIndexPath indexPath)
|
||||
{
|
||||
var mode = SelectableItemsView.SelectionMode;
|
||||
var mode = ItemsView.SelectionMode;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case SelectionMode.None:
|
||||
break;
|
||||
case SelectionMode.Single:
|
||||
SelectableItemsView.SelectedItem = GetItemAtIndex(indexPath);
|
||||
ItemsView.SelectedItem = GetItemAtIndex(indexPath);
|
||||
break;
|
||||
case SelectionMode.Multiple:
|
||||
SelectableItemsView.SelectedItems.Add(GetItemAtIndex(indexPath));
|
||||
ItemsView.SelectedItems.Add(GetItemAtIndex(indexPath));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FormsDeselectItem(NSIndexPath indexPath)
|
||||
{
|
||||
var mode = SelectableItemsView.SelectionMode;
|
||||
var mode = ItemsView.SelectionMode;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
|
@ -72,26 +80,26 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
case SelectionMode.Single:
|
||||
break;
|
||||
case SelectionMode.Multiple:
|
||||
SelectableItemsView.SelectedItems.Remove(GetItemAtIndex(indexPath));
|
||||
ItemsView.SelectedItems.Remove(GetItemAtIndex(indexPath));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
internal void UpdateNativeSelection()
|
||||
{
|
||||
if (SelectableItemsView == null)
|
||||
if (ItemsView == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var mode = SelectableItemsView.SelectionMode;
|
||||
var mode = ItemsView.SelectionMode;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case SelectionMode.None:
|
||||
return;
|
||||
case SelectionMode.Single:
|
||||
var selectedItem = SelectableItemsView.SelectedItem;
|
||||
var selectedItem = ItemsView.SelectedItem;
|
||||
|
||||
if (selectedItem != null)
|
||||
{
|
||||
|
@ -112,7 +120,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
|
||||
internal void UpdateSelectionMode()
|
||||
{
|
||||
var mode = SelectableItemsView.SelectionMode;
|
||||
var mode = ItemsView.SelectionMode;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
|
@ -135,7 +143,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
|
||||
void SynchronizeNativeSelectionWithSelectedItems()
|
||||
{
|
||||
var selectedItems = SelectableItemsView.SelectedItems;
|
||||
var selectedItems = ItemsView.SelectedItems;
|
||||
var selectedIndexPaths = CollectionView.GetIndexPathsForSelectedItems();
|
||||
|
||||
foreach (var path in selectedIndexPaths)
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
using Foundation;
|
||||
using UIKit;
|
||||
|
||||
namespace Xamarin.Forms.Platform.iOS
|
||||
{
|
||||
public class SelectableItemsViewDelegator<TItemsView, TViewController> : ItemsViewDelegator<TItemsView, TViewController>
|
||||
where TItemsView : SelectableItemsView
|
||||
where TViewController : SelectableItemsViewController<TItemsView>
|
||||
{
|
||||
public SelectableItemsViewDelegator(ItemsViewLayout itemsViewLayout, TViewController itemsViewController)
|
||||
: base(itemsViewLayout, itemsViewController)
|
||||
{
|
||||
}
|
||||
|
||||
public override void ItemSelected(UICollectionView collectionView, NSIndexPath indexPath)
|
||||
{
|
||||
ViewController?.ItemSelected(collectionView, indexPath);
|
||||
}
|
||||
|
||||
public override void ItemDeselected(UICollectionView collectionView, NSIndexPath indexPath)
|
||||
{
|
||||
ViewController?.ItemDeselected(collectionView, indexPath);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,14 +3,13 @@ using System.ComponentModel;
|
|||
|
||||
namespace Xamarin.Forms.Platform.iOS
|
||||
{
|
||||
public class SelectableItemsViewRenderer : StructuredItemsViewRenderer
|
||||
public class SelectableItemsViewRenderer<TItemsView, TViewController> : StructuredItemsViewRenderer<TItemsView, TViewController>
|
||||
where TItemsView : SelectableItemsView
|
||||
where TViewController : SelectableItemsViewController<TItemsView>
|
||||
{
|
||||
SelectableItemsView SelectableItemsView => (SelectableItemsView)Element;
|
||||
SelectableItemsViewController SelectableItemsViewController => (SelectableItemsViewController)ItemsViewController;
|
||||
|
||||
protected override ItemsViewController CreateController(ItemsView itemsView, ItemsViewLayout layout)
|
||||
protected override TViewController CreateController(TItemsView itemsView, ItemsViewLayout layout)
|
||||
{
|
||||
return new SelectableItemsViewController(itemsView as SelectableItemsView, layout);
|
||||
return new SelectableItemsViewController<TItemsView>(itemsView, layout) as TViewController;
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs changedProperty)
|
||||
|
@ -19,21 +18,16 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
|
||||
if (changedProperty.IsOneOf(SelectableItemsView.SelectedItemProperty, SelectableItemsView.SelectedItemsProperty))
|
||||
{
|
||||
SelectableItemsViewController.UpdateNativeSelection();
|
||||
UpdateNativeSelection();
|
||||
}
|
||||
else if (changedProperty.Is(SelectableItemsView.SelectionModeProperty))
|
||||
{
|
||||
SelectableItemsViewController.UpdateSelectionMode();
|
||||
UpdateSelectionMode();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void SetUpNewElement(ItemsView newElement)
|
||||
protected override void SetUpNewElement(TItemsView newElement)
|
||||
{
|
||||
if (newElement != null && !(newElement is SelectableItemsView))
|
||||
{
|
||||
throw new ArgumentException($"{nameof(newElement)} must be of type {typeof(SelectableItemsView).Name}");
|
||||
}
|
||||
|
||||
base.SetUpNewElement(newElement);
|
||||
|
||||
if (newElement == null)
|
||||
|
@ -41,8 +35,24 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
return;
|
||||
}
|
||||
|
||||
SelectableItemsViewController.UpdateSelectionMode();
|
||||
SelectableItemsViewController.UpdateNativeSelection();
|
||||
UpdateSelectionMode();
|
||||
UpdateNativeSelection();
|
||||
}
|
||||
|
||||
protected virtual void UpdateNativeSelection()
|
||||
{
|
||||
Controller.UpdateNativeSelection();
|
||||
}
|
||||
|
||||
protected virtual void UpdateSelectionMode()
|
||||
{
|
||||
Controller.UpdateSelectionMode();
|
||||
}
|
||||
|
||||
protected override void UpdateItemsSource()
|
||||
{
|
||||
base.UpdateItemsSource();
|
||||
UpdateNativeSelection();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,19 +3,18 @@ using UIKit;
|
|||
|
||||
namespace Xamarin.Forms.Platform.iOS
|
||||
{
|
||||
public class StructuredItemsViewController : ItemsViewController
|
||||
public class StructuredItemsViewController<TItemsView> : ItemsViewController<TItemsView>
|
||||
where TItemsView : StructuredItemsView
|
||||
{
|
||||
bool _disposed;
|
||||
|
||||
StructuredItemsView StructuredItemsView => (StructuredItemsView)ItemsView;
|
||||
|
||||
UIView _headerUIView;
|
||||
VisualElement _headerViewFormsElement;
|
||||
|
||||
UIView _footerUIView;
|
||||
VisualElement _footerViewFormsElement;
|
||||
|
||||
public StructuredItemsViewController(StructuredItemsView structuredItemsView, ItemsViewLayout layout)
|
||||
public StructuredItemsViewController(TItemsView structuredItemsView, ItemsViewLayout layout)
|
||||
: base(structuredItemsView, layout)
|
||||
{
|
||||
}
|
||||
|
@ -41,7 +40,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
protected override bool IsHorizontal => (StructuredItemsView?.ItemsLayout as ItemsLayout)?.Orientation == ItemsLayoutOrientation.Horizontal;
|
||||
protected override bool IsHorizontal => (ItemsView?.ItemsLayout as ItemsLayout)?.Orientation == ItemsLayoutOrientation.Horizontal;
|
||||
|
||||
public override void ViewWillLayoutSubviews()
|
||||
{
|
||||
|
@ -66,14 +65,14 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
|
||||
internal void UpdateFooterView()
|
||||
{
|
||||
UpdateSubview(StructuredItemsView?.Footer, StructuredItemsView?.FooterTemplate,
|
||||
UpdateSubview(ItemsView?.Footer, ItemsView?.FooterTemplate,
|
||||
ref _footerUIView, ref _footerViewFormsElement);
|
||||
UpdateHeaderFooterPosition();
|
||||
}
|
||||
|
||||
internal void UpdateHeaderView()
|
||||
{
|
||||
UpdateSubview(StructuredItemsView?.Header, StructuredItemsView?.HeaderTemplate,
|
||||
UpdateSubview(ItemsView?.Header, ItemsView?.HeaderTemplate,
|
||||
ref _headerUIView, ref _headerViewFormsElement);
|
||||
UpdateHeaderFooterPosition();
|
||||
}
|
||||
|
|
|
@ -2,14 +2,13 @@
|
|||
|
||||
namespace Xamarin.Forms.Platform.iOS
|
||||
{
|
||||
public class StructuredItemsViewRenderer : ItemsViewRenderer
|
||||
public class StructuredItemsViewRenderer<TItemsView, TViewController> : ItemsViewRenderer<TItemsView, TViewController>
|
||||
where TItemsView : StructuredItemsView
|
||||
where TViewController : StructuredItemsViewController<TItemsView>
|
||||
{
|
||||
StructuredItemsView StructuredItemsView => (StructuredItemsView)Element;
|
||||
StructuredItemsViewController StructuredItemsViewController => (StructuredItemsViewController)ItemsViewController;
|
||||
|
||||
protected override ItemsViewController CreateController(ItemsView itemsView, ItemsViewLayout layout)
|
||||
protected override TViewController CreateController(TItemsView itemsView, ItemsViewLayout layout)
|
||||
{
|
||||
return new StructuredItemsViewController(itemsView as StructuredItemsView, layout);
|
||||
return new StructuredItemsViewController<TItemsView>(itemsView, layout) as TViewController;
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs changedProperty)
|
||||
|
@ -18,19 +17,19 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
|
||||
if (changedProperty.IsOneOf(StructuredItemsView.HeaderProperty, StructuredItemsView.HeaderTemplateProperty))
|
||||
{
|
||||
StructuredItemsViewController.UpdateHeaderView();
|
||||
UpdateHeaderView();
|
||||
}
|
||||
else if (changedProperty.IsOneOf(StructuredItemsView.FooterProperty, StructuredItemsView.FooterTemplateProperty))
|
||||
{
|
||||
StructuredItemsViewController.UpdateFooterView();
|
||||
UpdateFooterView();
|
||||
}
|
||||
else if (changedProperty.Is(StructuredItemsView.ItemsLayoutProperty))
|
||||
{
|
||||
StructuredItemsViewController.UpdateLayout(SelectLayout());
|
||||
UpdateLayout();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void SetUpNewElement(ItemsView newElement)
|
||||
protected override void SetUpNewElement(TItemsView newElement)
|
||||
{
|
||||
base.SetUpNewElement(newElement);
|
||||
|
||||
|
@ -39,14 +38,14 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
return;
|
||||
}
|
||||
|
||||
StructuredItemsViewController.UpdateFooterView();
|
||||
StructuredItemsViewController.UpdateHeaderView();
|
||||
Controller.UpdateFooterView();
|
||||
Controller.UpdateHeaderView();
|
||||
}
|
||||
|
||||
protected override ItemsViewLayout SelectLayout()
|
||||
{
|
||||
var itemSizingStrategy = StructuredItemsView.ItemSizingStrategy;
|
||||
var itemsLayout = StructuredItemsView.ItemsLayout;
|
||||
var itemSizingStrategy = ItemsView.ItemSizingStrategy;
|
||||
var itemsLayout = ItemsView.ItemsLayout;
|
||||
|
||||
if (itemsLayout is GridItemsLayout gridItemsLayout)
|
||||
{
|
||||
|
@ -62,10 +61,20 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
return new ListViewLayout(new LinearItemsLayout(ItemsLayoutOrientation.Vertical), itemSizingStrategy);
|
||||
}
|
||||
|
||||
protected virtual void UpdateHeaderView()
|
||||
{
|
||||
Controller.UpdateHeaderView();
|
||||
}
|
||||
|
||||
protected virtual void UpdateFooterView()
|
||||
{
|
||||
Controller.UpdateFooterView();
|
||||
}
|
||||
|
||||
public override void LayoutSubviews()
|
||||
{
|
||||
base.LayoutSubviews();
|
||||
StructuredItemsViewController.UpdateLayoutMeasurements();
|
||||
Controller.UpdateLayoutMeasurements();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,174 +0,0 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using CoreGraphics;
|
||||
using Foundation;
|
||||
using UIKit;
|
||||
|
||||
namespace Xamarin.Forms.Platform.iOS
|
||||
{
|
||||
public class UICollectionViewDelegator : UICollectionViewDelegateFlowLayout
|
||||
{
|
||||
float _previousHorizontalOffset, _previousVerticalOffset;
|
||||
|
||||
public ItemsViewLayout ItemsViewLayout { get; }
|
||||
public ItemsViewController ItemsViewController { get; }
|
||||
public SelectableItemsViewController SelectableItemsViewController => ItemsViewController as SelectableItemsViewController;
|
||||
|
||||
public GroupableItemsViewController GroupableItemsViewController => ItemsViewController as GroupableItemsViewController;
|
||||
|
||||
public UICollectionViewDelegator(ItemsViewLayout itemsViewLayout, ItemsViewController itemsViewController)
|
||||
{
|
||||
ItemsViewLayout = itemsViewLayout;
|
||||
ItemsViewController = itemsViewController;
|
||||
}
|
||||
public CarouselViewController CarouselViewController { get; set; }
|
||||
|
||||
public override void DraggingStarted(UIScrollView scrollView)
|
||||
{
|
||||
CarouselViewController?.DraggingStarted(scrollView);
|
||||
|
||||
_previousHorizontalOffset = (float)scrollView.ContentOffset.X;
|
||||
_previousVerticalOffset = (float)scrollView.ContentOffset.Y;
|
||||
}
|
||||
|
||||
public override void DraggingEnded(UIScrollView scrollView, bool willDecelerate)
|
||||
{
|
||||
_previousHorizontalOffset = 0;
|
||||
_previousVerticalOffset = 0;
|
||||
|
||||
CarouselViewController?.DraggingEnded(scrollView, willDecelerate);
|
||||
}
|
||||
|
||||
public override void Scrolled(UIScrollView scrollView)
|
||||
{
|
||||
var indexPathsForVisibleItems = ItemsViewController.CollectionView.IndexPathsForVisibleItems.OrderBy(x => x.Row).ToList();
|
||||
|
||||
if (indexPathsForVisibleItems.Count == 0)
|
||||
return;
|
||||
|
||||
var contentInset = scrollView.ContentInset;
|
||||
var contentOffsetX = scrollView.ContentOffset.X + contentInset.Left;
|
||||
var contentOffsetY = scrollView.ContentOffset.Y + contentInset.Top;
|
||||
|
||||
var firstVisibleItemIndex = (int)indexPathsForVisibleItems.First().Item;
|
||||
var centerPoint = new CGPoint(ItemsViewController.CollectionView.Center.X + ItemsViewController.CollectionView.ContentOffset.X, ItemsViewController.CollectionView.Center.Y + ItemsViewController.CollectionView.ContentOffset.Y);
|
||||
var centerIndexPath = ItemsViewController.CollectionView.IndexPathForItemAtPoint(centerPoint);
|
||||
var centerItemIndex = centerIndexPath?.Row ?? firstVisibleItemIndex;
|
||||
var lastVisibleItemIndex = (int)indexPathsForVisibleItems.Last().Item;
|
||||
var itemsViewScrolledEventArgs = new ItemsViewScrolledEventArgs
|
||||
{
|
||||
HorizontalDelta = contentOffsetX - _previousHorizontalOffset,
|
||||
VerticalDelta = contentOffsetY - _previousVerticalOffset,
|
||||
HorizontalOffset = contentOffsetX,
|
||||
VerticalOffset = contentOffsetY,
|
||||
FirstVisibleItemIndex = firstVisibleItemIndex,
|
||||
CenterItemIndex = centerItemIndex,
|
||||
LastVisibleItemIndex = lastVisibleItemIndex
|
||||
};
|
||||
|
||||
ItemsViewController.ItemsView.SendScrolled(itemsViewScrolledEventArgs);
|
||||
|
||||
_previousHorizontalOffset = (float)contentOffsetX;
|
||||
_previousVerticalOffset = (float)contentOffsetY;
|
||||
|
||||
switch (ItemsViewController.ItemsView.RemainingItemsThreshold)
|
||||
{
|
||||
case -1:
|
||||
return;
|
||||
case 0:
|
||||
if (lastVisibleItemIndex == ItemsViewController.ItemsSource.ItemCount - 1)
|
||||
ItemsViewController.ItemsView.SendRemainingItemsThresholdReached();
|
||||
break;
|
||||
default:
|
||||
if (ItemsViewController.ItemsSource.ItemCount - 1 - lastVisibleItemIndex <= ItemsViewController.ItemsView.RemainingItemsThreshold)
|
||||
ItemsViewController.ItemsView.SendRemainingItemsThresholdReached();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override UIEdgeInsets GetInsetForSection(UICollectionView collectionView, UICollectionViewLayout layout,
|
||||
nint section)
|
||||
{
|
||||
if (ItemsViewLayout == null)
|
||||
{
|
||||
return default(UIEdgeInsets);
|
||||
}
|
||||
|
||||
return ItemsViewLayout.GetInsetForSection(collectionView, layout, section);
|
||||
}
|
||||
|
||||
public override nfloat GetMinimumInteritemSpacingForSection(UICollectionView collectionView,
|
||||
UICollectionViewLayout layout, nint section)
|
||||
{
|
||||
if (ItemsViewLayout == null)
|
||||
{
|
||||
return default(nfloat);
|
||||
}
|
||||
|
||||
return ItemsViewLayout.GetMinimumInteritemSpacingForSection(collectionView, layout, section);
|
||||
}
|
||||
|
||||
public override nfloat GetMinimumLineSpacingForSection(UICollectionView collectionView,
|
||||
UICollectionViewLayout layout, nint section)
|
||||
{
|
||||
if (ItemsViewLayout == null)
|
||||
{
|
||||
return default(nfloat);
|
||||
}
|
||||
|
||||
return ItemsViewLayout.GetMinimumLineSpacingForSection(collectionView, layout, section);
|
||||
}
|
||||
|
||||
public override void ItemSelected(UICollectionView collectionView, NSIndexPath indexPath)
|
||||
{
|
||||
SelectableItemsViewController?.ItemSelected(collectionView, indexPath);
|
||||
}
|
||||
|
||||
public override void ItemDeselected(UICollectionView collectionView, NSIndexPath indexPath)
|
||||
{
|
||||
SelectableItemsViewController?.ItemDeselected(collectionView, indexPath);
|
||||
}
|
||||
|
||||
public override void CellDisplayingEnded(UICollectionView collectionView, UICollectionViewCell cell, NSIndexPath indexPath)
|
||||
{
|
||||
if (ItemsViewLayout.ScrollDirection == UICollectionViewScrollDirection.Horizontal)
|
||||
{
|
||||
var actualWidth = collectionView.ContentSize.Width - collectionView.Bounds.Size.Width;
|
||||
if (collectionView.ContentOffset.X >= actualWidth || collectionView.ContentOffset.X < 0)
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
var actualHeight = collectionView.ContentSize.Height - collectionView.Bounds.Size.Height;
|
||||
|
||||
if (collectionView.ContentOffset.Y >= actualHeight || collectionView.ContentOffset.Y < 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public override CGSize GetReferenceSizeForHeader(UICollectionView collectionView, UICollectionViewLayout layout, nint section)
|
||||
{
|
||||
if (GroupableItemsViewController == null)
|
||||
{
|
||||
return CGSize.Empty;
|
||||
}
|
||||
|
||||
return GroupableItemsViewController.GetReferenceSizeForHeader(collectionView, layout, section);
|
||||
}
|
||||
|
||||
public override CGSize GetReferenceSizeForFooter(UICollectionView collectionView, UICollectionViewLayout layout, nint section)
|
||||
{
|
||||
if (GroupableItemsViewController == null)
|
||||
{
|
||||
return CGSize.Empty;
|
||||
}
|
||||
|
||||
return GroupableItemsViewController.GetReferenceSizeForFooter(collectionView, layout, section);
|
||||
}
|
||||
|
||||
public override void ScrollAnimationEnded(UIScrollView scrollView)
|
||||
{
|
||||
GroupableItemsViewController?.HandleScrollAnimationEnded();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -106,10 +106,12 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Extensions\CellExtensions.cs" />
|
||||
<Compile Include="CADisplayLinkTicker.cs" />
|
||||
<Compile Include="CollectionView\CarouselViewDelegator.cs" />
|
||||
<Compile Include="CollectionView\CarouselViewRenderer.cs" />
|
||||
<Compile Include="CollectionView\CollectionViewRenderer.cs" />
|
||||
<Compile Include="CollectionView\EmptySource.cs" />
|
||||
<Compile Include="CollectionView\GroupableItemsViewController.cs" />
|
||||
<Compile Include="CollectionView\GroupableItemsViewDelegator.cs" />
|
||||
<Compile Include="CollectionView\GroupableItemsViewRenderer.cs" />
|
||||
<Compile Include="CollectionView\HorizontalCell.cs" />
|
||||
<Compile Include="CollectionView\HorizontalDefaultSupplementalView.cs" />
|
||||
|
@ -124,9 +126,10 @@
|
|||
<Compile Include="CollectionView\ObservableGroupedSource.cs" />
|
||||
<Compile Include="CollectionView\ScrollToPositionExtensions.cs" />
|
||||
<Compile Include="CollectionView\SelectableItemsViewController.cs" />
|
||||
<Compile Include="CollectionView\SelectableItemsViewDelegator.cs" />
|
||||
<Compile Include="CollectionView\SelectableItemsViewRenderer.cs" />
|
||||
<Compile Include="CollectionView\TemplateHelpers.cs" />
|
||||
<Compile Include="CollectionView\UICollectionViewDelegator.cs" />
|
||||
<Compile Include="CollectionView\ItemsViewDelegator.cs" />
|
||||
<Compile Include="CollectionView\VerticalCell.cs" />
|
||||
<Compile Include="CollectionView\StructuredItemsViewController.cs" />
|
||||
<Compile Include="CollectionView\StructuredItemsViewRenderer.cs" />
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ContentPage
|
||||
xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:local="using:Xamarin.Forms.Xaml.UnitTests"
|
||||
x:Class="Xamarin.Forms.Xaml.UnitTests.Gh7837">
|
||||
<ContentPage.BindingContext>
|
||||
<local:Gh7837VM />
|
||||
</ContentPage.BindingContext>
|
||||
<StackLayout>
|
||||
<Label x:Name="label0" Text="{Binding .[42]}" />
|
||||
<Label x:Name="label1" Text="{Binding .[foo]}" />
|
||||
<Label x:Name="label2" Text="{Binding .[42]}" x:DataType="local:Gh7837VM" />
|
||||
<Label x:Name="label3" Text="{Binding .[foo]}" x:DataType="local:Gh7837VM" />
|
||||
</StackLayout>
|
||||
</ContentPage>
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Core.UnitTests;
|
||||
|
||||
namespace Xamarin.Forms.Xaml.UnitTests
|
||||
{
|
||||
public class Gh7837VMBase //using a base class to test #2131
|
||||
{
|
||||
public string this[int index] => "";
|
||||
public string this[string index] => "";
|
||||
}
|
||||
|
||||
public class Gh7837VM : Gh7837VMBase
|
||||
{
|
||||
public new string this[int index] => index == 42 ? "forty-two" : "dull number";
|
||||
public new string this[string index] => index.ToUpper();
|
||||
}
|
||||
|
||||
public partial class Gh7837 : ContentPage
|
||||
{
|
||||
public Gh7837() => InitializeComponent();
|
||||
public Gh7837(bool useCompiledXaml)
|
||||
{
|
||||
//this stub will be replaced at compile time
|
||||
}
|
||||
|
||||
[TestFixture]
|
||||
class Tests
|
||||
{
|
||||
[SetUp] public void Setup() => Device.PlatformServices = new MockPlatformServices();
|
||||
[TearDown] public void TearDown() => Device.PlatformServices = null;
|
||||
|
||||
[Test]
|
||||
public void BindingWithMultipleIndexers([Values(false, true)]bool useCompiledXaml)
|
||||
{
|
||||
if (useCompiledXaml)
|
||||
MockCompiler.Compile(typeof(Gh7837));
|
||||
var layout = new Gh7837(useCompiledXaml);
|
||||
Assert.That(layout.label0.Text, Is.EqualTo("forty-two"));
|
||||
Assert.That(layout.label1.Text, Is.EqualTo("FOO"));
|
||||
Assert.That(layout.label2.Text, Is.EqualTo("forty-two"));
|
||||
Assert.That(layout.label3.Text, Is.EqualTo("FOO"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,8 +35,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
|
|||
BuildEngine = new MSBuild.UnitTests.DummyBuildEngine()
|
||||
};
|
||||
|
||||
IList<Exception> exceptions;
|
||||
if (xamlc.Execute(out exceptions) || exceptions == null || !exceptions.Any()) {
|
||||
if (xamlc.Execute(out IList<Exception> exceptions) || exceptions == null || !exceptions.Any()) {
|
||||
methdoDefinition = xamlc.InitCompForType;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ jobs:
|
|||
displayName: Build Windows Phase
|
||||
vmImage: $(winVmImage)
|
||||
targetFolder: Xamarin.Forms.ControlGallery.Android/legacyRenderers/
|
||||
msbuildExtraArguments: '/nowarn:VSX1000 /p:CreateAllAndroidTargets=true /bl:$(Build.ArtifactStagingDirectory)\win.binlog'
|
||||
msbuildExtraArguments: '/nowarn:VSX1000 /p:CreateAllAndroidTargets=true'
|
||||
buildConfiguration: $(DefaultBuildConfiguration)
|
||||
buildPlatform: $(DefaultBuildPlatform)
|
||||
provisionatorPath : 'build/provisioning/provisioning.csx'
|
||||
|
|
43
build.cake
43
build.cake
|
@ -51,9 +51,9 @@ string monoMajorVersion = "5.18.1";
|
|||
string monoPatchVersion = "28";
|
||||
string monoVersion = $"{monoMajorVersion}.{monoPatchVersion}";
|
||||
|
||||
string monoSDK_windows = $"https://download.mono-project.com/archive/{monoMajorVersion}/windows-installer/mono-{monoVersion}-x64-0.msi";
|
||||
string androidSDK_windows = "https://aka.ms/xamarin-android-commercial-d15-9-windows";
|
||||
string iOSSDK_windows = "https://download.visualstudio.microsoft.com/download/pr/71f33151-5db4-49cc-ac70-ba835a9f81e2/d256c6c50cd80ec0207783c5c7a4bc2f/xamarin.visualstudio.apple.sdk.4.12.3.83.vsix";
|
||||
string monoSDK_windows = "";//$"https://download.mono-project.com/archive/{monoMajorVersion}/windows-installer/mono-{monoVersion}-x64-0.msi";
|
||||
string androidSDK_windows = "";//"https://aka.ms/xamarin-android-commercial-d15-9-windows";
|
||||
string iOSSDK_windows = "";//"https://download.visualstudio.microsoft.com/download/pr/71f33151-5db4-49cc-ac70-ba835a9f81e2/d256c6c50cd80ec0207783c5c7a4bc2f/xamarin.visualstudio.apple.sdk.4.12.3.83.vsix";
|
||||
string macSDK_windows = "";
|
||||
|
||||
monoMajorVersion = "6.4.0";
|
||||
|
@ -67,7 +67,7 @@ string macSDK_macos = $"https://bosstoragemirror.blob.core.windows.net/wrench/je
|
|||
|
||||
string androidSDK = IsRunningOnWindows() ? androidSDK_windows : androidSDK_macos;
|
||||
string monoSDK = IsRunningOnWindows() ? monoSDK_windows : monoSDK_macos;
|
||||
string iosSDK = IsRunningOnWindows() ? "" : iOSSDK_macos;
|
||||
string iosSDK = IsRunningOnWindows() ? iOSSDK_windows : iOSSDK_macos;
|
||||
string macSDK = IsRunningOnWindows() ? "" : macSDK_macos;
|
||||
|
||||
string[] androidSdkManagerInstalls = new string[0]; //new [] { "platforms;android-29"};
|
||||
|
@ -77,6 +77,7 @@ string[] androidSdkManagerInstalls = new string[0]; //new [] { "platforms;androi
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
Task("Clean")
|
||||
.Description("Deletes all the obj/bin directories")
|
||||
.Does(() =>
|
||||
{
|
||||
CleanDirectories("./**/obj", (fsi)=> !fsi.Path.FullPath.Contains("XFCorePostProcessor") && !fsi.Path.FullPath.StartsWith("tools"));
|
||||
|
@ -84,6 +85,7 @@ Task("Clean")
|
|||
});
|
||||
|
||||
Task("provision-macsdk")
|
||||
.Description("Install Xamarin.Mac SDK")
|
||||
.Does(async () =>
|
||||
{
|
||||
if(!IsRunningOnWindows() && !String.IsNullOrWhiteSpace(macSDK))
|
||||
|
@ -93,16 +95,15 @@ Task("provision-macsdk")
|
|||
});
|
||||
|
||||
Task("provision-iossdk")
|
||||
.Description("Install Xamarin.iOS SDK")
|
||||
.Does(async () =>
|
||||
{
|
||||
if(!IsRunningOnWindows())
|
||||
{
|
||||
if(!String.IsNullOrWhiteSpace(iosSDK))
|
||||
await Boots(iosSDK);
|
||||
}
|
||||
if(!String.IsNullOrWhiteSpace(iosSDK))
|
||||
await Boots(iosSDK);
|
||||
});
|
||||
|
||||
Task("provision-androidsdk")
|
||||
.Description("Install Xamarin.Android SDK")
|
||||
.Does(async () =>
|
||||
{
|
||||
Information ("ANDROID_HOME: {0}", ANDROID_HOME);
|
||||
|
@ -123,6 +124,7 @@ Task("provision-androidsdk")
|
|||
});
|
||||
|
||||
Task("provision-monosdk")
|
||||
.Description("Install Mono SDK")
|
||||
.Does(async () =>
|
||||
{
|
||||
if(IsRunningOnWindows())
|
||||
|
@ -155,17 +157,20 @@ Task("provision-monosdk")
|
|||
});
|
||||
|
||||
Task("provision")
|
||||
.Description("Install SDKs required to build project")
|
||||
.IsDependentOn("provision-macsdk")
|
||||
.IsDependentOn("provision-iossdk")
|
||||
.IsDependentOn("provision-monosdk")
|
||||
.IsDependentOn("provision-androidsdk");
|
||||
|
||||
Task("NuGetPack")
|
||||
.Description("Build and Create Nugets")
|
||||
.IsDependentOn("Build")
|
||||
.IsDependentOn("_NuGetPack");
|
||||
|
||||
|
||||
Task("_NuGetPack")
|
||||
.Description("Create Nugets without building anything")
|
||||
.Does(() =>
|
||||
{
|
||||
var nugetVersionFile =
|
||||
|
@ -192,6 +197,7 @@ Task("_NuGetPack")
|
|||
|
||||
|
||||
Task("Restore")
|
||||
.Description("Restore target on Xamarin.Forms.sln")
|
||||
.Does(() =>
|
||||
{
|
||||
try{
|
||||
|
@ -204,20 +210,9 @@ Task("Restore")
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
Task("BuildHack")
|
||||
.IsDependentOn("Restore")
|
||||
.Does(() =>
|
||||
{
|
||||
if(!IsRunningOnWindows())
|
||||
{
|
||||
MSBuild("./Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj", GetMSBuildSettings().WithRestore());
|
||||
}
|
||||
});
|
||||
|
||||
Task("Build")
|
||||
.Description("Builds all necessary projects to create Nuget Packages")
|
||||
.IsDependentOn("Restore")
|
||||
.IsDependentOn("BuildHack")
|
||||
.IsDependentOn("Android81")
|
||||
.Does(() =>
|
||||
{
|
||||
|
@ -232,7 +227,7 @@ Task("Build")
|
|||
});
|
||||
|
||||
Task("Android81")
|
||||
.IsDependentOn("BuildHack")
|
||||
.Description("Builds Monodroid81 targets")
|
||||
.Does(() =>
|
||||
{
|
||||
string[] androidProjects =
|
||||
|
@ -252,7 +247,7 @@ Task("Android81")
|
|||
});
|
||||
|
||||
Task("VSMAC")
|
||||
.IsDependentOn("BuildHack")
|
||||
.Description("Builds projects necessary so solution compiles on VSMAC")
|
||||
.Does(() =>
|
||||
{
|
||||
StartProcess("open", new ProcessSettings{ Arguments = "Xamarin.Forms.sln" });
|
||||
|
@ -274,7 +269,7 @@ Task("DeployiOS")
|
|||
});
|
||||
*/
|
||||
Task("DeployAndroid")
|
||||
.IsDependentOn("BuildHack")
|
||||
.Description("Builds and deploy Android Control Gallery")
|
||||
.Does(() =>
|
||||
{
|
||||
MSBuild("./Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj", GetMSBuildSettings().WithRestore());
|
||||
|
|
|
@ -73,7 +73,7 @@ jobs:
|
|||
solution: ${{ parameters.slnPath }}
|
||||
platform: '$(BuildPlatform)'
|
||||
configuration: '$(BuildConfiguration)'
|
||||
msbuildArguments: ${{ parameters.msbuildExtraArguments }} /p:JavaSdkDirectory="$(JAVA_HOME_8_X64)"
|
||||
msbuildArguments: ${{ parameters.msbuildExtraArguments }} /p:JavaSdkDirectory="$(JAVA_HOME_8_X64)" /bl:$(Build.ArtifactStagingDirectory)\win-$(BuildConfiguration).binlog
|
||||
|
||||
- task: VSTest@2
|
||||
displayName: 'Unit Tests'
|
||||
|
|
Загрузка…
Ссылка в новой задаче