MVVMCross中使用Acr.UserDialogs:自定义通知弹窗及实例注册问题
我来帮你一步步解决这两个问题,先搞定服务注册的报错,再实现带自定义布局的通知弹窗。
一、修复IUserDialogs注册的"instance"错误
你遇到的注册错误,核心原因是Acr.UserDialogs的实例是平台相关的,不能在跨平台的App.cs里注册,必须在Android项目的Setup类中完成平台服务的注册,具体步骤如下:
- 初始化Acr.UserDialogs到Android上下文
在Android项目的MainActivity.cs的OnCreate方法中添加初始化代码:
using Acr.UserDialogs; protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); // 把当前Activity传入,初始化UserDialogs UserDialogs.Init(this); }
- 在Setup类中注册IUserDialogs服务
找到Android项目中的Setup.cs(继承自MvxAndroidSetup<Core.App>),重写InitializePlatformServices方法:
protected override void InitializePlatformServices() { base.InitializePlatformServices(); // 注册UserDialogs的单例实例 Mvx.IoCProvider.RegisterSingleton<IUserDialogs>(UserDialogs.Instance); }
这样就能解决"object does not contain a definition for instance"的错误了——之前你可能在跨平台的App.cs里尝试访问UserDialogs.Instance,但这个属性是Android平台特有的,必须在Android项目的Setup中注册。
二、实现带自定义布局的通知弹窗
Acr.UserDialogs的默认Alert并不支持自定义布局,所以我们需要基于MVVMCross的MvxDialogFragment来实现自己的弹窗,结合你已有的notification.axml布局,步骤如下:
1. 创建自定义DialogFragment(Android项目)
新建一个CustomNotificationDialog.cs类,继承自MvxDialogFragment,用来加载你的自定义布局并传递数据:
using Android.App; using Android.OS; using Android.Views; using MvvmCross.Droid.Support.V7.AppCompat; using MvvmCross.Binding.BindingContext; namespace YourAppName.Droid.Views.Dialogs { [DialogFragment] public class CustomNotificationDialog : MvxDialogFragment { // 静态方法创建实例,传递弹窗需要的文本和图片资源ID public static CustomNotificationDialog NewInstance(string message, int imageResId) { var args = new Bundle(); args.PutString("DialogMessage", message); args.PutInt("ImageResId", imageResId); var dialog = new CustomNotificationDialog(); dialog.Arguments = args; return dialog; } public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { base.OnCreateView(inflater, container, savedInstanceState); // 加载你的自定义布局 var view = this.BindingInflate(Resource.Layout.notification, container, false); // 获取传递的参数 var message = Arguments.GetString("DialogMessage"); var imageResId = Arguments.GetInt("ImageResId"); // 给布局中的控件赋值(根据你的notification.axml调整控件ID) var tvMessage = view.FindViewById<Android.Widget.TextView>(Resource.Id.tv_notification_text); var ivIcon = view.FindViewById<Android.Widget.ImageView>(Resource.Id.iv_notification_icon); tvMessage.Text = message; ivIcon.SetImageResource(imageResId); return view; } // 可选:设置弹窗宽度为屏幕宽度 public override void OnStart() { base.OnStart(); if (Dialog != null) { Dialog.Window.SetLayout(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent); } } } }
2. 抽象弹窗服务接口(Core项目)
为了符合MVVM的跨平台原则,在Core项目中创建一个接口ICustomDialogService.cs:
namespace YourAppName.Core.Services { public interface ICustomDialogService { void ShowCustomNotification(string message, int imageResourceId); } }
3. 实现Android平台的弹窗服务(Android项目)
新建CustomDialogService.cs,实现上面的接口:
using YourAppName.Core.Services; using YourAppName.Droid.Views.Dialogs; using Android.Support.V4.App; using MvvmCross.Platforms.Android.Views; namespace YourAppName.Droid.Services { public class CustomDialogService : ICustomDialogService { public void ShowCustomNotification(string message, int imageResourceId) { // 获取当前的顶层Activity var currentActivity = Mvx.IoCProvider.Resolve<IMvxAndroidCurrentTopActivity>().Activity; var fragmentManager = (currentActivity as FragmentActivity)?.SupportFragmentManager; if (fragmentManager != null) { var dialog = CustomNotificationDialog.NewInstance(message, imageResourceId); dialog.Show(fragmentManager, "CustomNotificationDialog"); } } } }
4. 注册自定义弹窗服务(Android项目Setup类)
回到Setup.cs的InitializePlatformServices方法,添加服务注册:
protected override void InitializePlatformServices() { base.InitializePlatformServices(); Mvx.IoCProvider.RegisterSingleton<IUserDialogs>(UserDialogs.Instance); // 注册自定义弹窗服务 Mvx.IoCProvider.RegisterSingleton<ICustomDialogService>(new CustomDialogService()); }
5. 在ViewModel中调用自定义弹窗
在你的ViewModel中注入ICustomDialogService,并创建命令触发弹窗:
using MvvmCross.ViewModels; using YourAppName.Core.Services; using System.Windows.Input; using MvvmCross.Commands; namespace YourAppName.Core.ViewModels { public class YourViewModel : MvxViewModel { private readonly ICustomDialogService _customDialogService; public ICommand ShowCustomNotificationCommand { get; } public YourViewModel(ICustomDialogService customDialogService) { _customDialogService = customDialogService; ShowCustomNotificationCommand = new MvxCommand(() => { // 调用自定义弹窗,这里的图片资源ID是Android项目中的Drawable资源ID _customDialogService.ShowCustomNotification("这是自定义通知的内容", Resource.Drawable.ic_notification_icon); }); } } }
最后,在对应的View布局中,给按钮绑定这个命令:
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="显示自定义通知" local:MvxBind="Click ShowCustomNotificationCommand" />
内容的提问来源于stack exchange,提问作者NaSt

