如何使用Xamarin.Forms打开自定义对话框/弹出窗口?

时间:2014-09-22 10:59:48

标签: ipad xamarin xamarin.forms

我是Xamarin.Forms的新手并且遇到了我想打开一个带有我的控制细节的弹出框的情况[例如单击父页面查看“员工详细信息”。

如何使用Xamarin.Forms打开自定义对话框/弹出窗口?

任何示例代码都会受到赞赏吗?

提前致谢!

3 个答案:

答案 0 :(得分:15)

如果您仍希望将弹出式代码放在自己的页面中,可以按照以下逻辑设置一些自定义渲染器。

<强> 1。 ModalPage&amp;相应的渲染器

public class ModalPage : ContentPage { }

public class ModalPageRenderer : PageRenderer {
    protected override void OnElementChanged(VisualElementChangedEventArgs e)
    {
        base.OnElementChanged(e);
        this.View.BackgroundColor = UIColor.Clear;
        this.ModalPresentationStyle = UIModalPresentationStyle.OverCurrentContext;
    }

    public override void ViewDidLayoutSubviews()
    {
        base.ViewDidLayoutSubviews();
        SetElementSize (new Size (View.Bounds.Width, View.Bounds.Height));
    } 
}

<强> 2。 HostPage

public class ModalHostPage : ContentPage, IModalHost
{
    #region IModalHost implementation

    public Task DisplayPageModal(Page page)
    {
        var displayEvent = DisplayPageModalRequested;

        Task completion = null;
        if (displayEvent != null)
        {
            var eventArgs = new DisplayPageModalRequestedEventArgs(page);
            displayEvent(this, eventArgs);
            completion = eventArgs.DisplayingPageTask;
        }

        // If there is no task, just create a new completed one
        return completion ?? Task.FromResult<object>(null);
    }

    #endregion

    public event EventHandler<DisplayPageModalRequestedEventArgs> DisplayPageModalRequested;

    public sealed class DisplayPageModalRequestedEventArgs : EventArgs
    {
        public Task DisplayingPageTask { get; set;}

        public Page PageToDisplay { get; }

        public DisplayPageModalRequestedEventArgs(Page modalPage)
        {
            PageToDisplay = modalPage;
        }
    }
}

第3。 HostPage渲染器

public class ModalHostPageRenderer: PageRenderer
{
    protected override void OnElementChanged(VisualElementChangedEventArgs e)
    {
        base.OnElementChanged(e);

        if(e.OldElement as ModalHostPage != null)
        {
            var hostPage = (ModalHostPage)e.OldElement;
            hostPage.DisplayPageModalRequested -= OnDisplayPageModalRequested;
        }

        if (e.NewElement as ModalHostPage != null)
        {
            var hostPage = (ModalHostPage)e.NewElement;
            hostPage.DisplayPageModalRequested += OnDisplayPageModalRequested;
        }
    }

    void OnDisplayPageModalRequested(object sender, ModalHostPage.DisplayPageModalRequestedEventArgs e)
    {
        e.PageToDisplay.Parent = this.Element;
        var renderer = RendererFactory.GetRenderer (e.PageToDisplay);
        e.DisplayingPageTask = this.PresentViewControllerAsync(renderer.ViewController, true);
    }
}

然后就像打电话一样简单 await ModalHost.DisplayPageModal(new PopUpPage()); 从您的主机页面或在此特定情况下从后面的ViewModel。

Pete所说的关于PushModalAsync / PopModalAsync的内容对于这个解决方案仍然有效(我认为这不是一个缺点),但你的弹出窗口会以透明的背景出现。

在我看来,这种方法的主要优点是,您可以将弹出式XAML /代码定义与主机页面分开,并在您希望显示该弹出窗口的任何其他页面上重复使用它。

答案 1 :(得分:3)

您尝试实现的目标的一般目的可以通过使用 Xamarin.Forms PushModalAsync 和 PopModalAsync 方法来实现>导航对象。

这可能足以满足您的需求 - 然而 - 这不是真正的模态。我将在一个小代码片段后解释: -

        StackLayout objStackLayout = new StackLayout()
        {
        };
        //
        Button cmdButton_LaunchModalPage = new Button();
        cmdButton_LaunchModalPage.Text = "Launch Modal Window";
        objStackLayout.Children.Add(cmdButton_LaunchModalPage);
        //
        cmdButton_LaunchModalPage.Clicked += (async (o2, e2) =>
        {
            ContentPage objModalPage = new ContentPage();
            objModalPage.Content = await CreatePageContent_Page2();
            //
            await Navigation.PushModalAsync(objModalPage);
            //
            // Code will get executed immediately here before the page is dismissed above.
        });
        //
        return objStackLayout;



    private async Task<StackLayout> CreatePageContent_Page2()
    {
        StackLayout objStackLayout = new StackLayout()
        {
        };
        //
        Button cmdButton_CloseModalPage = new Button();
        cmdButton_CloseModalPage.Text = "Close";
        objStackLayout.Children.Add(cmdButton_CloseModalPage);
        //
        cmdButton_CloseModalPage.Clicked += ((o2, e2) =>
        {
            this.Navigation.PopModalAsync();
        });
        //
        return objStackLayout;
    }

以上问题是

            await Navigation.PushModalAsync(objModalPage);
动画后

会立即返回。

虽然您无法与上一页进行互动,因为我们正在显示一个新的 NavigationPage ,并显示关闭按钮 - 父级 导航页面仍在幕后并行执行。

所以,如果你有任何计时器或任何执行这些计时器仍然会被调用,除非你停止了。

您还可以使用 TaskCompletionSource 方法,如以下帖子How can I await modal form dismissal using Xamarin.Forms?中所述。

注意 - 尽管您现在可以等待显示第二页,然后当该页面被解除时允许代码执行在下一行继续 - 这仍然不是一个模态形式即可。再次定时器或任何执行仍然的内容将在父页面上被调用。

更新1: -

要让内容显示在现有内容的顶部,只需将其包含在当前页面上,但是在您需要之前,请将此部分内容隐藏起来。

如果你在同一个单元格中使用支持多个子控件的 Grid 之类的外部容器,那么你将能够达到你想要的效果。

您还需要使用填充 Box 之类的内容,其透明度也会覆盖整个页面,以控制内部内容部分周围的可见,透视部分。

答案 2 :(得分:0)

我遵循上述方法,发现无法在iOS 7上运行。 我发现这个库BTProgressHUD你可以修改和使用。 我通过依赖服务使用它的方法。 弹出窗口的实际库。 https://github.com/nicwise/BTProgressHUD

以下示例在内部使用BTProgressHUD库。

https://github.com/xximjasonxx/ScorePredictForms