2009-11-03 18 views
25

Czy ktoś ma przykłady wyświetlania okna dialogowego za pomocą MVVM (Prism)? - na przykład okno ustawień konfiguracji po wykonaniu polecenia.Przykład okna dialogowego WPV MVVM

Wszystkie przykłady widziałem użyć wzorca mediatora, który jest w porządku, ale oni także mają odniesienie do widoku w modelu widoku, który nie jest idealny (używamy DataTemplates)

Thanks

Odpowiedz

12

Sposób, w jaki to robię, polega również na użyciu wzorca mediatora. Kiedy ViewModel chce wyświetlić okno dialogowe, wysyła wiadomość odebraną przez główne okno aplikacji. Komunikat zawiera instancję ViewModel używaną przez okno dialogowe.

Okno główne następnie tworzy instancję okna dialogowego, przekazuje do niego model widoku i pokazuje okno dialogowe. Wynik okna dialogowego jest przekazywany rozmówcy w oryginalnej wiadomości.

Wygląda to mniej więcej tak:

w widoku modelu

DialogViewModel viewModel = new DialogViewModel(...); 
ShowDialogMessage message = new ShowDialogMessage(viewModel); 

_messenger.Broadcast(message); 

if (message.Result == true) 
{ 
    ... 
} 

w oknie głównym kodzie:

void RecieveShowDialogMessage(ShowDialogMessage message) 
{ 
    DialogWindow w = new DialogWindow(); 
    w.DataContext = message.ViewModel; 
    message.Result = w.ShowDialog(); 
} 

Mam nadzieję, że to wystarczy, aby dać Ci pomysł. ..

+0

Dziękuję za odpowiedź. Czy mógłbyś wyjaśnić poniższy scenariusz? Załóżmy, że wyświetlasz model widoku w oknie dialogowym Dialog Window z komendami Zapisz i Anuluj. Gdy użytkownik kliknie przycisk Zapisz w widoku (powiązany z poleceniem SaveCommand), może być konieczne przeprowadzenie sprawdzania poprawności i zapisanie konfiguracji, tylko jeśli zakończy się pomyślnie, okno dialogowe zostanie zamknięte. Nie mogę się zorientować, jak maszyna wirtualna ustawi DialogResult widoku (dlatego zamknięcie okna dialogowego). Jeszcze raz dziękuję. – Oll

+0

Istnieje wiele sposobów na to, aby maszyna wirtualna mogła wchodzić w interakcje z widokiem bez przerywania abstrakcji. Na przykład klasa bazowa widoku okna dialogowego zazwyczaj ma pewne podstawowe właściwości i metody, dzięki którym okna dialogowe wyświetlania są nieco łatwiejsze (zazwyczaj mam interfejs dla okna dialogowego viewmodel, który zawiera rzeczy takie jak metoda, która ma działać przy obciążeniu widoku, a także jako wynik dialogu, polecenia commit/abort, itp.). Łatwym sposobem przekonania viewmodelu do zamknięcia widoku jest ujawnienie właściwości (na przykład CanClose). – Egor

+0

Następnie utwórz odpowiednią właściwość zależności w oknie dialogowym, a gdy zmieni się format danych, ustaw powiązanie między tymi dwoma - w ten sposób możesz obsłużyć dowolną logikę w zmienionym module obsługi zdarzeń powiązanej. Z drugiej strony, jeszcze łatwiej jest po prostu wyświetlić zdarzenie "close" w oknie dialogowym viewmodel, aw oknie dialogowym kontekst danych kontekstu zmieniony handler subskrybować to zdarzenie, program obsługi może przypisać odpowiedni wynik dialogu i zamknąć okno. – Egor

2

