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

Nir*_*hta 9 ipad xamarin xamarin.forms

我是Xamarin.Forms的新手,并且遇到了一种情况,我想打开一个带有我的控件详细信息的弹出框[例如查看员工详细信息]点击父页面.

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

任何示例代码将不胜感激?

提前致谢!

Gab*_*bor 15

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

1. ModalPage和相应的渲染器

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));
    } 
}
Run Code Online (Sandbox Code Playgroud)

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后就像await ModalHost.DisplayPageModal(new PopUpPage()); 从主机页面调用一样简单,或者从后面的ViewModel 调用 此特定情况.

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

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

  • 简单的演示应用程序在这里:https://github.com/gaborv/xam-forms-transparent-modal (2认同)

Pet*_*ete 3

您想要实现的一般目的可以通过使用Xamarin.Forms NavigationPushModalAsyncPopModalAsync方法来实现 来实现。

很可能这足以满足您的需要 -但是- 这并不是真正的模态。我将在一小段代码之后进行解释:-

        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;
    }
Run Code Online (Sandbox Code Playgroud)

上述问题的问题在于

            await Navigation.PushModalAsync(objModalPage);
Run Code Online (Sandbox Code Playgroud)

动画结束后会立即返回。

尽管您无法与上一页进行交互,但由于我们正在显示一个新的导航页面并显示关闭按钮 - 导航页面仍在幕后并行执行。

因此,如果您有任何计时器或任何执行的东西,除非您停止它们,否则它们仍然会被调用。

您还可以使用下面的文章中概述的TaskCompletionSource方法,以及如何使用 Xamarin.Forms 等待模态表单解除?

请注意,虽然您现在可以等待第二页显示,然后当该页被关闭时允许代码在下一行继续执行,但这仍然不是真正的模态形式。同样,计时器或任何正在执行的内容都会在父页面上被调用。

更新 1:-

要使内容显示在现有内容的顶部,只需将其包含在当前页面上,但是在需要之前使这部分内容不可见。

如果您使用像Grid这样的外部容器,支持同一单元格中的多个子控件,那么您将能够实现您想要的。

您还需要使用类似具有透明度的填充之类的东西,该框也将覆盖整个页面,以控制围绕内部内容部分的可见、透明部分。