MvvmCross对话框

MvvmCross对话框,mvvm,dialog,modal-dialog,mvvmcross,Mvvm,Dialog,Modal Dialog,Mvvmcross,我目前正在调查所有可能的解决方案,以便在用户需要做出决定时通知用户(即弹出对话框)。这是MVVM模式的一个常见问题,我正在尝试为MvvmCross框架解决它 可能的解决办法可以是: 自定义MvxPresenter以显示对话框,但这在我看来有点难看 在核心项目中放置一个对话框界面,并使用控制反转将UI项目的实现注入到核心项目中 使用MvxMessenger插件并在Core和UI项目之间共享消息。听起来是个好主意,但开发起来可能更复杂 您有什么建议?对话框输入是一个有趣的主题,并不总是适合Mvv

我目前正在调查所有可能的解决方案,以便在用户需要做出决定时通知用户(即弹出对话框)。这是MVVM模式的一个常见问题,我正在尝试为MvvmCross框架解决它

可能的解决办法可以是:

  • 自定义MvxPresenter以显示对话框,但这在我看来有点难看
  • 在核心项目中放置一个对话框界面,并使用控制反转将UI项目的实现注入到核心项目中
  • 使用MvxMessenger插件并在Core和UI项目之间共享消息。听起来是个好主意,但开发起来可能更复杂

您有什么建议?

对话框输入是一个有趣的主题,并不总是适合Mvvm数据绑定的流程

