diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue11214.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue11214.cs
new file mode 100644
index 00000000000..eb596e27715
--- /dev/null
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue11214.cs
@@ -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
+ }
+}
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
index 0901a704dd0..f2c2bda57ed 100644
--- a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
@@ -10,6 +10,7 @@
+
@@ -2607,4 +2608,4 @@
MSBuild:UpdateDesignTimeXaml
-
+
\ No newline at end of file
diff --git a/Xamarin.Forms.Core/Shell/IShellController.cs b/Xamarin.Forms.Core/Shell/IShellController.cs
index 3c197509963..86344198b05 100644
--- a/Xamarin.Forms.Core/Shell/IShellController.cs
+++ b/Xamarin.Forms.Core/Shell/IShellController.cs
@@ -19,6 +19,7 @@ public interface IFlyoutBehaviorObserver
public interface IShellController : IPageController
{
event EventHandler StructureChanged;
+ event EventHandler FlyoutItemsChanged;
View FlyoutHeader { get; }
diff --git a/Xamarin.Forms.Core/Shell/Shell.cs b/Xamarin.Forms.Core/Shell/Shell.cs
index d4b6a93148c..cd3737f33c8 100644
--- a/Xamarin.Forms.Core/Shell/Shell.cs
+++ b/Xamarin.Forms.Core/Shell/Shell.cs
@@ -65,7 +65,7 @@ static void OnFlyoutItemIsVisibleChanged(BindableObject bindable, object oldValu
if (bindable is Element element)
element
.FindParentOfType()
- ?.SendStructureChanged();
+ ?.SendFlyoutItemsChanged();
}
public static readonly BindableProperty TabBarIsVisibleProperty =
@@ -294,6 +294,14 @@ event EventHandler IShellController.StructureChanged
event EventHandler _structureChanged;
+ event EventHandler IShellController.FlyoutItemsChanged
+ {
+ add { _flyoutItemsChanged += value; }
+ remove { _flyoutItemsChanged -= value; }
+ }
+
+ event EventHandler _flyoutItemsChanged;
+
View IShellController.FlyoutHeader => FlyoutHeaderView;
View IShellController.FlyoutFooter => FlyoutFooterView;
@@ -570,6 +578,7 @@ void Initialize()
{
SetCurrentItem();
SendStructureChanged();
+ SendFlyoutItemsChanged();
};
async void SetCurrentItem()
@@ -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> 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
@@ -926,11 +950,11 @@ List> IShellController.GenerateFlyoutGrouping()
}
if (!hasChanged)
- return _currentFlyoutViews;
+ return false;
}
_currentFlyoutViews = result;
- return result;
+ return true;
bool ShowInFlyoutMenu(BindableObject bo)
{
diff --git a/Xamarin.Forms.Core/Shell/ShellGroupItem.cs b/Xamarin.Forms.Core/Shell/ShellGroupItem.cs
index 7f9a51c732e..9b2c288e16a 100644
--- a/Xamarin.Forms.Core/Shell/ShellGroupItem.cs
+++ b/Xamarin.Forms.Core/Shell/ShellGroupItem.cs
@@ -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()?.SendFlyoutItemsChanged();
+ }
public FlyoutDisplayOptions FlyoutDisplayOptions
{
diff --git a/Xamarin.Forms.Core/Shell/ShellItem.cs b/Xamarin.Forms.Core/Shell/ShellItem.cs
index 9b0d886d651..9268843811b 100644
--- a/Xamarin.Forms.Core/Shell/ShellItem.cs
+++ b/Xamarin.Forms.Core/Shell/ShellItem.cs
@@ -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();
}
}
diff --git a/Xamarin.Forms.Core/Shell/ShellSection.cs b/Xamarin.Forms.Core/Shell/ShellSection.cs
index 04058d36015..800dbb50344 100644
--- a/Xamarin.Forms.Core/Shell/ShellSection.cs
+++ b/Xamarin.Forms.Core/Shell/ShellSection.cs
@@ -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();
}
}
diff --git a/Xamarin.Forms.Platform.Android/Renderers/ShellFlyoutRecyclerAdapter.cs b/Xamarin.Forms.Platform.Android/Renderers/ShellFlyoutRecyclerAdapter.cs
index c03838e7af1..884621a80d9 100644
--- a/Xamarin.Forms.Platform.Android/Renderers/ShellFlyoutRecyclerAdapter.cs
+++ b/Xamarin.Forms.Platform.Android/Renderers/ShellFlyoutRecyclerAdapter.cs
@@ -25,7 +25,7 @@ public ShellFlyoutRecyclerAdapter(IShellContext shellContext, Action se
{
_shellContext = shellContext;
- ShellController.StructureChanged += OnShellStructureChanged;
+ ShellController.FlyoutItemsChanged += OnFlyoutItemsChanged;
_listItems = GenerateItemList();
_selectedCallback = selectedCallback;
@@ -197,7 +197,7 @@ protected virtual List GenerateItemList()
return result;
}
- protected virtual void OnShellStructureChanged(object sender, EventArgs e)
+ protected virtual void OnFlyoutItemsChanged(object sender, EventArgs e)
{
var newListItems = GenerateItemList();
@@ -217,7 +217,7 @@ protected override void Dispose(bool disposing)
if (disposing)
{
- ((IShellController)Shell).StructureChanged -= OnShellStructureChanged;
+ ((IShellController)Shell).FlyoutItemsChanged -= OnFlyoutItemsChanged;
_elementViewHolder?.Dispose();
diff --git a/Xamarin.Forms.Platform.UAP/Shell/ShellRenderer.cs b/Xamarin.Forms.Platform.UAP/Shell/ShellRenderer.cs
index a6c48053125..b8aef50a839 100644
--- a/Xamarin.Forms.Platform.UAP/Shell/ShellRenderer.cs
+++ b/Xamarin.Forms.Platform.UAP/Shell/ShellRenderer.cs
@@ -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;
@@ -32,6 +34,7 @@ public class ShellRenderer : Microsoft.UI.Xaml.Controls.NavigationView, IVisualE
List> _flyoutGrouping;
ShellItemRenderer ItemRenderer { get; }
IShellController ShellController => (IShellController)_shell;
+ ObservableCollection