Jak zrozumiałem powyżej, powyższe pytanie nie polega na pokazywaniu okien dialogowych i ich ukrywaniu. Istnieją dwa sposoby rozwiązania tego problemu:

  1. Użyj standardowego okna dialogowego do implementacji widoku. Wymagałoby to luźno powiązanego sposobu komunikacji między View i ViewModel, aby ViewModel mógł powiadomić View, że można go zamknąć bez odniesienia do widoku.

    Istnieje wiele struktur, które pozwoliłyby na to - agregatory zdarzeń Prism byłyby jednym z nich. W tym scenariuszu View zasubskrybowałby zdarzenie (np. MyDialogResultValidated), a po odebraniu zdarzenia ustawiłoby DialogResult accrodingly. ViewModel (w swoim SaveCommand) uruchamiałby zdarzenie, gdyby sprawdzanie poprawności przebiegło pomyślnie.

  2. Nie należy używać standardowego okna dialogowego do implementacji widoku. Wymagałoby to nakładki, która efektywnie emulowałaby modalność.

    W tym scenariuszu widoczność widoku i nakładki będzie związana właściwością IsVisible ViewModel, która byłaby odpowiednio ustawiona przez implementację SaveCommand lub gdy ViewModel musi wyświetlić widok.

Pierwsze podejście wymagałoby posiadania bitowego kodu w kodzie opóźnieniem, wymaga dodania globalnego zdarzenia (S) i (prawdopodobnie) jest mniejsza MVVM-owski.Drugie podejście wymagałoby implementacji (lub użycia cudzej implementacji) nakładki, ale nie będzie wymagało posiadania kodu z tyłu kodu, nie będzie wymagało globalnego zdarzenia (zdarzeń) i jest (argumentowalne) więcej MVVM-ish .

21

Chciałbym użyć usługi, aby wyświetlić okno dialogowe. Usługa może następnie łączyć widoki z modelami podglądu.

public interface IDialogService { 
    void RegisterView<TView, TViewModel>() where TViewModel:IDialogViewModel; 
    bool? ShowDialog(IDialogViewModel viewModel); 
} 

public interface IDialogViewModel { 
    bool CanClose(); 
    void Close(); 
} 


RegisterView tylko linki typ widoku z typem ViewModel. Możesz ustawić te łącza w inicjalizacji modułu. Jest to prostsze niż próba uzyskania modułów do rejestracji datatemplates w górnej warstwie aplikacji.

ShowDialog Pokazuje model ViewModel, który chcesz wyświetlić. Zwraca true, false i null dla close, podobnie jak metoda Window.ShowDialog. Implementacja właśnie tworzy nowy widok typu TView z twojego kontenera, podłącza go do dostarczonego ViewModel i pokazuje go.

IDialogViewModel zapewnia mechanizm do wykonania ViewModel i anulowania zamknięcia okna dialogowego.

Mam standardowe okno dialogowe z kontrolą treści. Po wywołaniu ShowDialog tworzy nowe standardowe okno dialogowe, dodaje widok do kontroli treści, podłącza ViewModel i wyświetla go. Standardowe okno dialogowe ma już przyciski [OK] i [Anuluj] z odpowiednią logiką do wywoływania właściwych metod z IDialogViewModel.

+0

Witam Cameron! W jaki sposób widok informuje usługę, czy naciśnięto przycisk OK lub Anuluj? –

+0

Standardowy sposób. Implementacja kodu 'ShowDialog' będzie po prostu znajdować View, który musi wyświetlić, a następnie wywołać' ShowDialog' w tym widoku i przekazać wynik z powrotem. –

+0

W jaki sposób zmiany właściwości wewnątrz IDIalogViewModel powodują wyzwolenie oceny CanExecute poleceń związanych z przyciskami [OK] i [Anuluj] w standardowym oknie dialogowym? InvalidateRequerySuggested? – jan

0

To nie jest pryzmat, ale ten MVVM demo ma okno dialogowe opcji, które jest w pełni MVVM.

2

Zgadzam się, że używanie usługi do wyświetlania okna dialogowego zgodnie ze wzorcem MVVM jest najprostszym rozwiązaniem. Ale też zadałem sobie pytanie, czy istnieją 3 zespoły w moim projekcie Model, ViewModel, View i zgodnie z montażem modeli MVVM ViewModel ma odniesienie do Modelu, a View to zarówno Model, jak i ViewModel gdzie powinienem umieścić klasę DialogService? Jeśli umieścę jeden w zespole ViewModel - nie mam szans na utworzenie instancji DialogView; z drugiej strony, jeśli umieszczę DialogService w zestawie View, jak powinienem wstrzyknąć go w moją klasę ViewModel?

Tak, chciałbym recoment przyjrzeć Advanced MVVM scenarios with Prismczęści: Korzystanie Interaction Zamówienie Przedmioty

Jako przykład takiego podejścia:

DialogViewModelBase

public abstract class DialogViewModelBase : ViewModelBase 
{ 
    private ICommand _ok; 

    public ICommand Ok 
    { 
     get { return _ok ?? (_ok = new DelegateCommand(OkExecute, CanOkExecute)); } 
    } 

    protected virtual bool CanOkExecute() 
    { 
     return true; 
    } 

    protected virtual void OkExecute() 
    { 
     _isSaved = true; 
     Close = true; 
    } 

    private ICommand _cancel; 

    public ICommand Cancel 
    { 
     get 
     { 
      return _cancel ?? (_cancel = new DelegateCommand(CancelExecute, CanCancelExecute)); 
     } 
    } 

    protected virtual bool CanCancelExecute() 
    { 
     return true; 
    } 

    protected virtual void CancelExecute() 
    { 
     Close = true; 
    } 

    private bool _isSaved = false; 
    public bool IsSaved 
    { 
     get { return _isSaved; } 
    } 

    private bool _close = false; 

    public bool Close 
    { 
     get { return _close; } 
     set 
     { 
      _close = value; 
      RaisePropertyChanged(() => Close); 
     } 
    } 
} 

CreateUserStoryViewModel:

public class CreateUserStoryViewModel : DialogViewModelBase 
{ 
    private string _name = String.Empty; 

    public string Name 
    { 
     get { return _name; } 
     set 
     { 
      _name = value; 
      RaisePropertyChanged(() => Name); 
     } 
    } 
} 

CreateUserStoryRequest

private InteractionRequest<Notification> _createUserStoryRequest; 
public InteractionRequest<Notification> CreateUserStoryRequest 
{ 
    get 
    { 
     return _createUserStoryRequest ?? (_createUserStoryRequest = new InteractionRequest<Notification>()); 
    } 
} 

CreateUserStory poleceń

private void CreateUserStoryExecute() 
{ 
    CreateUserStoryRequest.Raise(new Notification() 
    { 
     Content = new CreateUserStoryViewModel(), 
     Title = "Create User Story" 
    }, 
    notification => 
       { 
         CreateUserStoryViewModel createUserStoryViewModel = 
           (CreateUserStoryViewModel)notification.Content; 
         if (createUserStoryViewModel.IsSaved) 
         { 
         _domainContext.CreateUserStory(
new UserStory(){ Name = createUserStoryViewModel.Name, }); 
         } 
       }); 
} 

XAML:

<!--where xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
      xmlns:ir="clr-namespace:Microsoft.Practices.Prism.Interactivity.InteractionRequest;assembly=Microsoft.Practices.Prism.Interactivity"--> 

<i:Interaction.Triggers> 
    <ir:InteractionRequestTrigger SourceObject="{Binding CreateUserStoryRequest}"> 
    <ir:PopupChildWindowAction> 
     <ir:PopupChildWindowAction.ChildWindow> 
     <view:CreateUserStory /> 
     </ir:PopupChildWindowAction.ChildWindow> 
    </ir:PopupChildWindowAction> 
    </ir:InteractionRequestTrigger> 
</i:Interaction.Triggers> 
+0

Vladimir: Próbowałem podejścia, ale to nie działa dla mnie.Can u opracowania, co jest _domainContext. Mój scenariusz to modalne okno dialogowe z polem tekstowym, etykietą i pdfviewer. Muszę zmienić datacontext ModalDialog [ie. przekazując te wartości jako model widoku] zgodnie z przyciskiem (wyzwalacz) kliknij. Każdy pomysł lub referencja byłaby pomocna ... Dzięki –

+0

_domainContext w mojej próbce jest rodzajem repozytorium. To tylko przykład i możesz go zastąpić wywołaniem usługi WCF lub zapisaniem na dysku. Ten przykład będzie działał w twoim scenariuszu. Musisz zastąpić CreateUserStoryViewModel swoim własnym ModalDialogViewModel z właściwościami Title, Text itp.i powiązać te właściwości z etykietą ModalDialogView i PdfViewer (zamiast mojego widoku CreateUserStory należy użyć ModalDialogView). –

+0

Wygląda na to, że nie działa z WPF. Element nie istnieje. Jednak robi to w Silverlight. –

Powiązane problemy