MvvmCross对话框 [英] MvvmCross Dialog

查看:188
本文介绍了MvvmCross对话框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在调查所有可能的解决方案,以便能够通知用户,即弹出对话框,当他需要做出决定。这是MVVM模式的常见问题,我正在为MvvmCross框架解决问题。



可能的解决方案可能是:




  • 自定义MvxPresenter可以显示对话框,但对我来说看起来有点丑陋

  • 将对话框界面放在Core项目中并使用反转控制将UI项目的实现注入到Core项目中

  • 使用MvxMessenger插件,并在Core和UI项目之间共享消息。听起来像个好主意,但可能更复杂的发展...



你会建议什么?

解决方案

对话框输入是一个有趣的话题,并不总是适合Mvvm Data-Binding的流程。



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


  1. 向提交按钮添加yes / no确认选项

  2. 请求额外的单个输入 - 例如

  3. 提供一系列动作(例如删除,编辑或重复?)

  4. 提供确认消息

  5. 请求额外的复杂输入 - 例如收集一组firstname / lastname / age / accept_terms字段

对于其中一些项目,我建议主要可以是模仿为纯粹的观点关注。例如,请求单项选择通常由复合控件标签完成,复制控件标签在点击时显示选择器。像一个MvxSpinner在 https ://github.com/slodge/MvvmCross-Tutorials/blob/master/ApiExamples/ApiExamples.Droid/Resources/Layout/Test_Spinner.axml#L16



对于一般情况,您希望共享的ViewModels驱动用户流程,则Mvv​​mCross中可用的选项包括3个列表,所有这些列表对我来说都是可行的,但我同意,它们都不是完美的。 p>

作为一个额外的建议,一个不错的建筑建议来自微软的模式和实践团队。在 http://msdn.microsoft.com/en -us / library / gg405494(v = pandp.40).aspx ,他们建议一个 IInteractionRequest 接口,可以在数据绑定中使用,特别是对于此类型的情况。



他们的参考实现是:

  public接口IInteractionRequest 
{
事件EventHandler< InteractionRequestedEventArgs>上调;
}

public class InteractionRequestedEventArgs:EventArgs
{
public Action Callback {get;私人集合}
public object Context {get;私人集合
public InteractionRequestedEventArgs(对象上下文,Action回调)
{
上下文=上下文;
回调=回调;
}
}

public class InteractionRequest< T> :IInteractionRequest
{
public event EventHandler< InteractionRequestedEventArgs>上调;

public void Raise(T context,Action< T> callback)
{
var handler = this.Raised;
if(handler!= null)
{
处理程序(
this,
new InteractionRequestedEventArgs(
context,
()=>回调(上下文)));
}
}
}

示例ViewModel使用此是:

  private InteractionRequest< Confirmation> _confirmCancelInteractionRequest = new InteractionRequest< Confirmation>(); 
public IInteractionRequest ConfirmCancelInteractionRequest
{
get
{
return _confirmCancelInteractionRequest;
}
}

,ViewModel可以使用以下方式提出:

  _confirmCancelInteractionRequest.Raise(
new确认(你确定要取消?),
确认=
{
if(confirmation.Confirmed)
{
this.NavigateToQuestionnaireList();
}
});
}

其中确认一个简单的类,如:

  public class Confirmation 
{
public string Message {get;私人集合}
public bool确认{get;组;
public Confirmation(string message)
{
Message = message;
}
}

在Views:



MSDN链接显示了Xaml客户端如何使用行为绑定到这个 - 所以我不会在这里进一步介绍。



在iOS中,对于MvvmCross,View对象可能会实现以下属性:

  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);
}
}

此View属性使用为了将ViewModel 提升事件到视图 MessageBox 型方法。使用 WeakReference 非常重要,以便ViewModel从不具有对 View 的引用 - 这些可能会导致内存泄漏问题在Xamarin.iOS。实际的 MessageBox -type方法本身将是相当简单的,如:

  private void DoConfirmation(InteractionRequestedEventArgs args)
{
var confirmation =(Confirmation)args.Context;

var alert = new UIAlertView();
alert.Title =Bazinga;
alert.Message = confirmation.Message;

alert.AddButton(是);
alert.AddButton(否);

alert.Clicked + =(sender,e)=> {
var alertView = sender as UIAlertView;

if(e.ButtonIndex == 0)
{
//是按钮
confirm.Confirmed = true;
}
else if(e.ButtonIndex == 1)
{
// NO按钮
confirm.Confirmed = false;
}

args.Callback();
};
}

该属性可以绑定在流动绑定集中,如:


  set.Bind(this)
