зеркало из https://github.com/DeGsoft/maui-linux.git
[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:
Родитель
d63002c25f
Коммит
dbf4037a31
|
@ -581,6 +581,30 @@ namespace Xamarin.Forms.Controls
|
||||||
#endif
|
#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
|
#if UITEST
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
Routing.Route="shellcontent"
|
Routing.Route="shellcontent"
|
||||||
Shell.SetPaddingInsets="true"
|
Shell.SetPaddingInsets="true"
|
||||||
Shell.TabBarIsVisible="false"
|
Shell.TabBarIsVisible="false"
|
||||||
x:Class="Xamarin.Forms.Controls.ShellContent">
|
x:Class="Xamarin.Forms.Controls.ShellContentTest">
|
||||||
<Page.ToolbarItems>
|
<Page.ToolbarItems>
|
||||||
<ToolbarItem Text="Search" Icon="bank.png" />
|
<ToolbarItem Text="Search" Icon="bank.png" />
|
||||||
</Page.ToolbarItems>
|
</Page.ToolbarItems>
|
|
@ -13,7 +13,7 @@ namespace Xamarin.Forms.Controls
|
||||||
[Preserve]
|
[Preserve]
|
||||||
[QueryProperty("Text", "welcome")]
|
[QueryProperty("Text", "welcome")]
|
||||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||||
public partial class ShellContent : ContentPage
|
public partial class ShellContentTest : ContentPage
|
||||||
{
|
{
|
||||||
private class MySearchHandler : SearchHandler
|
private class MySearchHandler : SearchHandler
|
||||||
{
|
{
|
||||||
|
@ -51,7 +51,7 @@ namespace Xamarin.Forms.Controls
|
||||||
|
|
||||||
private string _text;
|
private string _text;
|
||||||
|
|
||||||
public ShellContent()
|
public ShellContentTest()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ namespace Xamarin.Forms.Controls
|
||||||
|
|
||||||
private void InsertClicked(object sender, EventArgs e)
|
private void InsertClicked(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
Navigation.InsertPageBefore(new ShellContent(), this);
|
Navigation.InsertPageBefore(new ShellContentTest(), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ToggleClicked(object sender, EventArgs e)
|
private void ToggleClicked(object sender, EventArgs e)
|
||||||
|
@ -122,7 +122,7 @@ namespace Xamarin.Forms.Controls
|
||||||
|
|
||||||
private async void PushClicked(object sender, EventArgs e)
|
private async void PushClicked(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
await Navigation.PushAsync(new ShellContent()
|
await Navigation.PushAsync(new ShellContentTest()
|
||||||
{
|
{
|
||||||
Text = Text + "1"
|
Text = Text + "1"
|
||||||
});
|
});
|
|
@ -50,6 +50,9 @@
|
||||||
<Compile Update="GalleryPages\VisualStateManagerGalleries\OnPlatformExample.xaml.cs">
|
<Compile Update="GalleryPages\VisualStateManagerGalleries\OnPlatformExample.xaml.cs">
|
||||||
<DependentUpon>OnPlatformExample.xaml</DependentUpon>
|
<DependentUpon>OnPlatformExample.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Update="ShellContentTest.xaml.cs">
|
||||||
|
<DependentUpon>ShellContentTest.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<EmbeddedResource Update="GalleryPages\BindableLayoutGalleryPage.xaml">
|
<EmbeddedResource Update="GalleryPages\BindableLayoutGalleryPage.xaml">
|
||||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
|
|
@ -303,6 +303,9 @@ namespace Xamarin.Forms.Core.UnitTests
|
||||||
|
|
||||||
var label = new Label();
|
var label = new Label();
|
||||||
|
|
||||||
|
var viewModel = new Object();
|
||||||
|
shell.BindingContext = viewModel;
|
||||||
|
|
||||||
shell.FlyoutHeader = label;
|
shell.FlyoutHeader = label;
|
||||||
|
|
||||||
Assert.AreEqual(((IShellController)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, label2);
|
||||||
Assert.AreEqual(((IShellController)shell).FlyoutHeader.BindingContext, label);
|
Assert.AreEqual(((IShellController)shell).FlyoutHeader.BindingContext, viewModel);
|
||||||
|
|
||||||
shell.FlyoutHeaderTemplate = null;
|
shell.FlyoutHeaderTemplate = null;
|
||||||
|
|
||||||
|
@ -370,5 +373,110 @@ namespace Xamarin.Forms.Core.UnitTests
|
||||||
shell.GoToAsync("//rootlevelcontent1");
|
shell.GoToAsync("//rootlevelcontent1");
|
||||||
Assert.AreEqual(shell.CurrentItem, item1);
|
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)
|
if (Shell.GetSearchHandler(this) is SearchHandler searchHandler)
|
||||||
SetInheritedBindingContext(searchHandler, BindingContext);
|
SetInheritedBindingContext(searchHandler, BindingContext);
|
||||||
|
|
||||||
|
if (Shell.GetTitleView(this) is View titleView)
|
||||||
|
SetInheritedBindingContext(titleView, BindingContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||||
|
|
|
@ -49,6 +49,9 @@ namespace Xamarin.Forms
|
||||||
get { return _effectiveVisual; }
|
get { return _effectiveVisual; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
if (value == _effectiveVisual)
|
||||||
|
return;
|
||||||
|
|
||||||
_effectiveVisual = value;
|
_effectiveVisual = value;
|
||||||
OnPropertyChanged(VisualElement.VisualProperty.PropertyName);
|
OnPropertyChanged(VisualElement.VisualProperty.PropertyName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -338,6 +338,10 @@ namespace Xamarin.Forms
|
||||||
{
|
{
|
||||||
base.OnPropertyChanged(propertyName);
|
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)
|
if (_effects == null || _effects.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,9 @@ namespace Xamarin.Forms
|
||||||
get { return _effectiveVisual; }
|
get { return _effectiveVisual; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
if (value == _effectiveVisual)
|
||||||
|
return;
|
||||||
|
|
||||||
_effectiveVisual = value;
|
_effectiveVisual = value;
|
||||||
OnPropertyChanged(VisualElement.VisualProperty.PropertyName);
|
OnPropertyChanged(VisualElement.VisualProperty.PropertyName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,6 @@ namespace Xamarin.Forms
|
||||||
|
|
||||||
public interface IShellController : IPageController
|
public interface IShellController : IPageController
|
||||||
{
|
{
|
||||||
event EventHandler HeaderChanged;
|
|
||||||
|
|
||||||
event EventHandler StructureChanged;
|
event EventHandler StructureChanged;
|
||||||
|
|
||||||
View FlyoutHeader { get; }
|
View FlyoutHeader { get; }
|
||||||
|
|
|
@ -187,19 +187,12 @@ namespace Xamarin.Forms
|
||||||
List<(IAppearanceObserver Observer, Element Pivot)> _appearanceObservers = new List<(IAppearanceObserver Observer, Element Pivot)>();
|
List<(IAppearanceObserver Observer, Element Pivot)> _appearanceObservers = new List<(IAppearanceObserver Observer, Element Pivot)>();
|
||||||
List<IFlyoutBehaviorObserver> _flyoutBehaviorObservers = new List<IFlyoutBehaviorObserver>();
|
List<IFlyoutBehaviorObserver> _flyoutBehaviorObservers = new List<IFlyoutBehaviorObserver>();
|
||||||
|
|
||||||
event EventHandler IShellController.HeaderChanged
|
|
||||||
{
|
|
||||||
add { _headerChanged += value; }
|
|
||||||
remove { _headerChanged -= value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
event EventHandler IShellController.StructureChanged
|
event EventHandler IShellController.StructureChanged
|
||||||
{
|
{
|
||||||
add { _structureChanged += value; }
|
add { _structureChanged += value; }
|
||||||
remove { _structureChanged -= value; }
|
remove { _structureChanged -= value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
event EventHandler _headerChanged;
|
|
||||||
event EventHandler _structureChanged;
|
event EventHandler _structureChanged;
|
||||||
|
|
||||||
View IShellController.FlyoutHeader => FlyoutHeaderView;
|
View IShellController.FlyoutHeader => FlyoutHeaderView;
|
||||||
|
@ -708,10 +701,16 @@ namespace Xamarin.Forms
|
||||||
_flyoutHeaderView = value;
|
_flyoutHeaderView = value;
|
||||||
if (_flyoutHeaderView != null)
|
if (_flyoutHeaderView != null)
|
||||||
OnChildAdded(_flyoutHeaderView);
|
OnChildAdded(_flyoutHeaderView);
|
||||||
_headerChanged?.Invoke(this, EventArgs.Empty);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnBindingContextChanged()
|
||||||
|
{
|
||||||
|
base.OnBindingContextChanged();
|
||||||
|
if (FlyoutHeaderView != null)
|
||||||
|
SetInheritedBindingContext(FlyoutHeaderView, BindingContext);
|
||||||
|
}
|
||||||
|
|
||||||
List<List<Element>> IShellController.GenerateFlyoutGrouping()
|
List<List<Element>> IShellController.GenerateFlyoutGrouping()
|
||||||
{
|
{
|
||||||
// The idea here is to create grouping such that the Flyout would
|
// The idea here is to create grouping such that the Flyout would
|
||||||
|
@ -1033,10 +1032,6 @@ namespace Xamarin.Forms
|
||||||
else
|
else
|
||||||
FlyoutHeaderView = null;
|
FlyoutHeaderView = null;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
FlyoutHeaderView.BindingContext = newVal;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnFlyoutHeaderTemplateChanged(DataTemplate oldValue, DataTemplate newValue)
|
void OnFlyoutHeaderTemplateChanged(DataTemplate oldValue, DataTemplate newValue)
|
||||||
|
@ -1051,7 +1046,6 @@ namespace Xamarin.Forms
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var newHeaderView = (View)newValue.CreateContent(FlyoutHeader, this);
|
var newHeaderView = (View)newValue.CreateContent(FlyoutHeader, this);
|
||||||
newHeaderView.BindingContext = FlyoutHeader;
|
|
||||||
FlyoutHeaderView = newHeaderView;
|
FlyoutHeaderView = newHeaderView;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,8 @@ namespace Xamarin.Forms
|
||||||
|
|
||||||
internal override ReadOnlyCollection<Element> LogicalChildrenInternal => _logicalChildrenReadOnly ?? (_logicalChildrenReadOnly = new ReadOnlyCollection<Element>(_logicalChildren));
|
internal override ReadOnlyCollection<Element> LogicalChildrenInternal => _logicalChildrenReadOnly ?? (_logicalChildrenReadOnly = new ReadOnlyCollection<Element>(_logicalChildren));
|
||||||
|
|
||||||
Page ContentCache {
|
Page ContentCache
|
||||||
|
{
|
||||||
get { return _contentCache; }
|
get { return _contentCache; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
|
|
@ -64,6 +64,9 @@ namespace Xamarin.Forms.Platform.Android
|
||||||
_bottomView.SetBackgroundColor(Color.White.ToAndroid());
|
_bottomView.SetBackgroundColor(Color.White.ToAndroid());
|
||||||
_bottomView.SetOnNavigationItemSelectedListener(this);
|
_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);
|
HookEvents(ShellItem);
|
||||||
SetupMenu();
|
SetupMenu();
|
||||||
|
|
||||||
|
|
|
@ -386,8 +386,6 @@ namespace Xamarin.Forms.Platform.Android
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// FIXME
|
|
||||||
titleView.Parent = _shellContext.Shell;
|
|
||||||
_titleViewContainer = new ContainerView(context, titleView);
|
_titleViewContainer = new ContainerView(context, titleView);
|
||||||
_titleViewContainer.MatchHeight = _titleViewContainer.MatchWidth = true;
|
_titleViewContainer.MatchHeight = _titleViewContainer.MatchWidth = true;
|
||||||
_titleViewContainer.LayoutParameters = new Toolbar.LayoutParams(LP.MatchParent, LP.MatchParent)
|
_titleViewContainer.LayoutParameters = new Toolbar.LayoutParams(LP.MatchParent, LP.MatchParent)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче