2013-12-14 44 views
5

Korzystam z zestawu narzędzi Galasoft Mvvm Light, aby zbudować swoją aplikację w systemie MVVM dla Windows Phone. Mam do stron, które każdy ma swój własny model widoku.Nawigacja i rekonstrukcja stron/viewmodel konstruktor

Gdy użytkownik uruchamia aplikację, może wybrać nową grę i zakręcić stronę z pytaniami. Te strony mają każdy model widoku, a wszystko działa za pomocą narzędzia viewmodellocator. Gdy użytkownik przejdzie z powrotem, aby wybrać nową grę i pytania ponownie. Viewmodel/strona nie jest usuwany. co oznacza, że ​​gdy użytkownik po raz drugi przechodzi do pytań lub nowej gry, konstruktor dla viewmodel nie jest wywoływany, tak że inicjalizacja w konstruktorze nie jest uruchamiana, a widok nie jest ustawiony prawidłowo.

Solutions Próbowałem

Próbowałem usunięcie backstack w nawigacje, takie jak nowej nawigacji do nowej gry lub pytania, należy kręcić nową stronę, a tym samym caling konstruktora. Nie działa.

Użycie załadowanego zdarzenia w widoku i wywołanie konstruktora. Nie działa.

Próbowałem podążać za How to reset all instances in IOC Container Ale nie mogłem go uruchomić, mógłbym po prostu być mną.

Czy ktoś rozwiązuje ten problem, jeśli tak, to jak go rozwiązać?

Kod Tutaj można znaleźć przykład. Naciśnij pytania i naciśnij przycisk tam jeden raz, użyj klawisza wstecz. i ponownie zadawaj pytania. widzisz, że liczba to teraz 1, to można łatwo zmienić. Ale błąd pojawia się, gdy ponownie naciśniesz przycisk. Nagle pojawiają się dwa wyskakujące okienka.

Jaki jest poprawny sposób konfiguracji viewmodel. ponieważ widok nowej gry będzie użyty przy ponownym ładowaniu starej gry, tylko z innymi wartościami, i kiedy ktoś chce rozpocząć nową grę. Mam nadzieję, że rozumiesz :)

Ten przykład pokazuje tylko mój problem z licznikiem wyskakujących okien po każdym powrocie na stronę viewmodel. https://www.dropbox.com/s/gjbz0l8rmsxqzrd/PhoneApp8.rar

ViewModel Locator jestem w moim obecnym projekcie przy użyciu trzech ViewModels widoczne w poniższym kodzie:

using GalaSoft.MvvmLight; 
using GalaSoft.MvvmLight.Ioc; 
using Microsoft.Practices.ServiceLocation; 

namespace MVVMTestApp.ViewModel 
{ 
public class ViewModelLocator 
{ 
    public ViewModelLocator() 
    { 
     //Holder styr på ViewModels 
     ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); 

     //Tilføj linje her for hver ViewModel 
     SimpleIoc.Default.Register<MainViewModel>(); 
     SimpleIoc.Default.Register<MainViewModelTest>(); 
     SimpleIoc.Default.Register<MenuViewModel>(); 
    } 

    //Tilføj metode som denne for hver ViewModel 
    public MainViewModel Map 
    { 
     get 
     { 
      return ServiceLocator.Current.GetInstance<MainViewModel>(); 
     } 
    } 

    public MainViewModelTest Main 
    { 
     get 
     { 
      return ServiceLocator.Current.GetInstance<MainViewModelTest>(); 
     } 
    } 

    public MenuViewModel Menu 
    { 
     get 
     { 
      return ServiceLocator.Current.GetInstance<MenuViewModel>(); 
     } 
    } 

    public static void Cleanup() 
    { 
      // TODO Clear the ViewModels 
    } 
} 

Mam spojrzał na link odwołać powyżej zresetowanie wszystkich przypadkach, w MKOl pojemnika. Ale nie wiesz, jak działa klucz i jak upewnić się, że funkcja czyszczenia zostanie wywołana podczas nawigacji z dala od widoków. Ponieważ nie chciałbym wyczyścić wszystkich modeli widoku w tym samym czasie.

Nawigacja i viewmodelbinding

wiążę moją ViewModel do widoku jak

DataContext="{Binding Source={StaticResource Locator},Path=Map}" 

poruszać tam iz powrotem przy użyciu NavigationService i BackButton.Z menu do gry:

NavigationService.Navigate(new Uri("/View/MainPage.xaml", UriKind.Relative)); 

i na stronie

protected override void OnNavigatedTo(NavigationEventArgs e) 
    { 
     //e.Content = NavigationMode.New; 
     //e.NavigationMode = NavigationMode(
     ViewModel.MainViewModel test = new ViewModel.MainViewModel(); 
     GC.Collect(); 
     base.OnNavigatedTo(e); 
    } 