.For(v => v.ConfirmationInteraction)
.To(vm => vm.ConfirmCancelInteractionRequest);

对于Android,可以使用类似的实现 - 这可能使用 DialogFragment ,也可能使用XML中的 View 绑定。



注意:




  • 我相信如果我们进一步添加了 IInteractionRequest< T> InteractionRequestedEventArgs< T> 定义,基本交互可以得到改善 - 但是,对于这个答案的范围,我保持基本的实现尽可能接近于 http://msdn.microsoft.com/en-us/library/gg405494(v = pandp.40).aspx

  • 一些额外的助手类也可以帮助大大简化视图订阅代码


I am currently investigating all possible solutions to be able to inform the user, ie pop a dialog, when there is a decision he needs to make. This is a common problem with MVVM pattern and I am trying to solve it for MvvmCross framework.

Possible solutions could be:

  • Customize the MvxPresenter to be able to show dialogs, but that looks a bit ugly to me
  • Put a Dialog interface in the Core project and use Inversion of Control to inject the implementation from the UI project to the Core project
  • Use the MvxMessenger plugin and share messages between the Core and UI project. Sounds like a good idea but maybe more complicated to develop...

What would you suggest?

解决方案

Dialog input is an interesting topic that doesn't always fit well with the flow of Mvvm Data-Binding.

Generally, some use cases of Dialogs are for things like:

  1. adding a yes/no confirm option to a submit button
  2. requesting additional single input - e.g. a selection from a list
  3. offering a choice of actions (e.g. delete, edit or duplicate?)
  4. offering a confirmation message
  5. requesting additional complex input - e.g. collecting a set of firstname/lastname/age/accept_terms field

For some of these items, I'd suggest that mainly these could be modelled as purely View concerns. For example, requesting single item selection is commonly done from compound controls labels which display 'pickers' when tapped - e.g. like an MvxSpinner in https://github.com/slodge/MvvmCross-Tutorials/blob/master/ApiExamples/ApiExamples.Droid/Resources/Layout/Test_Spinner.axml#L16

For general cases, where you want the shared ViewModels to drive the user flow, then options which are available within MvvmCross include the 3 you list, all of which seem viable to me, but I agree that none of them is perfect.

As an additional suggestion, one nice architectural suggestion is from Microsoft's Pattern and Practices team. In http://msdn.microsoft.com/en-us/library/gg405494(v=pandp.40).aspx, they suggest a IInteractionRequest interface which can be used within data-binding especially for this type of situation.

Their reference implementation of this is:

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)));
        }
    }
}

An example ViewModel use of this is:

private InteractionRequest<Confirmation> _confirmCancelInteractionRequest = new InteractionRequest<Confirmation>();
public IInteractionRequest ConfirmCancelInteractionRequest
{
    get
    {
        return _confirmCancelInteractionRequest;
    }
}

and the ViewModel can raise this using:

_confirmCancelInteractionRequest.Raise(
    new Confirmation("Are you sure you wish to cancel?"),
    confirmation =>
    {
        if (confirmation.Confirmed)
        {
            this.NavigateToQuestionnaireList();
        }
    });
}

where Confirmation is a simple class like:

    public class Confirmation
    {
        public string Message { get; private set; }
        public bool Confirmed { get; set; }
        public Confirmation(string message)
        {
           Message = message;
        }
    }

For using this in the Views:

The MSDN link shows how a Xaml client might bind to this using behaviours - so I won't cover this further here.

In iOS for MvvmCross, a View object might implement a property like:

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);
    }
}

This View property uses a WeakReference-based event subscription in order to channel ViewModel Raise events through to a View MessageBox-type method. It's important to use a WeakReference so that the ViewModel never has a reference to the View - these can cause memory leak issues in Xamarin.iOS. The actual MessageBox-type method itself would be fairly simple - something like:

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();
    }; 
}

And the property could be bound in a Fluent Binding set like:

set.Bind(this)
   .For(v => v.ConfirmationInteraction)
   .To(vm => vm.ConfirmCancelInteractionRequest);

For Android, a similar implementation could be used - this could perhaps use a DialogFragment and could perhaps also be bound using a View within XML.

Note:

  • I believe that the basic interaction could be improved (in my opinion) if we added further IInteractionRequest<T> and InteractionRequestedEventArgs<T> definitions - but, for the scope of this answer, I kept to the 'basic' implementation keeping as close as I could to the one presented in http://msdn.microsoft.com/en-us/library/gg405494(v=pandp.40).aspx
  • some additional helper classes could also help significantly simplify the view subscription code too

这篇关于MvvmCross对话框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