Nhập bằng giọng nói là một chủ đề thú vị không phải lúc nào cũng phù hợp với luồng dữ liệu Mvvm.
Nói chung, một số trường hợp sử dụng các Dialogs là cho những thứ như:
- thêm một yes/no tùy chọn xác nhận vào một nút gửi
- yêu cầu thêm đơn đầu vào - ví dụ lựa chọn từ một danh sách
- cung cấp một lựa chọn hành động (ví dụ: xóa, chỉnh sửa hoặc sao chép?)
- cung cấp một thông báo xác nhận
- yêu cầu thêm đầu vào phức tạp - ví dụ thu thập một bộ trường firstname/lastname/age/accept_terms
Đối với một số mục này, tôi cho rằng chủ yếu chúng có thể được mô hình hóa hoàn toàn Xem các mối quan tâm. Ví dụ: yêu cầu lựa chọn một mục thường được thực hiện từ các nhãn điều khiển hợp chất hiển thị 'bộ chọn' khi nhấn vào - ví dụ: giống như một MvxSpinner trong https://github.com/slodge/MvvmCross-Tutorials/blob/master/ApiExamples/ApiExamples.Droid/Resources/Layout/Test_Spinner.axml#L16
Đối với trường hợp chung, nơi bạn muốn ViewModels chia sẻ lưu lượng người dùng, thì các tùy chọn có sẵn trong MvvmCross bao gồm danh sách 3 bạn, tất cả đều khả thi với tôi, nhưng tôi đồng ý rằng không ai trong số họ là hoàn hảo.
Là một đề xuất bổ sung, một đề xuất kiến trúc tốt đẹp là từ nhóm Mô hình và Thực tiễn của Microsoft. Trong http://msdn.microsoft.com/en-us/library/gg405494(v=pandp.40).aspx, chúng đề xuất một giao diện IInteractionRequest
có thể được sử dụng trong ràng buộc dữ liệu, đặc biệt là đối với loại tình huống này.
thực hiện tham chiếu của họ này là:
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)));
}
}
}
Một ví dụ sử dụng ViewModel của việc này là:
private InteractionRequest<Confirmation> _confirmCancelInteractionRequest = new InteractionRequest<Confirmation>();
public IInteractionRequest ConfirmCancelInteractionRequest
{
get
{
return _confirmCancelInteractionRequest;
}
}
và ViewModel có thể nêu vấn đề này bằng:
_confirmCancelInteractionRequest.Raise(
new Confirmation("Are you sure you wish to cancel?"),
confirmation =>
{
if (confirmation.Confirmed)
{
this.NavigateToQuestionnaireList();
}
});
}
nơi Confirmation
là một lớp học đơn giản như:
public class Confirmation
{
public string Message { get; private set; }
public bool Confirmed { get; set; }
public Confirmation(string message)
{
Message = message;
}
}
Để sử dụng này trong Views:
Liên kết MSDN cho thấy cách một khách hàng XAML có thể liên kết với này sử dụng hành vi - vì vậy tôi sẽ không bao gồm này hơn nữa đây.
Trong iOS cho MvvmCross, một Xem đối tượng có thể thực hiện một tài sản như:
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);
}
}
Xem tài sản này sử dụng một thuê bao sự kiện dựa trên WeakReference
để kênh ViewModel Raise
sự kiện thông qua một Xem MessageBox
-type phương pháp . Điều quan trọng là sử dụng WeakReference
để ViewModel không bao giờ có tham chiếu đến View
- những điều này có thể gây ra sự cố rò rỉ bộ nhớ trong Xamarin.iOS. Thực tế MessageBox
-type phương pháp riêng của mình sẽ là khá đơn giản - một cái gì đó như:
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();
};
}
Và tài sản có thể bị ràng buộc trong một bộ Binding thạo như:
set.Bind(this)
.For(v => v.ConfirmationInteraction)
.To(vm => vm.ConfirmCancelInteractionRequest);
Đối với Android, một thực hiện tương tự có thể được sử dụng - điều này có lẽ có thể sử dụng một DialogFragment
và có lẽ cũng có thể bị ràng buộc bằng cách sử dụng một View
trong XML.
Lưu ý:
- Tôi tin rằng sự tương tác cơ bản có thể được cải thiện (theo ý kiến của tôi) nếu chúng ta bổ sung thêm
IInteractionRequest<T>
và InteractionRequestedEventArgs<T>
định nghĩa - nhưng, đối với phạm vi của câu trả lời này, tôi vẫn tiếp tục đến việc triển khai 'cơ bản' giữ gần nhất có thể với cách triển khai trong số http://msdn.microsoft.com/en-us/library/gg405494(v=pandp.40).aspx
- một số lớp trợ giúp bổ sung cũng có thể giúp đơn giản hóa đáng kể mã đăng ký xem quá
nếu giải pháp thứ hai của bạn giống như thế này http://stackoverflow.com/questions/3801681/good-or-bad-practice-for-dialogs-in-wpf-with-mvvm - tôi sẽ đi với bạn :) – blindmeis