iz grę do menu:

protected override void OnNavigatedFrom(NavigationEventArgs e) 
    { 
     //e.NavigationMode = NavigationMode. 
     this.DataContext = null; 
     GC.Collect(); 
     base.OnNavigatedFrom(e); 
     //test = null; 
    } 

iw menu Wzywam śmieciarza. Jak można zauważyć, przełamuję strukturę MVVM, aby uwzględnić problem.

+0

Myślę, że otrzymasz bardziej szczegółowe odpowiedzi, jeśli możesz opublikować konkretną próbkę demonstrującą problem. Ogólnie rzecz biorąc, myślę, że punktem modelu widoku jest * utrzymywanie * danych na różnych stronach, więc nie powinieneś się dziwić, że widok drugiej strony zachowuje dane z pierwszego widoku. Możesz sobie z tym poradzić, przenosząc część procesu init z konstruktora do funkcji wywoływanej z konstruktora, a także ze zdarzenia ładowanego stronami. – BobHy

+0

Dokładnie to zrobiłem. Istnieje jednak problem z pamięcią, ponieważ model widoku nie jest czyszczony podczas nawigacji. A ponieważ Datacontext jest ustawiony na widok nie mogę uzyskać dostęp do viewmodel z tyłu. Co musiałem zrobić do tej pory było ustawienie datacontext = null i wywołanie GC.collect(). Ale nie jest to dobry sposób na zrobienie tego. Chciałem wiedzieć, jaki jest właściwy sposób. – JTIM

+1

Proszę opublikuj próbkę pokazującą, co aktualnie robisz (z komentarzami pokazującymi, co chciałbyś/chciałabyś/chciałabyś mieć). Posiadanie modelu widoku V1 dla danej strony P1 nadal pozostaje w pamięci, kiedy P1 jest ładowany po raz drugi, to właśnie ma się zdarzyć. Czy widzisz inny model widoku w P1.DataContext? – BobHy

Odpowiedz

3

Właściwości twojego ViewModelLocator zwracają Singletony. Aby właściwość zwróciła nową instancję za każdym razem, gdy można po prostu napisać:

private int questCount; 

public Question Quest 
{ 
    get 
    { 
     return ServiceLocator.Current.GetInstance<Question>((++questCount).ToString()); 
    } 
} 

Jednakże spowoduje to buforowanie zapytania typu ViewModel. Musisz zwolnić nieużywane ViewModels, uważnie obserwując odpowiedź, którą połączyłeś. Powoduje to moją opinię za dużo kodu dla prostego wyniku. Istnieją inne pojemniki IOC, które można użyć zamiast SimpleIoc na Windows Phone (np. ninject lub unity), które mogą być lepiej dopasowane do twoich potrzeb.

W prostym projekcie (para-of-stron APP), zwłaszcza w przypadku braku konieczności dużego doświadczenia z MKOl pojemnika, radziłbym ci porzucić te wszystkie przewody SimpleIoc i po prostu wywołanie konstruktora:

public Question Quest 
{ 
    get { return new Question(); } 
} 
+0

Dziękuję za odpowiedź, mój projekt jest dość duży i używam trzech modeli widoku. Próbowałem zaimplementować funkcję czyszczenia bez uruchamiania go, ponieważ nie miałem pewności, jak wywołać czyszczenie, i jak zapewnić, że czyszczenie zostanie wykonane dla wszystkich zmiennych, nawet jeśli są one statyczne. Potrafię wykonać kod, który został przeze mnie połączony i sprawić, że działa, ale nie wiem, jak działa klucz. Więc nie jestem za dużo używać kodu, nie wiem jak to utrzymać. Chciałbym użyć SimpleIoc, ponieważ używam światła MVVM, ale nie wiem, jak to zrobić. Będę aktualizował moje pytanie z moim Viewmodellocator. – JTIM

+0

@JTIM Trzy ViewModels z bardzo prostymi konstruktorami (sądząc po konfiguracji SimpleIoc), są * zdecydowanie * przypadkiem, w którym nie * użyłbym kontenera IOC. Wyraźne wywołania konstruktorów dostarczają znacznie mniej kodu, który na pewno zrozumiesz. – lisp

+0

@ JTIM Podobnie jak w SimpleIoc - GetInstance zwraca to samo wystąpienie, GetInstance z danym kluczem daje tę samą instancję dla danego klucza. Wyrejestruj pozwala na usunięcie instancji przypisanej do klucza. To tylko specyfikacja SimpleIoc. Dzięki temu jest przydatny w niektórych sytuacjach, w niektórych sprawia, że ​​trudno go zastosować. SimpleIoc jest tylko jednym z pomocników w MVVMLight - nie musisz ich używać w każdym projekcie. ViewModelLocator można łatwo napisać bez niego. – lisp