2013-06-11 32 views
5

Tôi đang sử dụng MvvmCross để tạo Android ứng dụng của tôi và tôi phải đối mặt với các vấn đề sau đây:Hiện AlertDialog từ ViewModel sử dụng MvvmCross

Khi tôi đang cố gắng để hiển thị AlertDialog, mà đã được tạo ra trong ViewModel, các

"Ngoại lệ không khớp: Android.Views.WindowManagerBadTokenException" xuất hiện.

public class MyViewModel : MvxViewModel 
{ 
    public ICommand ShowAlertCommand { get; private set; } 

    public AuthorizationViewModel() 
    { 
     ShowAlertCommand = new MvxCommand(() => 
      { 
       var adb = new AlertDialog.Builder(Application.Context); 
       adb.SetTitle("Title here"); 
       adb.SetMessage("Message here"); 
       adb.SetIcon(Resource.Drawable.Icon); 
       adb.SetPositiveButton("OK", (sender, args) => { /* some logic */}); 
       adb.SetNegativeButton("Cancel", (sender, args) => { /* close alertDialog */}); 

       adb.Create().Show(); 
      }); 
    } 
} 

Khi tôi researching Tôi đã phát hiện ra rằng nó sẽ xảy ra vì truyền tham chiếu đến bối cảnh nhưng không phải trên các hoạt động trong các AlertDialog.Builder.

Trong this topic tôi thấy quyết định sau đây: Nhận tài liệu tham khảo cho các Hoạt động hiện tại thông qua việc sử dụng các GetService(), nhưng tôi đã không tìm thấy plugin mvvmcross cho công việc với IMvxServiceConsumer, giao diện IMvxAndroidCurrentTopActivity.

Câu hỏi của tôi là tôi có thể hiển thị AlertDialog từ ViewModel không? Và làm thế nào tôi có thể nhận được tham chiếu đến Hoạt động, nhưng không phải cho Application.Context? Và cách chính xác để đóng AlertDialog mà người dùng sẽ ở trên Chế độ xem hiện tại là gì?

Trả lời

11

Nói chung, bạn nên cố gắng không để đặt loại mã thành ViewModels

  • vì ViewModels nên ở nền tảng độc lập
  • vì ViewModels nên đơn vị kiểm chứng - và thật khó để kiểm tra đơn vị khi mã hiển thị hộp thoại

Tôi cũng khuyên bạn không nên đặt mã như thế này bên trong Trình xây dựng ViewModel - những nhà xây dựng này thường được gọi trong khi điều hướng và hiển thị Hộp thoại trong quá trình chuyển đổi có thể là sự cố atic.


Với những điều đã nói, nếu bạn muốn có được giữ của các Hoạt động hàng đầu hiện nay trong bất kỳ mã, sau đó bạn có thể làm điều này bằng cách sử dụng IMvxAndroidCurrentTopActivity

public interface IMvxAndroidCurrentTopActivity 
{ 
    Activity Activity { get; } 
} 

Sử dụng này, bất kỳ mã có thể nhận được dòng điện Activity sử dụng:

var top = Mvx.Resolve<IMvxAndroidCurrentTopActivity>(); 
var act = top.Activity; 
if (act == null) 
{ 
    // this can happen during transitions 
    // - you need to be sure that this won't happen for your code 
    throw new MvxException("Cannot get current top activity"); 
} 

var dlg = new AlertDialog.Builder(act); 
//... 
dlg.Create().Show(); 

việc sử dụng IMvxAndroidCurrentTopActivity được thảo luận trong MvvmCross: How to pass Android context down to MvxCommand?

Phương pháp thực hiện trong câu hỏi đó/câu trả lời cũng là một trong những cách tôi nói chung sẽ tiếp cận cho thấy hộp thoại từ một ViewModel:

  • tôi sẽ tạo ra một giao diện IFooDialog
  • Lý tưởng nhất là tôi có lẽ sẽ làm cho giao diện này không đồng bộ - ví dụsử dụng async hoặc sử dụng một tham số Action<DialogResult> callback
  • trên mỗi nền tảng tôi sẽ thực hiện điều đó trong dự án giao diện người dùng sau đó
  • các ViewModel s có thể sử dụng IFooDialog khi một hộp thoại là cần thiết và mỗi nền tảng có thể đáp ứng với một hành động giao diện người dùng phù hợp

Cách tiếp cận 'Dịch vụ thoại' này là phổ biến trong Mvvm - ví dụ: xem các bài viết như http://www.codeproject.com/Articles/36745/Showing-Dialogs-When-Using-the-MVVM-Pattern (mặc dù bài viết đó rất cụ thể cho Windows!)

Ngoài ra còn có một vài câu hỏi khác về MvvmCross và hộp thoại - mặc dù chúng có thể chứa tham chiếu đến mã v1 hoặc vNext cũ hơn - ví dụ: Alerts or Popups in MvvmCrossUnable run ProgressDialog - BadTokenException while showind

+0

Ok, tôi đang thử công cụ này :) –

+0

Tôi đồng ý rằng làm việc với giao diện người dùng từ VM không phải là "Phong thủy";) nhưng nền tảng WinPhone và iPhone đã khởi chạy và tôi chỉ cần trong Android phiên bản ứng dụng của tôi. Trong tương lai, trong các dự án mới của tôi, tôi nhất thiết sẽ phát triển theo các hộp MVVM :) –

+0

Stuart, một câu hỏi ngắn về 'IMvxAndroidCurrentTopActivity': Nó sẽ luôn luôn là cùng một ví dụ, ngay cả khi hoạt động hàng đầu hiện tại thay đổi? Bối cảnh: Tôi không phải là một fan hâm mộ của vị trí dịch vụ, thay vào đó các lớp học của tôi có sự phụ thuộc rõ ràng. Nó có hoạt động nếu một lớp singleton của tôi có sự phụ thuộc của hàm khởi tạo trên 'IMvxAndroidCurrentTopActivity' và nó vẫn có thể hoạt động trên hoạt động hiện tại không? –

Các vấn đề liên quan