【问题标题】:Menu Item not showing in Xamarin.Forms after navigation back导航返回后 Xamarin.Forms 中未显示菜单项
【发布时间】:2017-07-22 13:10:39
【问题描述】:

我正在开发一个 Xamarin.Forms Android-App,其中 ContentPage 上的 CustomRenderer 用于在页面的标题中显示 SearchView。 “SearchPage”类的 CustomRenderer 如下所示:

 /// <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 Thread,到目前为止,我让它像魅力一样工作。 现在,如果用户点击“SearchPage”中的某个项目,则使用以下方法将一个新的 ContentPage(称为“DetailPage”)推送到 NavigationStack:

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

这没有问题。但是如果用户使用 Back-Button 从“DetailPage”导航回“SearchPage”,自定义的 Search-Header 根本不会显示

我尝试了什么:

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

所以我的问题是:

Xamarin 中有错误还是我做错了什么?

【问题讨论】:

  • 尝试覆盖OnRestart。我最近发现了一个实例,当视图被带回前面时,需要重新绑定我的列表,这是一直被调用的方法
  • 你最终选择了什么解决方案?

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


【解决方案1】:

Xamarin 中有错误还是我做错了什么?

我不能说这是一个错误,我更愿意认为这是设计使然。真正的问题是您正在尝试修改自定义渲染器中的Toolbar,并且根据您的描述,您正在使用NavigationPage,它的NavigationPageRenderer 每次当前时都会更新Toolbar 的视图页面已更改。

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

Device.StartTimer(TimeSpan.FromMilliseconds(10), () =>
{
    UpdateToolbar();
    return false;
});

所以我也不认为你做错了什么,你使用await Task.Delay(500);的方法可以快速解决这个问题。

根据您在此处的描述:

但是这个修复看起来很丑陋,如果我在使用 SearchPage 时休眠应用并恢复,Search-Widget 会显示两次。

我建议将您的SearchPage 更改为View,然后从页面中动态添加/删除此视图:

public class SearchPage : View
{
  ...
}

以及它的渲染器(其他代码相同,只是改为继承ViewRendererOnElementChanged的参数不同):

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。例如,我想在我的MainPage 中显示这个搜索视图,然后导航到 App.xaml.cs 中的MainPage

MainPage = new NavigationPage(new MainPage());

MainPage的布局:

<StackLayout>
   ...
</StackLayout>

最后覆盖MainPageOnAppearingOnDisappearing方法:

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导航到其他页面,你可以这样编码:

this.Navigation.PushAsync(new Page1());

无需为它创建PushPageAsync 任务。

【讨论】:

  • 忘了说,我之所以建议用ViewRenderer而不是PageRenderer是因为不知道你怎么又加了SearchPage,你也可以直接尝试去掉OnDisappearing.
  • 非常感谢您的出色回答!似乎这个任务延迟是必要的。我喜欢您使用视图而不是页面进行自定义呈现的想法,因此我将尝试一下。 :)
  • 添加 await Task.Delay(500); 有什么意义在 OnAppearing 方法中?
  • @user3713398,正如我在答案中所说,在NavigationPageRenderer 的源代码中,在RemovePage 方法中,它在那里被硬编码以延迟一点。
  • @GraceFeng :你的逻辑就像魅力一样。谢谢。能否请您也发送适用于 IOS 的 ViewRenderer。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-09-03
  • 2021-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-07
  • 1970-01-01
相关资源
最近更新 更多