[Shell] Propagate Page bindings to TitleView and Shell Binding to Flyout (#5934) fixes #5650 fixes #5501

* propagate bindingcontext

* - add exception message and fix poorly named xaml file

* add ui test automation

* - fix unit test to represent new code

* - changed from ui test to unit test

* - propagate visual, parent, bc to titleview

* - style fixes
This commit is contained in:
Shane Neuville 2019-04-18 09:25:31 -06:00 коммит произвёл Rui Marinho
Родитель d63002c25f
Коммит dbf4037a31
15 изменённых файлов: 168 добавлений и 26 удалений

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

@ -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()

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

@ -34,7 +34,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Issue4484.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue3509.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue4597.cs" />
<Compile Include="$(MSBuildThisFileDirectory)A11yTabIndex.xaml.cs">
<Compile Include="$(MSBuildThisFileDirectory)A11yTabIndex.xaml.cs">
<DependentUpon>A11yTabIndex.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
@ -1158,7 +1158,7 @@
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<ItemGroup>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)A11yTabIndex.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>

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

@ -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">
<Page.ToolbarItems>
<ToolbarItem Text="Search" Icon="bank.png" />
</Page.ToolbarItems>

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

@ -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"
});

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

@ -50,6 +50,9 @@
<Compile Update="GalleryPages\VisualStateManagerGalleries\OnPlatformExample.xaml.cs">
<DependentUpon>OnPlatformExample.xaml</DependentUpon>
</Compile>
<Compile Update="ShellContentTest.xaml.cs">
<DependentUpon>ShellContentTest.xaml</DependentUpon>
</Compile>
<EmbeddedResource Update="GalleryPages\BindableLayoutGalleryPage.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>

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

@ -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);
}
}
}

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

@ -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)

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

@ -49,6 +49,9 @@ namespace Xamarin.Forms
get { return _effectiveVisual; }
set
{
if (value == _effectiveVisual)
return;
_effectiveVisual = value;
OnPropertyChanged(VisualElement.VisualProperty.PropertyName);
}

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

@ -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;

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

@ -67,6 +67,9 @@ namespace Xamarin.Forms
get { return _effectiveVisual; }
set
{
if (value == _effectiveVisual)
return;
_effectiveVisual = value;
OnPropertyChanged(VisualElement.VisualProperty.PropertyName);
}

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

@ -16,8 +16,6 @@ namespace Xamarin.Forms
public interface IShellController : IPageController
{
event EventHandler HeaderChanged;
event EventHandler StructureChanged;
View FlyoutHeader { get; }

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

@ -187,19 +187,12 @@ namespace Xamarin.Forms
List<(IAppearanceObserver Observer, Element Pivot)> _appearanceObservers = new List<(IAppearanceObserver Observer, Element Pivot)>();
List<IFlyoutBehaviorObserver> _flyoutBehaviorObservers = new List<IFlyoutBehaviorObserver>();
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<List<Element>> 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;
}
}

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

@ -89,7 +89,8 @@ namespace Xamarin.Forms
internal override ReadOnlyCollection<Element> LogicalChildrenInternal => _logicalChildrenReadOnly ?? (_logicalChildrenReadOnly = new ReadOnlyCollection<Element>(_logicalChildren));
Page ContentCache {
Page ContentCache
{
get { return _contentCache; }
set
{

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

@ -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();

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

@ -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)