Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

Add new xplat event to to propagate FlyoutItemsChanged events to the platforms #13195

Merged
merged 5 commits into from
Dec 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;


#if UITEST
using Xamarin.UITest;
using NUnit.Framework;
using Xamarin.Forms.Core.UITests;
#endif

namespace Xamarin.Forms.Controls.Issues
{
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 11214, "When adding FlyoutItems during Navigating only first one is shown",
PlatformAffected.iOS)]
#if UITEST
[NUnit.Framework.Category(Core.UITests.UITestCategories.Github10000)]
[NUnit.Framework.Category(UITestCategories.Shell)]
#endif
public class Issue11214 : TestShell
{
FlyoutItem _itemexpanderItems;
protected override void Init()
{
_itemexpanderItems = new FlyoutItem()
{
Title = "Expando Magic",
FlyoutDisplayOptions = FlyoutDisplayOptions.AsMultipleItems
};

ContentPage contentPage = new ContentPage()
{
Content = new StackLayout()
{
Children =
{
new Label()
{
Text = "Open the Flyout",
AutomationId = "PageLoaded"
}
}
}
};

AddFlyoutItem(contentPage, "Top Item");

var flyoutItem = AddFlyoutItem("Click Me and You Should see 2 Items show up");
flyoutItem.Route = "ExpandMe";
flyoutItem.AutomationId = "ExpandMe";
Items.Add(_itemexpanderItems);
}

protected override void OnNavigating(ShellNavigatingEventArgs args)
{
base.OnNavigating(args);

if(!args.Target.FullLocation.ToString().Contains("ExpandMe"))
{
return;
}

args.Cancel();

if (_itemexpanderItems.Items.Count == 0 ||
_itemexpanderItems.Items[0].Items.Count == 0)
{
for (int i = 0; i < 2; i++)
{
_itemexpanderItems.Items.Add(new ShellContent()
{
Title = $"Some Item: {i}",
Content = new ContentPage()
});
}
}
else
{
_itemexpanderItems.Items.Clear();
}
}

#if UITEST
[Test]
public void FlyoutItemChangesPropagateCorrectlyToPlatformForShellElementsNotCurrentlyActive()
{
RunningApp.WaitForElement("PageLoaded");
TapInFlyout("ExpandMe", makeSureFlyoutStaysOpen: true);

for (int i = 0; i < 2; i++)
RunningApp.WaitForElement($"Some Item: {i}");

TapInFlyout("ExpandMe", makeSureFlyoutStaysOpen: true);

for (int i = 0; i < 2; i++)
RunningApp.WaitForNoElement($"Some Item: {i}");
}
#endif
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)CollectionViewGroupTypeIssue.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue11214.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue13109.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue4720.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue10897.xaml.cs">
Expand Down Expand Up @@ -2607,4 +2608,4 @@
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
</ItemGroup>
</Project>
</Project>
1 change: 1 addition & 0 deletions Xamarin.Forms.Core/Shell/IShellController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public interface IFlyoutBehaviorObserver
public interface IShellController : IPageController
{
event EventHandler StructureChanged;
event EventHandler FlyoutItemsChanged;

View FlyoutHeader { get; }

Expand Down
30 changes: 27 additions & 3 deletions Xamarin.Forms.Core/Shell/Shell.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ static void OnFlyoutItemIsVisibleChanged(BindableObject bindable, object oldValu
if (bindable is Element element)
element
.FindParentOfType<Shell>()
?.SendStructureChanged();
?.SendFlyoutItemsChanged();
}

public static readonly BindableProperty TabBarIsVisibleProperty =
Expand Down Expand Up @@ -294,6 +294,14 @@ DataTemplate IShellController.GetFlyoutItemDataTemplate(BindableObject bo)

event EventHandler _structureChanged;

event EventHandler IShellController.FlyoutItemsChanged
{
add { _flyoutItemsChanged += value; }
remove { _flyoutItemsChanged -= value; }
}

event EventHandler _flyoutItemsChanged;

View IShellController.FlyoutHeader => FlyoutHeaderView;
View IShellController.FlyoutFooter => FlyoutFooterView;

Expand Down Expand Up @@ -570,6 +578,7 @@ void Initialize()
{
SetCurrentItem();
SendStructureChanged();
SendFlyoutItemsChanged();
};

async void SetCurrentItem()
Expand Down Expand Up @@ -814,8 +823,23 @@ protected override void OnBindingContextChanged()
if (FlyoutFooterView != null)
SetInheritedBindingContext(FlyoutFooterView, BindingContext);
}


