【发布时间】:2016-03-14 18:36:57
【问题描述】:
我是 Xamarin.Forms 的新手,遇到了一种情况,我想用我的控制详细信息打开一个弹出框 [例如点击父页面查看员工详细信息。
如何使用 Xamarin.Forms 打开自定义对话框/弹出窗口?
任何示例代码将不胜感激?
提前致谢!
【问题讨论】:
标签: ipad xamarin xamarin.forms
我是 Xamarin.Forms 的新手,遇到了一种情况,我想用我的控制详细信息打开一个弹出框 [例如点击父页面查看员工详细信息。
如何使用 Xamarin.Forms 打开自定义对话框/弹出窗口?
任何示例代码将不胜感激?
提前致谢!
【问题讨论】:
标签: ipad xamarin xamarin.forms
如果您仍希望将弹出窗口的代码放在其自己的页面中,您可以按照以下逻辑设置一些自定义渲染器。
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));
}
}
2。主机页面
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/代码定义与主机页面分开,并在您希望显示该弹出窗口的任何其他页面上重复使用它。
【讨论】:
您尝试实现的一般目的可以通过使用 Xamarin.Forms 的 PushModalAsync 和 PopModalAsync 方法来实现 导航对象。
这可能足以满足您的需要 - 但是 - 这不是真正的模态。我会在一段小代码sn-p之后解释:-
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?。
注意 - 虽然您现在可以等待显示第二个页面,然后当该页面被关闭时允许代码在下一行继续执行 - 这仍然不是真正的模态表单。再次计时器或任何执行still的东西都会在父页面上被调用。
更新 1:-
要让内容显示在现有内容的顶部,然后只需将其包含在当前页面中,但是在您需要之前使这部分内容不可见。
如果您使用像 Grid 这样支持同一单元格中的多个子控件的外部容器,那么您将能够实现您想要的。
您还需要使用填充的 Box 之类的东西,其透明度也将覆盖整个页面,以控制围绕您的内部内容部分的可见、透视部分。
【讨论】:
我遵循上述方法,发现无法在 iOS 7 上运行。 我找到了这个库 BTProgressHUD,你可以修改和使用它。 我通过依赖服务使用它的方法。 弹出窗口的实际库。 https://github.com/nicwise/BTProgressHUD
以下示例在内部使用 BTProgressHUD 库。
【讨论】: