2013-09-04 38 views
7

Tôi hiện đang điều tra tất cả các giải pháp khả thi để có thể thông báo cho người dùng, tức là bật hộp thoại, khi có quyết định cần thiết. Đây là một vấn đề phổ biến với mẫu MVVM và tôi đang cố gắng giải quyết nó cho khung công tác MvvmCross.Hộp thoại MvvmCross

giải pháp có thể có thể là:

  • Tùy chỉnh MvxPresenter để có thể hiển thị hộp thoại, nhưng điều đó có vẻ hơi xấu xí với tôi
  • Đặt một giao diện Dialog trong dự án Core và sử dụng Inversion of Control để tiêm triển khai từ dự án giao diện người dùng vào dự án Core
  • Sử dụng plugin MvxMessenger và chia sẻ thông điệp giữa dự án Core và giao diện người dùng. Nghe có vẻ như một ý tưởng hay nhưng có thể phức tạp hơn để phát triển ...

Bạn sẽ đề xuất điều gì?

+0

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

Trả lời

13

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ư:

  1. thêm một yes/no tùy chọn xác nhận vào một nút gửi
  2. yêu cầu thêm đơn đầu vào - ví dụ lựa chọn từ một danh sách
  3. 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?)
  4. cung cấp một thông báo xác nhận
  5. 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>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á
3

Như Eugene nói, sử dụng plugin UserInteraction. Thật không may, không có hiện Windows thực hiện điện thoại, vì vậy đây là đoạn code tôi đã sử dụng trong thời gian chuyển tiếp:

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

Bạn sẽ nhận thấy rằng không phải mọi thứ của thực hiện, và thậm chí cả các bit bị giới hạn (bạn có thể' t đặt văn bản nút Hủy quảng cáo OK, ví dụ)

Tất nhiên, tôi cần đăng ký thiết lập này.cs là tốt:

Mvx.RegisterSingleton<IUserInteraction>(new WindowsPhoneUserInteraction()); 
Các vấn đề liên quan