internal void SendFlyoutItemsChanged()
{
if (UpdateFlyoutGroupings())
_flyoutItemsChanged?.Invoke(this, EventArgs.Empty);
}

List<List<Element>> IShellController.GenerateFlyoutGrouping()
{
if(_currentFlyoutViews == null)
UpdateFlyoutGroupings();

return _currentFlyoutViews;
}

bool UpdateFlyoutGroupings()
{
// The idea here is to create grouping such that the Flyout would
// render correctly if it renderered each item in the groups in order
Expand Down Expand Up @@ -926,11 +950,11 @@ List<List<Element>> IShellController.GenerateFlyoutGrouping()
}

if (!hasChanged)
return _currentFlyoutViews;
return false;
}

_currentFlyoutViews = result;
return result;
return true;

bool ShowInFlyoutMenu(BindableObject bo)
{
Expand Down
11 changes: 9 additions & 2 deletions Xamarin.Forms.Core/Shell/ShellGroupItem.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
namespace Xamarin.Forms
using System;

namespace Xamarin.Forms
{
public class ShellGroupItem : BaseShellItem
{
public static readonly BindableProperty FlyoutDisplayOptionsProperty =
BindableProperty.Create(nameof(FlyoutDisplayOptions), typeof(FlyoutDisplayOptions), typeof(ShellItem), FlyoutDisplayOptions.AsSingleItem, BindingMode.OneTime);
BindableProperty.Create(nameof(FlyoutDisplayOptions), typeof(FlyoutDisplayOptions), typeof(ShellGroupItem), FlyoutDisplayOptions.AsSingleItem, BindingMode.OneTime, propertyChanged: OnFlyoutDisplayOptionsPropertyChanged);

static void OnFlyoutDisplayOptionsPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
((Element)bindable).FindParentOfType<Shell>()?.SendFlyoutItemsChanged();
}

public FlyoutDisplayOptions FlyoutDisplayOptions
{
Expand Down
7 changes: 5 additions & 2 deletions Xamarin.Forms.Core/Shell/ShellItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,12 @@ public ShellSection CurrentItem

internal void SendStructureChanged()
{
if (Parent is Shell shell && IsVisibleItem)
if (Parent is Shell shell)
{
shell.SendStructureChanged();
if (IsVisibleItem)
shell.SendStructureChanged();

shell.SendFlyoutItemsChanged();
}
}

Expand Down
7 changes: 5 additions & 2 deletions Xamarin.Forms.Core/Shell/ShellSection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -622,9 +622,12 @@ bool IsNavigationAnimated(BindableObject bo)

internal void SendStructureChanged()
{
if (Parent?.Parent is Shell shell && IsVisibleSection)
if (Parent?.Parent is Shell shell)
{
shell.SendStructureChanged();
if (IsVisibleSection)
shell.SendStructureChanged();

shell.SendFlyoutItemsChanged();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public ShellFlyoutRecyclerAdapter(IShellContext shellContext, Action<Element> se
{
_shellContext = shellContext;

ShellController.StructureChanged += OnShellStructureChanged;
ShellController.FlyoutItemsChanged += OnFlyoutItemsChanged;

_listItems = GenerateItemList();
_selectedCallback = selectedCallback;
Expand Down Expand Up @@ -197,7 +197,7 @@ protected virtual List<AdapterListItem> GenerateItemList()
return result;
}

protected virtual void OnShellStructureChanged(object sender, EventArgs e)
protected virtual void OnFlyoutItemsChanged(object sender, EventArgs e)
{
var newListItems = GenerateItemList();

Expand All @@ -217,7 +217,7 @@ protected override void Dispose(bool disposing)

if (disposing)
{
((IShellController)Shell).StructureChanged -= OnShellStructureChanged;
((IShellController)Shell).FlyoutItemsChanged -= OnFlyoutItemsChanged;

_elementViewHolder?.Dispose();

Expand Down
39 changes: 35 additions & 4 deletions Xamarin.Forms.Platform.UAP/Shell/ShellRenderer.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using Windows.Foundation.Metadata;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
Expand Down Expand Up @@ -32,6 +34,7 @@ public class ShellRenderer : Microsoft.UI.Xaml.Controls.NavigationView, IVisualE
List<List<Element>> _flyoutGrouping;
ShellItemRenderer ItemRenderer { get; }
IShellController ShellController => (IShellController)_shell;
ObservableCollection<object> FlyoutItems = new ObservableCollection<object>();

public ShellRenderer()
{
Expand All @@ -43,6 +46,7 @@ public ShellRenderer()
Content = ItemRenderer = CreateShellItemRenderer();
MenuItemTemplateSelector = CreateShellFlyoutTemplateSelector();
Style = (Windows.UI.Xaml.Style)Windows.UI.Xaml.Application.Current.Resources["ShellNavigationView"];
MenuItemsSource = FlyoutItems;
}

async void OnBackRequested(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewBackRequestedEventArgs args)
Expand Down Expand Up @@ -317,7 +321,7 @@ protected virtual void OnElementSet(Shell shell)
ShellController.AddFlyoutBehaviorObserver(this);
ShellController.AddAppearanceObserver(this, shell);
ShellController.ItemsCollectionChanged += OnItemsCollectionChanged;
ShellController.StructureChanged += OnStructureChanged;
ShellController.FlyoutItemsChanged += OnFlyoutItemsChanged;
UpdateFlyoutBackgroundColor();

_shell.Navigated += OnShellNavigated;
Expand Down Expand Up @@ -370,7 +374,7 @@ void UpdateToolBar()
}
}

void OnStructureChanged(object sender, EventArgs e)
void OnFlyoutItemsChanged(object sender, EventArgs e)
{
UpdateMenuItemSource();
}
Expand All @@ -386,17 +390,31 @@ void UpdateMenuItemSource()
if (_flyoutGrouping != newGrouping)
{
_flyoutGrouping = newGrouping;
MenuItemsSource = IterateItems(newGrouping);
var newItems = IterateItems(newGrouping).ToList();

foreach (var item in newItems)
{
if (!FlyoutItems.Contains(item))
FlyoutItems.Add(item);
}

for (var i = FlyoutItems.Count - 1; i >= 0; i--)
{
var item = FlyoutItems[i];
if (!newItems.Contains(item))
FlyoutItems.RemoveAt(i);
}
}
}

IEnumerable<object> IterateItems(List<List<Element>> groups)
{
int separatorNumber = 0;
foreach (var group in groups)
{
if (group.Count > 0 && group != groups[0])
{
yield return new MenuFlyoutSeparator(); // Creates a separator
yield return new FlyoutItemMenuSeparator(separatorNumber++); // Creates a separator
}
foreach (var item in group)
{
Expand All @@ -405,6 +423,19 @@ IEnumerable<object> IterateItems(List<List<Element>> groups)
}
}

class FlyoutItemMenuSeparator : MenuFlyoutSeparator
{
public FlyoutItemMenuSeparator(int separatorNumber)
{
Id = separatorNumber;
}

public int Id { get; set; }
public override int GetHashCode() => Id.GetHashCode();
public override bool Equals(object obj) =>
obj is FlyoutItemMenuSeparator fim && fim.Id == Id;
}

void SwitchShellItem(ShellItem newItem, bool animate = true)
{
SelectedItem = newItem;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public ShellTableViewController(IShellContext context, Action<Element> onElement
_source = CreateShellTableViewSource();
_source.ScrolledEvent += OnScrolled;

ShellController.StructureChanged += OnStructureChanged;
ShellController.FlyoutItemsChanged += OnFlyoutItemsChanged;
_context.Shell.PropertyChanged += OnShellPropertyChanged;
}

Expand Down Expand Up @@ -90,7 +90,7 @@ void OnHeaderFooterSizeChanged(object sender, EventArgs e)
LayoutParallax();
}

void OnStructureChanged(object sender, EventArgs e)
void OnFlyoutItemsChanged(object sender, EventArgs e)
{
_source.ClearCache();
TableView.ReloadData();
Expand Down Expand Up @@ -181,8 +181,8 @@ protected override void Dispose(bool disposing)

if (disposing)
{
if ((_context?.Shell as IShellController) != null)
((IShellController)_context.Shell).StructureChanged -= OnStructureChanged;
if (ShellController != null)
ShellController.FlyoutItemsChanged -= OnFlyoutItemsChanged;

if (_source != null)
_source.ScrolledEvent -= OnScrolled;
Expand Down