C# 导航返回后,Xamarin.Forms中未显示菜单项
我正在开发一个Xamarin.Forms Android应用程序,其中在ContentPage上使用CustomRenderer在页面标题中显示SearchView。“SearchPage”类的CustomRenderer如下所示:C# 导航返回后,Xamarin.Forms中未显示菜单项,c#,xamarin,xamarin.android,xamarin.forms,searchview,C#,Xamarin,Xamarin.android,Xamarin.forms,Searchview,我正在开发一个Xamarin.Forms Android应用程序,其中在ContentPage上使用CustomRenderer在页面标题中显示SearchView。“SearchPage”类的CustomRenderer如下所示: /// <summary> /// The search page renderer. /// </summary> public class SearchPageRenderer : PageRenderer { ///
/// <summary>
/// The search page renderer.
/// </summary>
public class SearchPageRenderer : PageRenderer
{
/// <summary>
/// Gets or sets the search view.
/// </summary>
private SearchView searchView;
/// <summary>
/// Gets or sets the toolbar.
/// </summary>
private Toolbar toolbar;
/// <summary>
/// Reaction on the disposing of the page.
/// </summary>
/// <param name="disposing">A value indicating whether disposing.</param>
protected override void Dispose(bool disposing)
{
if (this.searchView != null)
{
this.searchView.QueryTextChange -= this.OnQueryTextChangeSearchView;
}
this.toolbar?.Menu?.RemoveItem(Resource.Menu.mainmenu);
base.Dispose(disposing);
}
/// <summary>
/// Reaction on the element changed event.
/// </summary>
/// <param name="e">The event argument.</param>
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
base.OnElementChanged(e);
if (e?.NewElement == null || e.OldElement != null)
{
return;
}
this.AddSearchToToolBar();
}
/// <summary>
/// Adds a search item to the toolbar.
/// </summary>
private void AddSearchToToolBar()
{
this.toolbar = (CrossCurrentActivity.Current?.Activity as MainActivity)?.FindViewById<Toolbar>(Resource.Id.toolbar);
if (this.toolbar != null)
{
this.toolbar.Title = this.Element.Title;
this.toolbar.InflateMenu(Resource.Menu.mainmenu);
this.searchView = this.toolbar.Menu?.FindItem(Resource.Id.action_search)?.ActionView?.JavaCast<SearchView>();
if (this.searchView != null)
{
this.searchView.QueryTextChange += this.OnQueryTextChangeSearchView;
this.searchView.ImeOptions = (int)ImeAction.Search;
this.searchView.MaxWidth = int.MaxValue;
this.searchView.SetBackgroundResource(Resource.Drawable.textfield_search_holo_light);
}
}
}
/// <summary>
/// Reaction on the text change event of the searchbar.
/// </summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event argument.</param>
private void OnQueryTextChangeSearchView(object sender, SearchView.QueryTextChangeEventArgs e)
{
var searchPage = this.Element as SearchPage;
searchPage?.SearchCommand?.Execute(e?.NewText);
}
}
这是没有问题的。但是,如果用户使用后退按钮从“DetailPage”导航回“SearchPage”,则定制的搜索标题根本不会显示
我尝试的是:
使用页面的“OnAppearing”事件而不是“OnElementChanged”。乍一看,这并不能解决问题。但是,如果我将Task.Delay(500)添加到OnAppearing方法,然后再次添加SearchView,它就会显示出来。但是这个补丁看起来很难看,如果我在使用SearchPage时休眠应用程序并继续,搜索小部件会显示两次
所以我的问题是:
Xamarin中是否有bug,或者我做错了什么?
Xamarin有缺陷还是我做错了什么
我不能说这是一只虫子,我宁愿把它当作设计来考虑。真正的问题是,您试图在自定义渲染器中修改工具栏
,并且根据您的描述,您正在使用导航页面
,每次更改当前页面时,它都会更新工具栏
的视图
因此,您使用页面的“OnAppearing”事件而不是“OnElementChanged”是正确的,这会导致另一个问题,工具栏
的更新会在删除旧页面时延迟,正如您在RemovePage
方法的源代码中看到的那样,当显示新页面时,OnAppearing
方法将立即执行:
Device.StartTimer(TimeSpan.FromMilliseconds(10), () =>
{
UpdateToolbar();
return false;
});
所以我不认为你也做错了什么,你使用的方法是等待任务。延迟(500)代码>可以快速解决此问题
根据您在此处的描述:
但是这个补丁看起来很难看,如果我在使用SearchPage时休眠应用程序并继续,搜索小部件会显示两次
我建议将您的搜索页面
更改为视图
,然后从页面中动态添加/删除此视图:
public class SearchPage : View
{
...
}
和它的渲染器(其他代码相同,仅更改为继承自ViewRenderer
,并且OnElementChanged
的参数不同):
主页
的布局:
<StackLayout>
...
</StackLayout>
顺便说一下,如果您想从这里的MainPage
导航到其他页面,您可以这样编码:
this.Navigation.PushAsync(new Page1());
无需为其创建
PushPageAsync
任务 尝试在重新启动时覆盖
。我最近发现了一个实例,当视图回到前面时,需要重新绑定我的列表,这个方法被称为Consistently,您最终选择了什么解决方案?忘了说,我建议使用ViewRenderer
而不是PageRenderer
的原因是,我不知道您如何再次添加SearchPage
,您也可以直接尝试在OnDisappearing
中删除它。非常感谢您的回答!看来任务延迟是必要的。我喜欢您使用视图而不是页面进行自定义渲染的想法,因此我将尝试一下:添加等待任务的意义是什么。延迟(500);在OnAppearing方法中?@user3713398,正如我在回答中所说的,在NavigationPageRenderer
的源代码中,在RemovePage
方法中,它在那里被硬编码以延迟一点。@GraceFeng:你的逻辑工作得很有魅力。非常感谢。您是否也可以发送IOS的ViewRenderer。
MainPage = new NavigationPage(new MainPage());
<StackLayout>
...
</StackLayout>
protected override async void OnAppearing()
{
base.OnAppearing();
await Task.Delay(500);
var content = this.Content as StackLayout;
content.Children.Add(new SearchPage());
}
protected override void OnDisappearing()
{
base.OnDisappearing();
var content = this.Content as StackLayout;
foreach (var child in content.Children)
{
var searchpage = child as SearchPage;
if (searchpage != null)
{
content.Children.Remove(searchpage);
return;
}
}
}
this.Navigation.PushAsync(new Page1());