[Android] Context actions menu is now updated when changing cells. (#6460) fixes #1455 fixes #4041

* Bugfix of issue 1455. Force SupportActionMode Menu to recreate when it's active and another cell is clicked.

* Added UITest

* Added an assert which checks if the new menu items have been updated.

* Correct project file

* Added a platform specific BindableProperty for the ViewCell to use ContextActions in LegacyMode.

* Update Xamarin.Forms.Core/PlatformConfiguration/AndroidSpecific/ViewCell.cs

Co-Authored-By: Gerald Versluis <github@geraldversluis.nl>

* Update Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue1455.xaml.cs

Co-Authored-By: Gerald Versluis <github@geraldversluis.nl>

* Update Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems

Co-Authored-By: Gerald Versluis <github@geraldversluis.nl>
This commit is contained in:
Guido Neele 2019-08-22 13:23:55 +02:00 коммит произвёл Rui Marinho
Родитель 61fadc4769
Коммит 1407f09603
8 изменённых файлов: 269 добавлений и 4 удалений

3
.gitignore поставляемый
Просмотреть файл

@ -67,4 +67,5 @@ tools/
!tools/mdoc/**/*
caketools/
*.binlog
.ionide/**
.ionide/**
/.nuspec

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

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8" ?>
<controls:TestContentPage x:Class="Xamarin.Forms.Controls.Issues.Issue1455"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
xmlns:controls="clr-namespace:Xamarin.Forms.Controls"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:local="clr-namespace:Xamarin.Forms.Controls.Issues"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Name="Issue1455Page"
mc:Ignorable="d">
<controls:TestContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="Temp1">
<ViewCell android:ViewCell.IsContextActionsLegacyModeEnabled="{Binding BindingContext.IsContextActionsLegacyModeEnabled, Source={x:Reference Issue1455Page}}}">
<ViewCell.ContextActions>
<MenuItem Text="{Binding Item1Text}" />
<MenuItem Text="{Binding Item2Text}" />
<MenuItem Text="{Binding Item3Text}" />
<MenuItem Text="{Binding Item4Text}" />
</ViewCell.ContextActions>
<Grid>
<Label Text="{Binding Text}" />
</Grid>
</ViewCell>
</DataTemplate>
<DataTemplate x:Key="Temp2">
<ViewCell android:ViewCell.IsContextActionsLegacyModeEnabled="{Binding BindingContext.IsContextActionsLegacyModeEnabled, Source={x:Reference Issue1455Page}}}">
<ViewCell.ContextActions>
<MenuItem Text="{Binding Item1Text}" />
<MenuItem Text="{Binding Item2Text}" />
</ViewCell.ContextActions>
<Grid>
<Label Text="{Binding Text}" />
</Grid>
</ViewCell>
</DataTemplate>
<local:Issue1455DataTemplateSelector x:Key="Issue1455DataTemplateSelector"
Temp1Template="{StaticResource Temp1}"
Temp2Template="{StaticResource Temp2}" />
</ResourceDictionary>
</controls:TestContentPage.Resources>
<controls:TestContentPage.ToolbarItems>
<ToolbarItem Command="{Binding ToggleLegacyMode}" Text="Toggle LegacyMode" />
</controls:TestContentPage.ToolbarItems>
<controls:TestContentPage.Content>
<ListView HorizontalOptions="FillAndExpand"
ItemTemplate="{StaticResource Issue1455DataTemplateSelector}"
ItemsSource="{Binding Items}"
VerticalOptions="FillAndExpand" />
</controls:TestContentPage.Content>
</controls:TestContentPage>

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

@ -0,0 +1,158 @@
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.CustomAttributes;
using Xamarin.Forms.Internals;
using Xamarin.Forms.Xaml;
using System.Windows.Input;
#if UITEST
using Xamarin.UITest.Queries;
using NUnit.Framework;
#endif
namespace Xamarin.Forms.Controls.Issues
{
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 1455, "Context action are not changed when selected item changed on Android", PlatformAffected.Android)]
public partial class Issue1455 : TestContentPage
{
public Issue1455()
{
#if APP
InitializeComponent();
#endif
}
MyViewModel ViewModel
{
get {
return (MyViewModel)BindingContext;
}
}
protected override void Init()
{
BindingContext = new MyViewModel();
}
[Preserve(AllMembers = true)]
public class MyViewModel : PropertyChangedBase
{
bool _isContextActionsLegacyModeEnabled;
public bool IsContextActionsLegacyModeEnabled
{
get
{
return _isContextActionsLegacyModeEnabled;
}
set
{
_isContextActionsLegacyModeEnabled = value;
OnPropertyChanged();
}
}
public ICommand ToggleLegacyMode { get; }
public ObservableCollection<ContextMenuItem> Items { get; private set; }
public MyViewModel()
{
IsContextActionsLegacyModeEnabled = false;
ToggleLegacyMode = new Command(() => IsContextActionsLegacyModeEnabled = !IsContextActionsLegacyModeEnabled);
Items = new ObservableCollection<ContextMenuItem>();
Items.Add(new ContextMenuItem { Item1Text = "Lorem", Text = "Cell 1", Type = ContextMenuItemType.Temp1 });
Items.Add(new ContextMenuItem { Item2Text = "Ipsum", Text = "Cell 2", Type = ContextMenuItemType.Temp2 });
Items.Add(new ContextMenuItem { Item1Text = "Dictum", Text = "Cell 3", Type = ContextMenuItemType.Temp1 });
Items.Add(new ContextMenuItem { Item2Text = "Vestibulum", Text = "Cell 4", Type = ContextMenuItemType.Temp2 });
Items.Add(new ContextMenuItem { Item1Text = "Hendrerit", Text = "Cell 5", Type = ContextMenuItemType.Temp1 });
Items.Add(new ContextMenuItem { Item2Text = "Posuere", Text = "Cell 6", Type = ContextMenuItemType.Temp2 });
Items.Add(new ContextMenuItem { Item1Text = "Bibendum", Text = "Cell 7", Type = ContextMenuItemType.Temp1 });
Items.Add(new ContextMenuItem { Item2Text = "Vivamus", Text = "Cell 8", Type = ContextMenuItemType.Temp2 });
Items.Add(new ContextMenuItem { Item1Text = "Enim", Text = "Cell 9", Type = ContextMenuItemType.Temp1 });
Items.Add(new ContextMenuItem { Item2Text = "Quis", Text = "Cell 10", Type = ContextMenuItemType.Temp2 });
Items.Add(new ContextMenuItem { Item1Text = "Phasellus", Text = "Cell 11", Type = ContextMenuItemType.Temp1 });
Items.Add(new ContextMenuItem { Item2Text = "Pretium", Text = "Cell 12", Type = ContextMenuItemType.Temp2 });
Items.Add(new ContextMenuItem { Item1Text = "Aliquam", Text = "Cell 13", Type = ContextMenuItemType.Temp1 });
Items.Add(new ContextMenuItem { Item2Text = "Tristique", Text = "Cell 14", Type = ContextMenuItemType.Temp2 });
Items.Add(new ContextMenuItem { Item1Text = "Malesuada", Text = "Cell 15", Type = ContextMenuItemType.Temp1 });
Items.Add(new ContextMenuItem { Item2Text = "Dolor", Text = "Cell 16", Type = ContextMenuItemType.Temp2 });
Items.Add(new ContextMenuItem { Item1Text = "Id", Text = "Cell 17", Type = ContextMenuItemType.Temp1 });
Items.Add(new ContextMenuItem { Item2Text = "Orci", Text = "Cell 18", Type = ContextMenuItemType.Temp2 });
Items.Add(new ContextMenuItem { Item1Text = "Diam", Text = "Cell 19", Type = ContextMenuItemType.Temp1 });
Items.Add(new ContextMenuItem { Item2Text = "Nibh", Text = "Cell 20", Type = ContextMenuItemType.Temp2 });
Items.Add(new ContextMenuItem { Item1Text = "Non", Text = "Cell 21", Type = ContextMenuItemType.Temp1 });
Items.Add(new ContextMenuItem { Item2Text = "Aliquam", Text = "Cell 22", Type = ContextMenuItemType.Temp2 });
Items.Add(new ContextMenuItem { Item1Text = "Ultrices", Text = "Cell 23", Type = ContextMenuItemType.Temp1 });
Items.Add(new ContextMenuItem { Item2Text = "Vulputate", Text = "Cell 24", Type = ContextMenuItemType.Temp2 });
}
}
#if UITEST && __ANDROID__
[Test]
[Category(Core.UITests.UITestCategories.ListView)]
public void RefreshContextActions()
{
RunningApp.WaitForElement("Cell 1");
RunningApp.Screenshot("I am at Issue 1455");
RunningApp.TouchAndHold(q => q.Marked("Cell 4"));
RunningApp.Screenshot("Long Press Cell 4 to show context actions");
RunningApp.Tap(q => q.Marked("Cell 5"));
RunningApp.Screenshot("Clicked another cell and changed menu items");
Assert.AreEqual(1, RunningApp.Query(c => c.Marked("Hendrerit")).Length);
RunningApp.Back();
RunningApp.WaitForElement("Toggle LegacyMode");
RunningApp.Tap(q => q.Marked("Toggle LegacyMode"));
RunningApp.TouchAndHold(q => q.Marked("Cell 4"));
RunningApp.Screenshot("Long Press Cell 4 to show context actions");
RunningApp.Tap(q => q.Marked("Cell 5"));
RunningApp.Screenshot("Clicked another cell and changed menu items");
Assert.AreEqual(1, RunningApp.Query(c => c.Marked("Vestibulum")).Length);
}
#endif
}
public enum ContextMenuItemType
{
Temp1,
Temp2
}
[Preserve(AllMembers = true)]
public class ContextMenuItem
{
public ContextMenuItemType Type { get; set; } = ContextMenuItemType.Temp1;
public string Item1Text { get; set; } = "Text 1";
public string Item2Text { get; set; } = "Text 2";
public string Item3Text { get; set; } = "Text 3";
public string Item4Text { get; set; } = "Text 4";
public string Text { get; set; }
}
[Preserve(AllMembers = true)]
public class Issue1455DataTemplateSelector : DataTemplateSelector
{
public DataTemplate Temp1Template { get; set; }
public DataTemplate Temp2Template { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
return ((ContextMenuItem)item).Type == ContextMenuItemType.Temp1 ? Temp1Template : Temp2Template;
}
}
}

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

@ -9,6 +9,10 @@
<Import_RootNamespace>Xamarin.Forms.Controls.Issues</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)Issue1455.xaml.cs">
<DependentUpon>Issue1455.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)CollectionViewHeaderFooterString.cs" />
<Compile Include="$(MSBuildThisFileDirectory)CollectionViewHeaderFooterTemplate.cs" />
<Compile Include="$(MSBuildThisFileDirectory)CollectionViewHeaderFooterView.cs" />
@ -16,7 +20,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Issue3475.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue6945.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue5046.xaml.cs">
<DependentUpon>Issue5046.xaml</DependentUpon>
<DependentUpon>Issue5046.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Issue6609.cs" />
@ -1333,6 +1337,10 @@
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue1455.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</EmbeddedResource>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue5268.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>

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

@ -82,6 +82,8 @@ namespace Xamarin.Forms
get { return _contextActions != null && _contextActions.Count > 0 && IsEnabled; }
}
public bool IsContextActionsLegacyModeEnabled { get; set; } = false;
public double Height
{
get { return _height; }

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

@ -0,0 +1,37 @@
namespace Xamarin.Forms.PlatformConfiguration.AndroidSpecific
{
using System;
using FormsCell = Forms.Cell;
public static class ViewCell
{
public static readonly BindableProperty IsContextActionsLegacyModeEnabledProperty = BindableProperty.Create("IsContextActionsLegacyModeEnabled", typeof(bool), typeof(Forms.ViewCell), false, propertyChanged: OnIsContextActionsLegacyModeEnabledPropertyChanged);
private static void OnIsContextActionsLegacyModeEnabledPropertyChanged(BindableObject element, object oldValue, object newValue)
{
var cell = element as FormsCell;
cell.IsContextActionsLegacyModeEnabled = (bool)newValue;
}
public static bool GetIsContextActionsLegacyModeEnabled(BindableObject element)
{
return (bool)element.GetValue(IsContextActionsLegacyModeEnabledProperty);
}
public static void SetIsContextActionsLegacyModeEnabled(BindableObject element, bool value)
{
element.SetValue(IsContextActionsLegacyModeEnabledProperty, value);
}
public static bool GetIsContextActionsLegacyModeEnabled(this IPlatformElementConfiguration<Android, FormsCell> config)
{
return GetIsContextActionsLegacyModeEnabled(config.Element);
}
public static IPlatformElementConfiguration<Android, FormsCell> SetIsContextActionsLegacyModeEnabled(this IPlatformElementConfiguration<Android, FormsCell> config, bool value)
{
SetIsContextActionsLegacyModeEnabled(config.Element, value);
return config;
}
}
}

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

@ -193,7 +193,7 @@ namespace Xamarin.Forms.Platform.Android
{
MenuItem action = ActionModeContext.ContextActions[i];
IMenuItem item = menu.Add(global::Android.Views.Menu.None, i,global::Android.Views.Menu.None, action.Text);
IMenuItem item = menu.Add(global::Android.Views.Menu.None, i, global::Android.Views.Menu.None, action.Text);
_ = _context.ApplyDrawableAsync(action, MenuItem.IconImageSourceProperty, iconDrawable =>
{
@ -235,7 +235,10 @@ namespace Xamarin.Forms.Platform.Android
ActionModeContext = cell;
_actionMode?.Invalidate();
if(ActionModeContext.IsContextActionsLegacyModeEnabled == false)
_actionModeNeedsUpdates = true;
_actionMode?.Invalidate();
_supportActionMode?.Invalidate();
}
else

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

@ -5,6 +5,7 @@ using Xamarin.Forms.Internals;
using System;
using System.Linq;
using Android.Runtime;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
namespace Xamarin.Forms.Platform.Android
{
@ -31,6 +32,8 @@ namespace Xamarin.Forms.Platform.Android
}
else if (ParentView is ListView)
{
cell.IsContextActionsLegacyModeEnabled = item.On<PlatformConfiguration.Android>().GetIsContextActionsLegacyModeEnabled();
unevenRows = ListView.HasUnevenRowsProperty;
rowHeight = ListView.RowHeightProperty;
}