【问题标题】:await for a PushModalAsync form to closed in xamarin forms等待 PushModalAsync 表单以 xamarin 表单关闭
【发布时间】:2016-09-23 04:59:36
【问题描述】:

我有一个页面,点击工具栏上的加号按钮,我正在调用一个弹出页面

从弹出页面用户可以添加新条目或取消/关闭窗口而无需执行任何操作

一切正常,代码是这样的

    public partial class SelectSchool : ContentPage
    {
        public SelectSchool()
        {
            InitializeComponent();
            #region toolbar
            ToolbarItem tbi = null;
            if (Device.OS == TargetPlatform.Android)
            {
                tbi = new ToolbarItem("+", "plus", async () =>
                {
                    var target_page = new AddSchool(); 
                    Navigation.PushModalAsync(target_page);                                 
                }, 0,0);
            }
            ToolbarItems.Add(tbi);
            #endregion

            this.Title = "Select School";

        }
    }

我的弹出页面就像

     public partial class AddSchool : ContentPage
    {
        public AddSchool()
        {
            InitializeComponent();
        }
        private async void Button_OK_Clicked(object sender, EventArgs e)
        {
        //doing some operations like entry to db etc and close page
             Navigation.PopModalAsync();

        }
        private void cancelClicked(object sender, EventArgs e)
        {
            Navigation.PopModalAsync();
        }
    }

但现在我想等待弹出窗口关闭以进行一些额外的编码,我尝试了下面的代码

 if (Device.OS == TargetPlatform.Android)
            {
                tbi = new ToolbarItem("+", "plus", async () =>
                {
                    var target_page = new AddSchool(); 
                    await Navigation.PushModalAsync(target_page);  
                    //await till target_page is closed and once its closed call my next function here               
                }, 0,0);
            }

但是等待不起作用。在弹出窗口关闭之前,我如何在该区域等待?有什么想法吗??

【问题讨论】:

标签: c# xamarin async-await xamarin.forms


【解决方案1】:

在模态页面上使用Disappearing 事件。

示例:

var modalPage = new ContentPage();
modalPage.Disappearing += (sender2, e2) =>
{
    System.Diagnostics.Debug.WriteLine("The modal page is dismissed, do something now");
};
await content.Navigation.PushModalAsync(modalPage);
System.Diagnostics.Debug.WriteLine("The modal page is now on screen, hit back button");

或者使用EventWaitHandle:

var waitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
var modalPage = new ContentPage();
modalPage.Disappearing += (sender2, e2) =>
{
    waitHandle.Set();
};
await content.Navigation.PushModalAsync(modalPage);
System.Diagnostics.Debug.WriteLine("The modal page is now on screen, hit back button");
await Task.Run(() => waitHandle.WaitOne());
System.Diagnostics.Debug.WriteLine("The modal page is dismissed, do something now");

【讨论】:

  • 不知道将哪一个标记为答案??两个方面都很好:)
  • @JibinMathew 我个人喜欢使用EventWaitHandle,因为代码/逻辑流是顺序的,这在考虑模态窗口流时具有线性意义,并且它需要的更少代码然后创建/处理其他事件处理程序....即当前代码路径将不会继续,直到用户关闭窗口。这当然是个人选择,因为有很多方法可以获得与您所看到的相同的结果。 ;-)
  • 在许多其他情况下页面可能会消失(例如最小化应用程序或导航到其他页面表单弹出窗口),因此取决于 Disappearing 事件可能会导致问题。
  • @raV720 您可以在这种情况下使用 Current.On() .SendDisappearingEventOnPause(false) .SendAppearingEventOnResume(false) 禁用 onDissapearing 调用;
【解决方案2】:

这里的答案有点晚,但最好听一下应用程序的OnModalPagePopping 事件处理程序。

首先,创建模态页面。给它一个属性来存储你以后要检索的数据:

public class MyModalPage : ContentPage
{
    public string Data { get; set; }

    public MyModalPage()
    {
        InitializeComponent();
        // ... set up the page ...
    }

    private async void PopThisPage()
    {
        // When you want to pop the page, just call this method
        // Perhaps you have a text view with x:Name="PhoneNumber", for example
        Data = PhoneNumber.Text; // store the "return value" before popping
        await MyProject.App.Current.MainPage.Navigation.PopModalAsync();
    }
}

在父页面中,你可以创建模态页面,并设置事件处理程序来监听模态页面何时弹出:

public class MyPage : ContentPage
{
    MyModalPage _myModalPage;

    public MyPage()
    {
        InitializeComponent();
        // ... set up the page ...
    }

    private async void ShowModalPage()
    {
        // When you want to show the modal page, just call this method
        // add the event handler for to listen for the modal popping event:
        MyProject.App.Current.ModalPopping += HandleModalPopping;
        _myModalPage = new MyModalPage();
        await MyProject.App.Current.MainPage.Navigation.PushModalAsync(_myModalPage());
    }

