导航返回后,菜单项未在Xamarin.Forms中显示

时间:2017-07-22 13:10:39

标签: c# xamarin xamarin.android xamarin.forms searchview

我正在开发一个 Xamarin.Forms Android-App ,在ContentPage上, CustomRenderer 用于在页面页眉中显示SearchView。 " SearchPage"的CustomRenderer; class类似于以下内容:

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

感谢this Stack-Overflow线程,到目前为止我的工作就像魅力一样。 现在,如果用户点击&#34; SearchPage&#34;中的项目,则使用以下方法将新的ContentPage(称为&#34; DetailPage&#34;)推送到NavigationStack:

private async Task PushPageAsync(object model, ContentPage page, INavigation navigation)
    {
        page.BindingContext = model;
        await navigation.PushAsync(page).ConfigureAwait(false);
    }

没有问题。但是,如果用户从&#34; DetailPage&#34;导航回到&#34; SearchPage&#34;通过使用后退按钮,自定义搜索标题根本不显示

我尝试了什么:

使用&#34; OnAppearing&#34;页面的事件而不是&#34; OnElementChanged&#34;。这并没有乍一看解决问题。但是,如果我将一个Task.Delay(500)添加到OnAppearing-Method然后再添加SearchView ,则会显示它。但是这个修复看起来非常难看,如果我在使用SearchPage时使用应用程序并恢复,则Search-Widget显示两次

所以我的问题是:

Xamarin是否有错误或我做错了什么?

1 个答案:

答案 0 :(得分:3)

  

Xamarin是否有错误或我做错了什么?

我不能说这是一个错误,我更愿意认为它是设计的。真正的问题是您尝试修改自定义渲染器中的Toolbar,并根据您的说明使用NavigationPage,其NavigationPageRenderer将更新{{3}}的视图{1}}每次更改当前页面时。

所以你正确使用页面的“OnAppearing”事件而不是“OnElementChanged”,这会导致另一个问题,当您删除旧页面时,Toolbar的更新会被延迟可以从Toolbar方法的源代码中看到,而RemovePage方法将在显示新页面时立即执行:

OnAppearing

所以我不认为你做错了什么,你使用Device.StartTimer(TimeSpan.FromMilliseconds(10), () => { UpdateToolbar(); return false; }); 的方法可以快速解决这个问题。

根据您的描述:

  

但是这个修复看起来很难看,如果我在使用SearchPage时使用应用程序并恢复,则Search-Widget会显示两次。

我建议您将await Task.Delay(500);更改为SearchPage,然后从页面中动态添加/删除此视图:

View

和它的渲染器(其他代码相同,只更改为从public class SearchPage : View { ... } 继承而且ViewRenderer的参数不同):

OnElementChanged

然后,您可以将其用作要显示的页面中的控件/视图,而不是直接用作public class SearchPageRenderer : ViewRenderer { private SearchView searchView; /// <summary> /// Gets or sets the toolbar. /// </summary> private Android.Support.V7.Widget.Toolbar toolbar; ... /// <summary> /// Reaction on the element changed event. /// </summary> /// <param name="e">The event argument.</param> protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.View> e) { base.OnElementChanged(e); if (e?.NewElement == null || e.OldElement != null) { return; } this.AddSearchToToolBar(); } ... } 。例如,我想在Page中显示此搜索视图,然后导航到App.xaml.cs中的MainPage

MainPage

MainPage = new NavigationPage(new MainPage()); 的布局:

MainPage

最后覆盖<StackLayout> ... </StackLayout> 的{​​{1}}和OnAppearing方法:

OnDisappearing

顺便说一下,如果你想从这里的MainPage导航到其他页面,你可以像这样编码:

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

无需为其创建MainPage任务。