通常,对话框的一些用例用于以下情况:

  • 向“提交”按钮添加“是/否确认”选项
  • 请求额外的单一输入-例如从列表中选择
  • 提供操作选择(例如删除、编辑或复制?)
  • 提供确认信息
  • 请求其他复杂输入-例如收集一组firstname/lastname/age/accept_术语字段
  • 对于其中一些项目,我建议主要将其建模为纯粹的视图关注点。例如,请求单个项目选择通常是从复合控件标签中完成的,该标签在点击时显示“选择器”-例如,类似于中的MvxSpinner

    对于一般情况,如果您希望共享ViewModels来驱动用户流,那么MvvmCross中可用的选项包括您列出的3个选项,所有这些选项对我来说都是可行的,但我同意没有一个是完美的

    作为另外一个建议,微软的模式和实践团队提出了一个很好的架构建议。在中,他们建议使用
    IInteractionRequest
    接口,该接口可在数据绑定中使用,特别是在这种情况下

    这方面的参考实施是:

    public interface IInteractionRequest
    {
        event EventHandler<InteractionRequestedEventArgs> Raised;
    }
    
        public class InteractionRequestedEventArgs : EventArgs
        {
           public Action Callback { get; private set; }
           public object Context { get; private set; }
           public InteractionRequestedEventArgs(object context, Action callback)
           {
               Context = context;
               Callback = callback;
           }
        }
    
    public class InteractionRequest<T> : IInteractionRequest
    {
        public event EventHandler<InteractionRequestedEventArgs> Raised;
    
        public void Raise(T context, Action<T> callback)
        {
            var handler = this.Raised;
            if (handler != null)
            {
                handler(
                    this, 
                    new InteractionRequestedEventArgs(
                        context, 
                        () => callback(context)));
            }
        }
    }
    
    private InteractionRequest<Confirmation> _confirmCancelInteractionRequest = new InteractionRequest<Confirmation>();
    public IInteractionRequest ConfirmCancelInteractionRequest
    {
        get
        {
            return _confirmCancelInteractionRequest;
        }
    }
    
    其中,
    Confirmation
    是一个简单的类,如:

        public class Confirmation
        {
            public string Message { get; private set; }
            public bool Confirmed { get; set; }
            public Confirmation(string message)
            {
               Message = message;
            }
        }
    
    要在视图中使用此选项,请执行以下操作:

    MSDN链接显示了Xaml客户机如何使用行为绑定到该数据库,因此我在这里不作进一步介绍

    在iOS for MvvmCross中,视图对象可能实现如下属性:

    private MvxGeneralEventSubscription _confirmationSubscription;
    private IInteractionRequest _confirmationInteraction;
    public IInteractionRequest ConfirmationInteraction
    {
        get { return _confirmationInteraction; }
        set
        {
            if (_confirmationInteraction == value)
                return;
            if (_confirmationSubscription != null)
                _confirmationSubscription.Dispose();
            _confirmationInteraction = value;
            if (_confirmationInteraction != null)
                _confirmationSubscription = _confirmationInteraction
                    .GetType()
                    .GetEvent("Raised")
                    .WeakSubscribe(_confirmationInteraction, 
                       DoConfirmation);
        }
    }
    
    此视图属性使用基于
    WeakReference
    的事件订阅,以便将ViewModel
    引发的
    事件引导至视图
    消息框
    -类型方法。使用
    WeakReference
    非常重要,这样ViewModel就不会引用
    视图
    ——这可能会导致Xamarin.iOS中的内存泄漏问题。实际的
    MessageBox
    类型方法本身相当简单,类似于:

    private void DoConfirmation(InteractionRequestedEventArgs args)
    {
        var confirmation = (Confirmation)args.Context;
    
        var alert = new UIAlertView(); 
        alert.Title = "Bazinga"; 
        alert.Message = confirmation.Message; 
    
        alert.AddButton("Yes"); 
        alert.AddButton("No"); 
    
        alert.Clicked += (sender, e) => { 
           var alertView = sender as UIAlertView; 
    
           if (e.ButtonIndex == 0) 
           { 
              // YES button
              confirmation.Confirmed = true;
           } 
           else if (e.ButtonIndex == 1) 
           { 
              // NO button
              confirmation.Confirmed = false; 
           } 
    
           args.Callback();
        }; 
    }
    
    属性可以绑定在一个流畅的绑定集中,如:

    set.Bind(this)
       .For(v => v.ConfirmationInteraction)
       .To(vm => vm.ConfirmCancelInteractionRequest);
    
    对于Android,可以使用类似的实现—这可能使用
    对话框片段
    ,也可能使用XML中的
    视图
    进行绑定

    注意:

    • 我相信,如果我们进一步添加
      IInteractionRequest
      InteractionRequestedEventArgs
      定义,基本交互可以得到改进(在我看来)-但是,就这个答案的范围而言,我尽量保持“基本”实现,尽可能接近
    • 一些附加的助手类也可以帮助显著简化视图订阅代码

    你可以使用Brian Chance

    正如Eugene所说,使用用户交互插件。不幸的是,目前还没有Windows Phone实现,因此我在此期间使用了以下代码:

    public class WindowsPhoneUserInteraction : IUserInteraction
    {
        public void Confirm(string message, Action okClicked, string title = null, string okButton = "OK", string cancelButton = "Cancel")
        {
            Confirm(message, confirmed =>
            {
                if (confirmed)
                    okClicked();
            },
            title, okButton, cancelButton);
        }
    
        public void Confirm(string message, Action<bool> answer, string title = null, string okButton = "OK", string cancelButton = "Cancel")
        {
            var mbResult = MessageBox.Show(message, title, MessageBoxButton.OKCancel);
            if (answer != null)
                answer(mbResult == MessageBoxResult.OK);
        }
    
        public Task<bool> ConfirmAsync(string message, string title = "", string okButton = "OK", string cancelButton = "Cancel")
        {
            var tcs = new TaskCompletionSource<bool>();
            Confirm(message, tcs.SetResult, title, okButton, cancelButton);
            return tcs.Task;
        }
    
        public void Alert(string message, Action done = null, string title = "", string okButton = "OK")
        {
            MessageBox.Show(message, title, MessageBoxButton.OK);
            if (done != null)
                done();
        }
    
        public Task AlertAsync(string message, string title = "", string okButton = "OK")
        {
            var tcs = new TaskCompletionSource<object>();
            Alert(message, () => tcs.SetResult(null), title, okButton);
            return tcs.Task;
        }
    
        public void Input(string message, Action<string> okClicked, string placeholder = null, string title = null, string okButton = "OK", string cancelButton = "Cancel", string initialText = null)
        {
            throw new NotImplementedException();
        }
    
        public void Input(string message, Action<bool, string> answer, string placeholder = null, string title = null, string okButton = "OK", string cancelButton = "Cancel", string initialText = null)
        {
            throw new NotImplementedException();
        }
    
        public Task<InputResponse> InputAsync(string message, string placeholder = null, string title = null, string okButton = "OK", string cancelButton = "Cancel", string initialText = null)
        {
            throw new NotImplementedException();
        }
    
        public void ConfirmThreeButtons(string message, Action<ConfirmThreeButtonsResponse> answer, string title = null, string positive = "Yes", string negative = "No", string neutral = "Maybe")
        {
            throw new NotImplementedException();
        }
    
        public Task<ConfirmThreeButtonsResponse> ConfirmThreeButtonsAsync(string message, string title = null, string positive = "Yes", string negative = "No", string neutral = "Maybe")
        {
            throw new NotImplementedException();
        }
    }
    
    公共类WindowsPhoneUserInteraction:IUserInteraction
    {
    public void Confirm(字符串消息,操作已单击,字符串标题=null,字符串okButton=“确定”,字符串cancelButton=“取消”)
    {
    确认(消息,确认=>
    {
    如果(已确认)
    okClicked();
    },
    标题、确认按钮、取消按钮);
    }
    public void Confirm(字符串消息、操作应答、字符串标题=null、字符串okButton=“确定”、字符串cancelButton=“取消”)
    {
    var mbResult=MessageBox.Show(消息、标题、MessageBoxButton.OKCancel);
    如果(回答!=null)
    回答(mbResult==MessageBoxResult.OK);
    }
    公共任务确认同步(字符串消息,字符串标题=“确定”,字符串取消按钮=“取消”)
    {
    var tcs=new TaskCompletionSource();
    确认(消息、tcs.SetResult、标题、确定按钮、取消按钮);
    返回tcs.Task;
    }
    公共作废警报(字符串消息,操作完成=null,字符串标题=,字符串okButton=“确定”)
    {
    MessageBox.Show(消息、标题、MessageBoxButton.OK);
    如果(完成!=null)
    完成();
    }
    公共任务AlertAsync(字符串消息,字符串标题=,字符串okButton=“确定”)
    {
    var tcs=new TaskCompletionSource();
    警报(消息,()=>tcs.SetResult(null)、标题、OK按钮);
    返回tcs.Task;
    }
    公共无效输入(字符串消息,单击操作OK,字符串占位符=null,字符串标题=null,字符串OK按钮=“OK”,字符串cancelButton=“取消”,字符串initialText=null)
    {
    抛出新的NotImplementedException();
    }
    公共无效输入(字符串消息、操作答案、字符串占位符=null、字符串标题=null、字符串okButton=“OK”、字符串cancelButton=“Cancel”、字符串initialText=null)
    {
    抛出新的NotImplementedException();
    }
    公共任务InputAsync(字符串消息,字符串占位符=null,字符串标题=null,字符串okButton=“确定”,字符串cancelButton=“取消”,字符串initialText=null)
    {
    抛出新的NotImplementedException();
    }
    public void ConfirmThreeButtons(字符串消息、操作应答、字符串标题=null、字符串
    
    public class WindowsPhoneUserInteraction : IUserInteraction
    {
        public void Confirm(string message, Action okClicked, string title = null, string okButton = "OK", string cancelButton = "Cancel")
        {
            Confirm(message, confirmed =>
            {
                if (confirmed)
                    okClicked();
            },
            title, okButton, cancelButton);
        }
    
        public void Confirm(string message, Action<bool> answer, string title = null, string okButton = "OK", string cancelButton = "Cancel")
        {
            var mbResult = MessageBox.Show(message, title, MessageBoxButton.OKCancel);
            if (answer != null)
                answer(mbResult == MessageBoxResult.OK);
        }
    
        public Task<bool> ConfirmAsync(string message, string title = "", string okButton = "OK", string cancelButton = "Cancel")
        {
            var tcs = new TaskCompletionSource<bool>();
            Confirm(message, tcs.SetResult, title, okButton, cancelButton);
            return tcs.Task;
        }
    
        public void Alert(string message, Action done = null, string title = "", string okButton = "OK")
        {
            MessageBox.Show(message, title, MessageBoxButton.OK);
            if (done != null)
                done();
        }
    
        public Task AlertAsync(string message, string title = "", string okButton = "OK")
        {
            var tcs = new TaskCompletionSource<object>();
            Alert(message, () => tcs.SetResult(null), title, okButton);
            return tcs.Task;
        }
    
        public void Input(string message, Action<string> okClicked, string placeholder = null, string title = null, string okButton = "OK", string cancelButton = "Cancel", string initialText = null)
        {
            throw new NotImplementedException();
        }
    
        public void Input(string message, Action<bool, string> answer, string placeholder = null, string title = null, string okButton = "OK", string cancelButton = "Cancel", string initialText = null)
        {
            throw new NotImplementedException();
        }
    
        public Task<InputResponse> InputAsync(string message, string placeholder = null, string title = null, string okButton = "OK", string cancelButton = "Cancel", string initialText = null)
        {
            throw new NotImplementedException();
        }
    
        public void ConfirmThreeButtons(string message, Action<ConfirmThreeButtonsResponse> answer, string title = null, string positive = "Yes", string negative = "No", string neutral = "Maybe")
        {
            throw new NotImplementedException();
        }
    
        public Task<ConfirmThreeButtonsResponse> ConfirmThreeButtonsAsync(string message, string title = null, string positive = "Yes", string negative = "No", string neutral = "Maybe")
        {
            throw new NotImplementedException();
        }
    }
    
    Mvx.RegisterSingleton<IUserInteraction>(new WindowsPhoneUserInteraction());