    private void HandleModalPopping(object sender, ModalPoppingEventArgs e)
    {
        if (e.Modal == _myModalPage)
        {
            // now we can retrieve that phone number:
            var phoneNumber = _myModalPage.Data;
            _myModalPage = null;

            // remember to remove the event handler:
            MyProject.App.Current.ModalPopping -= HandleModalPopping;
        }
    }

}

这比使用OnDisappearing 方法要好,因为其他人已经说过可以在应用程序后台运行时调用等。并且其行为跨平台并不一致。

还有另一个事件OnModalPopped,在modal完全从导航栈弹出后调用。如果使用它,它应该类似地工作。

【讨论】:

  • 我正在使用 OnModalPopped。 +1 通过删除处理程序来避免泄漏。
【解决方案3】:

你可以尝试创建一个事件,pop close时调用。

public partial class AddSchool : ContentPage
{
    public delegate void PopupClosedDelegate();

    public event PopupClosedDelegate PopupClosed;

    public AddSchool()
    {
        InitializeComponent();
    }
    private async void Button_OK_Clicked(object sender, EventArgs e)
    {
        //doing some operations like entry to db etc and close page
        await Navigation.PopModalAsync();
        if (PopupClosed!=null)
        {
            PopupClosed();
        }
    }
    private async void cancelClicked(object sender, EventArgs e)
    {
        await Navigation.PopModalAsync();
        if (PopupClosed != null)
        {
            PopupClosed();
        }
    }
}

我把它放在按钮点击事件上,也许你可以把它放在关闭或处置事件上。然后这里是实现

public partial class SelectSchool : ContentPage
{
    public SelectSchool()
    {
        InitializeComponent();
        #region toolbar
        ToolbarItem tbi = null;
        if (Device.OS == TargetPlatform.Android)
        {
            tbi = new ToolbarItem("+", "plus", async () =>
            {
                var target_page = new AddSchool();
                target_page.PopupClosed += () => { /*Do something here*/ };
                Navigation.PushModalAsync(target_page);
            }, 0, 0);
        }
        ToolbarItems.Add(tbi);
        #endregion

        this.Title = "Select School";

    }
}

希望对您有所帮助。

【讨论】:

  • 不知道将哪一个标记为答案??两个方面都很好:)
【解决方案4】:

我为此创建了一个扩展方法:

public static class DialogUtils
{
    public static async Task ShowPageAsDialog(this INavigation navigation, Page page)
    {
        int pagesOnStack = navigation.NavigationStack.Count + 1;
        var waitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
        page.Disappearing += (s, e) =>
        {
            if (navigation.NavigationStack.Count <= pagesOnStack)
                waitHandle.Set();
        };
        await navigation.PushAsync(page);
        await Task.Run(() => waitHandle.WaitOne());
    }
}

我可以使用它:

private async void bShowDialogPage_Clicked(object sender, EventArgs e)
{
    var page = new DialogPage();
    await page.LoadData();
    await Navigation.ShowPageAsDialog(page);
    var result = page.PageResult;
}

它支持对话框页面显示另一个页面的情况。由于 NavigationPage 和 BackButton,我更喜欢 NavigationStack 而不是 ModalStack。

【讨论】:

    【解决方案5】:

    实现此目的的另一种方法是从页面的 OnDisapearing 方法调用事件,然后您创建的导航服务可以订阅此事件,然后您可以使用 "TaskCompletionSource" 来等待您的页面完成工作然后完成任务。 有关完成此操作的更多详细信息,you can check this blog post.

    这是基本页面的实现,这个演示应用中的每个页面都继承了这个页面:

    public class BasePage<T> : ContentPage
    {
        public event Action<T> PageDisapearing;
        protected T _navigationResut;
    
        public BasePage()
        {
        }
    
        protected override void OnDisappearing()
        {
            PageDisapearing?.Invoke(_navigationResut);
            if (PageDisapearing != null)
            {
                foreach (var @delegate in PageDisapearing.GetInvocationList())
                {
                    PageDisapearing -= @delegate as Action<T>;
                }
            }
            base.OnDisappearing();
        }
    }
    

    以下是您应该使用的导航服务的概述:

    public async Task<T> NavigateToModal<T>(string modalName)
        {
            var source = new TaskCompletionSource<T>();
            if (modalName == nameof(NewItemPage))
            {
                var page = new NewItemPage();
                page.PageDisapearing += (result) =>
                {
                    var res = (T)Convert.ChangeType(result, typeof(T));
                    source.SetResult(res);
                };
                await App.Current.MainPage.Navigation.PushModalAsync(new NavigationPage(page));
            }
            return await source.Task;
        }
    

    要使用导航服务调用此页面,可以使用以下代码:

     var item = await new SimpleNavigationService().NavigateToModal<Item>(nameof(NewItemPage));
            Items.Add(item);
    

    【讨论】:

      猜你喜欢
      • 2016-03-13
      • 2018-04-02
      • 2020-07-10
      • 2019-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-20
      • 1970-01-01
      相关资源
      最近更新 更多