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

Commit

Permalink
Add new xplat event to to propagate FlyoutItemsChanged events to the …
Browse files Browse the repository at this point in the history
…platforms (#13195) fixes #11214

* Add new xplat event to update FlyoutItems from

* - always send flyout item changes

* - fix flyout changed propagation

* - add additional scenario for Sending Flyout Items Changed Event
  • Loading branch information
PureWeen committed Dec 28, 2020
1 parent 1b1b70e commit a054afd
Show file tree
Hide file tree
Showing 11 changed files with 197 additions and 23 deletions.
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 @@ 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;

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
Loading

0 comments on commit a054afd

Please sign in to comment.