Диалоговый ввод - интересная тема, которая не всегда хорошо сочетается с потоком передачи данных Mvvm.
Вообще, некоторые случаи использования Диалоги для таких вещей, как:
- добавляющих да/нет опции подтверждения к не кнопка отправки
- запрашивает дополнительную один вход - например, выбор из списка
- предлагает выбор действий (например, удалять, редактировать или дублировать?)
- предлагает подтверждающее сообщение
- запрашивающего дополнительный сложный вход - например, собирая набор firstname/lastname/age/accept_terms поле
Для некоторых из этих пунктов я бы предположил, что в основном они могут быть смоделированы как чисто взгляды. Например, запрос на выбор отдельных элементов обычно делается из составных контрольных надписей, которые отображают «сборщики» при нажатии. как MvxSpinner в https://github.com/slodge/MvvmCross-Tutorials/blob/master/ApiExamples/ApiExamples.Droid/Resources/Layout/Test_Spinner.axml#L16
Для общих случаев, когда вы хотите, чтобы общие ViewModels управляли потоком пользователя, тогда параметры, доступные в MvvmCross, включают в себя список 3, все из которых кажутся мне жизнеспособными, но я согласен с тем, что ни один из них не является совершенным.
В качестве дополнительного предложения, одно из замечательных архитектурных предложений - это команда Microsoft по шаблонам и практике. В http://msdn.microsoft.com/en-us/library/gg405494(v=pandp.40).aspx они предлагают интерфейс 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)));
}
}
}
Пример использования ViewModel этого:
private InteractionRequest<Confirmation> _confirmCancelInteractionRequest = new InteractionRequest<Confirmation>();
public IInteractionRequest ConfirmCancelInteractionRequest
{
get
{
return _confirmCancelInteractionRequest;
}
}
и ViewModel может поднять это с помощью:
_confirmCancelInteractionRequest.Raise(
new Confirmation("Are you sure you wish to cancel?"),
confirmation =>
{
if (confirmation.Confirmed)
{
this.NavigateToQuestionnaireList();
}
});
}
где Confirmation
это простой класс:
public class Confirmation
{
public string Message { get; private set; }
public bool Confirmed { get; set; }
public Confirmation(string message)
{
Message = message;
}
}
Для использования этого в соображениях:
Ссылка MSDN показывает, как клиент Xaml может связываться с этим с помощью поведения - поэтому я не буду покрывать это еще здесь.
В прошивкой для 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);
}
}
Это свойство View использует -На подписку WeakReference
событий для того, чтобы направить ViewModel Raise
события через к View MessageBox
типа метода , Важно использовать WeakReference
, чтобы ViewModel никогда не ссылался на View
- это может вызвать проблемы с утечкой памяти в 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();
};
}
И имущество может быть связано в Fluent Binding набор как:
set.Bind(this)
.For(v => v.ConfirmationInteraction)
.To(vm => vm.ConfirmCancelInteractionRequest);
для Android, подобная реализация может быть используется - возможно, можно использовать DialogFragment
и, возможно, также можно связать с помощью View
в XML.
Примечание:
- Я считаю, что основное взаимодействие может быть улучшено (по-моему), если мы добавили дополнительные
IInteractionRequest<T>
и InteractionRequestedEventArgs<T>
определения - но, в рамки этого ответа, я держал в «основной» учет реализации так близко, как я мог к представленному в http://msdn.microsoft.com/en-us/library/gg405494(v=pandp.40).aspx
- некоторых дополнительных вспомогательных классов также может помочь существенно упростить код вида подписки слишком
если ваше второе решение что-то вроде этого http://stackoverflow.com/questions/3801681/good-or-bad-practice-for-dialogs-in-wpf-with-mvvm - я поеду с тобой :) – blindmeis