diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/TestPages/TestPages.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/TestPages/TestPages.cs
index 607e60f44..b1bc3e74b 100644
--- a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/TestPages/TestPages.cs
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/TestPages/TestPages.cs
@@ -581,6 +581,30 @@ namespace Xamarin.Forms.Controls
#endif
}
+ public ContentPage CreateContentPage()
+ {
+ ContentPage page = new ContentPage();
+ ShellItem item = new ShellItem()
+ {
+ Items =
+ {
+ new ShellSection()
+ {
+ Items =
+ {
+ new ShellContent()
+ {
+ Content = page
+ }
+ }
+ }
+ }
+ };
+
+ Items.Add(item);
+ return page;
+
+ }
#if UITEST
[SetUp]
public void Setup()
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 6173e4ed3..83084d5df 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
@@ -34,7 +34,7 @@
-
+
A11yTabIndex.xaml
Code
@@ -1158,7 +1158,7 @@
MSBuild:UpdateDesignTimeXaml
-
+
Designer
MSBuild:Compile
diff --git a/Xamarin.Forms.Controls/ShellContent.xaml b/Xamarin.Forms.Controls/ShellContentTest.xaml
similarity index 94%
rename from Xamarin.Forms.Controls/ShellContent.xaml
rename to Xamarin.Forms.Controls/ShellContentTest.xaml
index e5fb11007..8fd4eccc6 100644
--- a/Xamarin.Forms.Controls/ShellContent.xaml
+++ b/Xamarin.Forms.Controls/ShellContentTest.xaml
@@ -5,7 +5,7 @@
Routing.Route="shellcontent"
Shell.SetPaddingInsets="true"
Shell.TabBarIsVisible="false"
- x:Class="Xamarin.Forms.Controls.ShellContent">
+ x:Class="Xamarin.Forms.Controls.ShellContentTest">
diff --git a/Xamarin.Forms.Controls/ShellContent.xaml.cs b/Xamarin.Forms.Controls/ShellContentTest.xaml.cs
similarity index 93%
rename from Xamarin.Forms.Controls/ShellContent.xaml.cs
rename to Xamarin.Forms.Controls/ShellContentTest.xaml.cs
index 002eb86e4..204fa2d9d 100644
--- a/Xamarin.Forms.Controls/ShellContent.xaml.cs
+++ b/Xamarin.Forms.Controls/ShellContentTest.xaml.cs
@@ -13,7 +13,7 @@ namespace Xamarin.Forms.Controls
[Preserve]
[QueryProperty("Text", "welcome")]
[XamlCompilation(XamlCompilationOptions.Compile)]
- public partial class ShellContent : ContentPage
+ public partial class ShellContentTest : ContentPage
{
private class MySearchHandler : SearchHandler
{
@@ -51,7 +51,7 @@ namespace Xamarin.Forms.Controls
private string _text;
- public ShellContent()
+ public ShellContentTest()
{
InitializeComponent();
@@ -89,7 +89,7 @@ namespace Xamarin.Forms.Controls
private void InsertClicked(object sender, EventArgs e)
{
- Navigation.InsertPageBefore(new ShellContent(), this);
+ Navigation.InsertPageBefore(new ShellContentTest(), this);
}
private void ToggleClicked(object sender, EventArgs e)
@@ -122,7 +122,7 @@ namespace Xamarin.Forms.Controls
private async void PushClicked(object sender, EventArgs e)
{
- await Navigation.PushAsync(new ShellContent()
+ await Navigation.PushAsync(new ShellContentTest()
{
Text = Text + "1"
});
diff --git a/Xamarin.Forms.Controls/Xamarin.Forms.Controls.csproj b/Xamarin.Forms.Controls/Xamarin.Forms.Controls.csproj
index 93ad41c5d..df98d49b9 100644
--- a/Xamarin.Forms.Controls/Xamarin.Forms.Controls.csproj
+++ b/Xamarin.Forms.Controls/Xamarin.Forms.Controls.csproj
@@ -50,6 +50,9 @@
OnPlatformExample.xaml
+
+ ShellContentTest.xaml
+
MSBuild:UpdateDesignTimeXaml
diff --git a/Xamarin.Forms.Core.UnitTests/ShellTests.cs b/Xamarin.Forms.Core.UnitTests/ShellTests.cs
index 84cfcb15e..495647fc8 100644
--- a/Xamarin.Forms.Core.UnitTests/ShellTests.cs
+++ b/Xamarin.Forms.Core.UnitTests/ShellTests.cs
@@ -303,6 +303,9 @@ namespace Xamarin.Forms.Core.UnitTests
var label = new Label();
+ var viewModel = new Object();
+ shell.BindingContext = viewModel;
+
shell.FlyoutHeader = label;
Assert.AreEqual(((IShellController)shell).FlyoutHeader, label);
@@ -315,7 +318,7 @@ namespace Xamarin.Forms.Core.UnitTests
});
Assert.AreEqual(((IShellController)shell).FlyoutHeader, label2);
- Assert.AreEqual(((IShellController)shell).FlyoutHeader.BindingContext, label);
+ Assert.AreEqual(((IShellController)shell).FlyoutHeader.BindingContext, viewModel);
shell.FlyoutHeaderTemplate = null;
@@ -370,5 +373,110 @@ namespace Xamarin.Forms.Core.UnitTests
shell.GoToAsync("//rootlevelcontent1");
Assert.AreEqual(shell.CurrentItem, item1);
}
+
+ [Test]
+ public async Task TitleViewBindingContext()
+ {
+ Shell shell = new Shell();
+ ContentPage page = new ContentPage();
+ shell.Items.Add(CreateShellItem(page));
+ page.BindingContext = new { Text = "Binding" };
+
+ // setup title view
+ StackLayout layout = new StackLayout() { BackgroundColor = Color.White };
+ Label label = new Label();
+ label.SetBinding(Label.TextProperty, "Text");
+ layout.Children.Add(label);
+ Shell.SetTitleView(page, layout);
+
+ Assert.AreEqual("Binding", label.Text);
+ page.BindingContext = new { Text = "Binding Changed" };
+ Assert.AreEqual("Binding Changed", label.Text);
+ }
+
+ [Test]
+ public async Task VisualPropagationPageLevel()
+ {
+ Shell shell = new Shell();
+ ContentPage page = new ContentPage();
+ shell.Items.Add(CreateShellItem(page));
+
+ // setup title view
+ StackLayout titleView = new StackLayout() { BackgroundColor = Color.White };
+ Button button = new Button();
+ titleView.Children.Add(button);
+ Shell.SetTitleView(page, titleView);
+ IVisualController visualController = button as IVisualController;
+
+
+ Assert.AreEqual(page, titleView.Parent);
+
+ Assert.AreEqual(VisualMarker.Default, ((IVisualController)button).EffectiveVisual);
+ page.Visual = VisualMarker.Material;
+ Assert.AreEqual(VisualMarker.Material, ((IVisualController)button).EffectiveVisual);
+ }
+
+ [Test]
+ public async Task VisualPropagationShellLevel()
+ {
+ Shell shell = new Shell();
+ ContentPage page = new ContentPage();
+ shell.Items.Add(CreateShellItem(page));
+
+ // setup title view
+ StackLayout titleView = new StackLayout() { BackgroundColor = Color.White };
+ Button button = new Button();
+ titleView.Children.Add(button);
+ Shell.SetTitleView(page, titleView);
+ IVisualController visualController = button as IVisualController;
+
+
+ Assert.AreEqual(page, titleView.Parent);
+ Assert.AreEqual(VisualMarker.Default, ((IVisualController)button).EffectiveVisual);
+ shell.Visual = VisualMarker.Material;
+ Assert.AreEqual(VisualMarker.Material, ((IVisualController)button).EffectiveVisual);
+ }
+
+ [Test]
+ public async Task FlyoutViewVisualPropagation()
+ {
+ Shell shell = new Shell();
+ ContentPage page = new ContentPage();
+ shell.Items.Add(CreateShellItem(page));
+
+
+ // setup title view
+ StackLayout flyoutView = new StackLayout() { BackgroundColor = Color.White };
+ Button button = new Button();
+ flyoutView.Children.Add(button);
+ shell.SetValue(Shell.FlyoutHeaderProperty, flyoutView);
+
+ IVisualController visualController = button as IVisualController;
+ Assert.AreEqual(VisualMarker.Default, visualController.EffectiveVisual);
+ shell.Visual = VisualMarker.Material;
+ Assert.AreEqual(VisualMarker.Material, visualController.EffectiveVisual);
+ }
+
+ [Test]
+ public async Task FlyoutViewBindingContext()
+ {
+ Shell shell = new Shell();
+ ContentPage page = new ContentPage();
+ shell.Items.Add(CreateShellItem(page));
+ shell.BindingContext = new { Text = "Binding" };
+
+ // setup title view
+ StackLayout flyoutView = new StackLayout() { BackgroundColor = Color.White };
+ Label label = new Label();
+ label.SetBinding(Label.TextProperty, "Text");
+ flyoutView.Children.Add(label);
+ shell.SetValue(Shell.FlyoutHeaderProperty, flyoutView);
+
+ Assert.AreEqual("Binding", label.Text);
+ shell.BindingContext = new { Text = "Binding Changed" };
+ Assert.AreEqual("Binding Changed", label.Text);
+ shell.SetValue(Shell.FlyoutHeaderProperty, new ContentView());
+ Assert.AreEqual(null, flyoutView.BindingContext);
+ }
}
}
diff --git a/Xamarin.Forms.Core/BindableObject.cs b/Xamarin.Forms.Core/BindableObject.cs
index fdf386362..34164647c 100644
--- a/Xamarin.Forms.Core/BindableObject.cs
+++ b/Xamarin.Forms.Core/BindableObject.cs
@@ -202,6 +202,9 @@ namespace Xamarin.Forms
if (Shell.GetSearchHandler(this) is SearchHandler searchHandler)
SetInheritedBindingContext(searchHandler, BindingContext);
+
+ if (Shell.GetTitleView(this) is View titleView)
+ SetInheritedBindingContext(titleView, BindingContext);
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
diff --git a/Xamarin.Forms.Core/Cells/Cell.cs b/Xamarin.Forms.Core/Cells/Cell.cs
index e5e4f20df..c8898d6cc 100644
--- a/Xamarin.Forms.Core/Cells/Cell.cs
+++ b/Xamarin.Forms.Core/Cells/Cell.cs
@@ -49,6 +49,9 @@ namespace Xamarin.Forms
get { return _effectiveVisual; }
set
{
+ if (value == _effectiveVisual)
+ return;
+
_effectiveVisual = value;
OnPropertyChanged(VisualElement.VisualProperty.PropertyName);
}
diff --git a/Xamarin.Forms.Core/Element.cs b/Xamarin.Forms.Core/Element.cs
index c7274f2ac..19ad039ba 100644
--- a/Xamarin.Forms.Core/Element.cs
+++ b/Xamarin.Forms.Core/Element.cs
@@ -338,6 +338,10 @@ namespace Xamarin.Forms
{
base.OnPropertyChanged(propertyName);
+ IPropertyPropagationController titleView = Shell.GetTitleView(this) ?? NavigationPage.GetTitleView(this);
+ if(titleView != null)
+ PropertyPropagationExtensions.PropagatePropertyChanged(propertyName, this, new[] { titleView });
+
if (_effects == null || _effects.Count == 0)
return;
diff --git a/Xamarin.Forms.Core/Shell/BaseShellItem.cs b/Xamarin.Forms.Core/Shell/BaseShellItem.cs
index 8311d83f5..da705fd14 100644
--- a/Xamarin.Forms.Core/Shell/BaseShellItem.cs
+++ b/Xamarin.Forms.Core/Shell/BaseShellItem.cs
@@ -67,6 +67,9 @@ namespace Xamarin.Forms
get { return _effectiveVisual; }
set
{
+ if (value == _effectiveVisual)
+ return;
+
_effectiveVisual = value;
OnPropertyChanged(VisualElement.VisualProperty.PropertyName);
}
diff --git a/Xamarin.Forms.Core/Shell/IShellController.cs b/Xamarin.Forms.Core/Shell/IShellController.cs
index 9d62c0578..fcf8e0a9a 100644
--- a/Xamarin.Forms.Core/Shell/IShellController.cs
+++ b/Xamarin.Forms.Core/Shell/IShellController.cs
@@ -16,8 +16,6 @@ namespace Xamarin.Forms
public interface IShellController : IPageController
{
- event EventHandler HeaderChanged;
-
event EventHandler StructureChanged;
View FlyoutHeader { get; }
diff --git a/Xamarin.Forms.Core/Shell/Shell.cs b/Xamarin.Forms.Core/Shell/Shell.cs
index 5d5f99ac8..bae08e606 100644
--- a/Xamarin.Forms.Core/Shell/Shell.cs
+++ b/Xamarin.Forms.Core/Shell/Shell.cs
@@ -187,19 +187,12 @@ namespace Xamarin.Forms
List<(IAppearanceObserver Observer, Element Pivot)> _appearanceObservers = new List<(IAppearanceObserver Observer, Element Pivot)>();
List _flyoutBehaviorObservers = new List();
- event EventHandler IShellController.HeaderChanged
- {
- add { _headerChanged += value; }
- remove { _headerChanged -= value; }
- }
-
event EventHandler IShellController.StructureChanged
{
add { _structureChanged += value; }
remove { _structureChanged -= value; }
}
- event EventHandler _headerChanged;
event EventHandler _structureChanged;
View IShellController.FlyoutHeader => FlyoutHeaderView;
@@ -708,10 +701,16 @@ namespace Xamarin.Forms
_flyoutHeaderView = value;
if (_flyoutHeaderView != null)
OnChildAdded(_flyoutHeaderView);
- _headerChanged?.Invoke(this, EventArgs.Empty);
}
}
+ protected override void OnBindingContextChanged()
+ {
+ base.OnBindingContextChanged();
+ if (FlyoutHeaderView != null)
+ SetInheritedBindingContext(FlyoutHeaderView, BindingContext);
+ }
+
List> IShellController.GenerateFlyoutGrouping()
{
// The idea here is to create grouping such that the Flyout would
@@ -1033,10 +1032,6 @@ namespace Xamarin.Forms
else
FlyoutHeaderView = null;
}
- else
- {
- FlyoutHeaderView.BindingContext = newVal;
- }
}
void OnFlyoutHeaderTemplateChanged(DataTemplate oldValue, DataTemplate newValue)
@@ -1051,7 +1046,6 @@ namespace Xamarin.Forms
else
{
var newHeaderView = (View)newValue.CreateContent(FlyoutHeader, this);
- newHeaderView.BindingContext = FlyoutHeader;
FlyoutHeaderView = newHeaderView;
}
}
diff --git a/Xamarin.Forms.Core/Shell/ShellContent.cs b/Xamarin.Forms.Core/Shell/ShellContent.cs
index 799f208df..8403efe10 100644
--- a/Xamarin.Forms.Core/Shell/ShellContent.cs
+++ b/Xamarin.Forms.Core/Shell/ShellContent.cs
@@ -89,7 +89,8 @@ namespace Xamarin.Forms
internal override ReadOnlyCollection LogicalChildrenInternal => _logicalChildrenReadOnly ?? (_logicalChildrenReadOnly = new ReadOnlyCollection(_logicalChildren));
- Page ContentCache {
+ Page ContentCache
+ {
get { return _contentCache; }
set
{
diff --git a/Xamarin.Forms.Platform.Android/Renderers/ShellItemRenderer.cs b/Xamarin.Forms.Platform.Android/Renderers/ShellItemRenderer.cs
index 09452a522..e6840f730 100644
--- a/Xamarin.Forms.Platform.Android/Renderers/ShellItemRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/Renderers/ShellItemRenderer.cs
@@ -64,6 +64,9 @@ namespace Xamarin.Forms.Platform.Android
_bottomView.SetBackgroundColor(Color.White.ToAndroid());
_bottomView.SetOnNavigationItemSelectedListener(this);
+ if(ShellItem == null)
+ throw new ArgumentException("Active Shell Item not set. Have you added any Shell Items to your Shell?", nameof(ShellItem));
+
HookEvents(ShellItem);
SetupMenu();
diff --git a/Xamarin.Forms.Platform.Android/Renderers/ShellToolbarTracker.cs b/Xamarin.Forms.Platform.Android/Renderers/ShellToolbarTracker.cs
index c7a5611c3..3d80d5d78 100644
--- a/Xamarin.Forms.Platform.Android/Renderers/ShellToolbarTracker.cs
+++ b/Xamarin.Forms.Platform.Android/Renderers/ShellToolbarTracker.cs
@@ -386,8 +386,6 @@ namespace Xamarin.Forms.Platform.Android
}
else
{
- // FIXME
- titleView.Parent = _shellContext.Shell;
_titleViewContainer = new ContainerView(context, titleView);
_titleViewContainer.MatchHeight = _titleViewContainer.MatchWidth = true;
_titleViewContainer.LayoutParameters = new Toolbar.LayoutParams(LP.MatchParent, LP.MatchParent)