MVVM w WPF-jak alarmować ViewModel o zmianach w modelu... czy powinienem?

Przeglądam kilka artykułów MVVM, głównie to i to .

Moje konkretne pytanie brzmi: Jak przekazać zmiany modelu z modelu do modelu ViewModel?

W artykule Josha nie widzę, żeby to robił. Model widoku zawsze pyta Model o właściwości. W przykładzie Rachel ma implementację modelu INotifyPropertyChanged i podnosi zdarzenia z modelu, ale są one do konsumpcji przez sam widok (zobacz ją artykuł / kod, aby uzyskać więcej szczegółów na temat tego, dlaczego to robi).

Nigdzie nie widzę przykładów, w których model ostrzega ViewModel o zmianach we właściwościach modelu. To mnie martwi, że być może nie jest zrobione z jakiegoś powodu. czy istnieje wzorzec powiadamiania ViewModel o zmianach w modelu? wydaje się to konieczne, ponieważ (1) prawdopodobnie istnieje więcej niż 1 Model ViewModel dla każdego modelu, a (2) nawet jeśli istnieje tylko jeden model ViewModel, niektóre działania na modelu mogą spowodować inne właściwości są zmieniane.

Podejrzewam, że mogą być odpowiedzi/komentarze w formularzu " dlaczego chcesz to zrobić?"komentarze, oto opis mojego programu. Jestem nowy w MVVM więc może cały mój projekt jest wadliwy. Opiszę to krótko.

Programuję coś ciekawszego (przynajmniej dla mnie!) niż klasy "Klient" lub "produkt". Programuję Blackjacka.

Mam pogląd, który nie ma żadnego kodu za sobą i opiera się na powiązanie z właściwościami i poleceniami w ViewModel (patrz artykuł Josha Smitha).

Na dobre i na złe, przyjęłam postawę, że Model powinien zawierać nie tylko klasy takie jak PlayingCard, Deck, ale także BlackJackGame klasa, która utrzymuje stan całej gry i wie, Kiedy gracz zbankrutował, krupier musi dobrać karty, a jaki jest obecny wynik gracza i krupiera (mniej niż 21, 21, bust, itp.).

Z BlackJackGame ujawniam metody typu "DrawCard" i przyszło mi do głowy że po wylosowaniu karty właściwości takie jak CardScore i IsBust powinny zostać zaktualizowane, a te nowe wartości przekazane modelowi widoku. Może to błędne myślenie?

Można przyjąć postawę, że ViewModel nazywa metodę DrawCard(), więc powinien wiedzieć, aby poprosić o zaktualizowaną ocenę i dowiedzieć się, czy jest popierdolony, czy nie. Opinie?

Moim zdaniem, mam logikę, aby pobrać rzeczywisty obraz karty do gry (na podstawie koloru,rangi) i udostępnić go do widoku. Model nie powinno się tym przejmować (być może inny ViewModel po prostu użyłby liczb zamiast obrazów kart do gry). Oczywiście, być może niektórzy powiedzą mi, że Model nie powinien nawet mieć pojęcie gry w blackjacka i że powinny być obsługiwane w ViewModel?

Author: Ondrej Janacek, 2013-03-15

11 answers

Jeśli chcesz, aby twoje modele powiadamiały Viewmodele o zmianach, powinny zaimplementować INotifyPropertyChanged , a Viewmodele powinny subskrybować, aby otrzymywać powiadomienia o zmianach właściwości.

Twój kod może wyglądać mniej więcej tak:

// Attach EventHandler
PlayerModel.PropertyChanged += PlayerModel_PropertyChanged;

...

// When property gets changed in the Model, raise the PropertyChanged 
// event of the ViewModel copy of the property
PlayerModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if (e.PropertyName == "SomeProperty")
        RaisePropertyChanged("ViewModelCopyOfSomeProperty");
}

Ale zazwyczaj jest to potrzebne tylko wtedy, gdy więcej niż jeden obiekt będzie wprowadzał zmiany w danych modelu, co zwykle nie ma miejsca.

Jeśli kiedykolwiek masz przypadek, w którym nie masz odniesienia do swojego Właściwość modelu aby dołączyć do niej Zdarzenie właściwości, można użyć systemu komunikatorów, np. Prism 's EventAggregator lub MVVM Light' s Messenger.

Mam krótki przegląd systemów wiadomości na moim blogu, jednak podsumowując, każdy obiekt może nadawać wiadomość, a każdy obiekt może subskrybować, aby słuchać konkretnych wiadomości. Możesz więc nadawać PlayerScoreHasChangedMessage z jednego obiektu, a inny obiekt może subskrybować, aby słuchać tego typu wiadomości i aktualizować właściwość PlayerScore, gdy słyszy jeden.

Ale myślę, że nie jest to potrzebne dla systemu, który opisałeś.

W idealnym świecie MVVM, Twoja aplikacja składa się z Twoich modeli ViewModel, a twoje modele są tylko blokami używanymi do budowania aplikacji. Zazwyczaj zawierają tylko dane, więc nie mają metod takich jak DrawCard() (które byłyby w ViewModel)

Więc prawdopodobnie miałbyś zwykłe obiekty danych Modelu, takie jak te:

class CardModel
{
    int Score;
    SuitEnum Suit;
    CardEnum CardValue;
}

class PlayerModel 
{
    ObservableCollection<Card> FaceUpCards;
    ObservableCollection<Card> FaceDownCards;
    int CurrentScore;

    bool IsBust
    {
        get
        {
            return Score > 21;
        }
    }
}

I mielibyście obiekt ViewModel jak

public class GameViewModel
{
    ObservableCollection<CardModel> Deck;
    PlayerModel Dealer;
    PlayerModel Player;

    ICommand DrawCardCommand;

    void DrawCard(Player currentPlayer)
    {
        var nextCard = Deck.First();
        currentPlayer.FaceUpCards.Add(nextCard);

        if (currentPlayer.IsBust)
            // Process next player turn

        Deck.Remove(nextCard);
    }
}

(powyższe obiekty powinny zaimplementować INotifyPropertyChanged, ale pominąłem to dla uproszczenia)

 64
Author: Rachel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-15 19:48:10

Krótka odpowiedź: to zależy od specyfiki.

W twoim przykładzie modele są aktualizowane "na własną rękę" i te zmiany oczywiście muszą w jakiś sposób propagować się do widoków. Ponieważ widoki mogą mieć bezpośredni dostęp tylko do modeli widoku, oznacza to, że model musi przekazać te zmiany do odpowiedniego modelu widoku. Mechanizm, który jest do tego stworzony, to oczywiście INotifyPropertyChanged, co oznacza, że otrzymasz taki przepływ pracy:

  1. ViewModel jest tworzony i owijany model
  2. ViewModel subskrybuje Zdarzenie modelu PropertyChanged
  3. Viewmodel jest ustawiony jako widok DataContext, właściwości są powiązane itp
  4. widok uruchamia akcję na viewmodel
  5. ViewModel wywołuje metodę na modelu
  6. Model sam się aktualizuje
  7. Viewmodel obsługuje model PropertyChanged i podnosi swój własny PropertyChanged w odpowiedzi
  8. widok odzwierciedla zmiany w jego powiązaniach, zamykając pętlę sprzężenia zwrotnego

Z drugiej strony, jeśli twoje modele zawierały niewiele (lub nie) logika biznesowa, lub jeśli z jakiegoś innego powodu (np. zyskanie możliwości transakcyjnych) zdecydowałeś się pozwolić każdemu viewmodelowi "posiadać" swój zawinięty model, wtedy wszystkie modyfikacje modelu przechodzą przez viewmodel, więc takie rozwiązanie nie byłoby konieczne.

Opisuję taki projekt w innym pytaniu MVVM tutaj .

 24
Author: Jon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:20

Twoje wybory:

  • Zaimplementuj INotifyPropertyChanged
  • Wydarzenia
  • POCO z manipulatorem Proxy

Jak ja to widzę, {[1] } jest podstawową częścią .Net. czyli jej w System.dll. Wdrożenie go w twoim "modelu" jest podobne do wdrożenia struktury wydarzenia.

Jeśli chcesz mieć czyste POCO, musisz skutecznie manipulować obiektami za pomocą proxy/usług, a następnie twój ViewModel jest powiadamiany o zmianach przez nasłuchiwanie proxy.

Osobiście po prostu luźno zaimplementuj INotifyPropertyChanged, a następnie użyj FODY , aby wykonać za mnie brudną robotę. Wygląda i czuje POCO.

Przykład (używając FODY do splotu właściwości):

public class NearlyPOCO: INotifyPropertyChanged
{
     public string ValueA {get;set;}
     public string ValueB {get;set;}

     public event PropertyChangedEventHandler PropertyChanged;
}

Następnie możesz poprosić ViewModel, aby nasłuchał właściwości PropertyChanged dla jakichkolwiek zmian; lub zmian specyficznych dla właściwości.

Piękno drogi INotifyPropertyChanged, jest łańcuchem go z Rozszerzony obserwowalny Collection. Więc wyrzucasz swoje pobliskie obiekty poco do kolekcji i słuchać kolekcji... jeśli coś się zmieni, gdziekolwiek się dowiesz.

Będę szczery, to może dołączyć do dyskusji "Why wasn' t INotifyPropertyChanged autmatically handed by the compiler", która devolves to: każdy obiekt w c# powinien mieć możliwość powiadamiania, jeśli jakakolwiek jego część została zmieniona; tj. implementacja INotifyPropertyChanged domyślnie. Ale tak nie jest i najlepszą drogą, która wymaga najmniejszego wysiłku, jest użycie IL Weaving (konkretnie FODY ).

 4
Author: Meirion Hughes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:29

Dość stary wątek, ale po wielu poszukiwaniach wymyśliłem własne rozwiązanie: PropertyChangedProxy

Z tą klasą możesz łatwo zarejestrować się do cudzej NotifyPropertyChanged i podjąć odpowiednie działania, jeśli zostanie ona wywołana dla zarejestrowanej właściwości.

Oto przykład jak to może wyglądać, gdy masz właściwość modelu "Status", która może się zmienić na własną rękę, a następnie powinna automatycznie powiadomić ViewModel, aby odpalił własne właściwości " Status" właściwość tak, aby Widok był również powiadamiany :)

public class MyModel : INotifyPropertyChanged
{
    private string _status;
    public string Status
    {
        get { return _status; }
        set { _status = value; OnPropertyChanged(); }
    }

    // Default INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

public class MyViewModel : INotifyPropertyChanged
{
    public string Status
    {
        get { return _model.Status; }
    }

    private PropertyChangedProxy<MyModel, string> _statusPropertyChangedProxy;
    private MyModel _model;
    public MyViewModel(MyModel model)
    {
        _model = model;
        _statusPropertyChangedProxy = new PropertyChangedProxy<MyModel, string>(
            _model, myModel => myModel.Status, s => OnPropertyChanged("Status")
        );
    }

    // Default INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

A oto sama klasa:

/// <summary>
/// Proxy class to easily take actions when a specific property in the "source" changed
/// </summary>
/// Last updated: 20.01.2015
/// <typeparam name="TSource">Type of the source</typeparam>
/// <typeparam name="TPropType">Type of the property</typeparam>
public class PropertyChangedProxy<TSource, TPropType> where TSource : INotifyPropertyChanged
{
    private readonly Func<TSource, TPropType> _getValueFunc;
    private readonly TSource _source;
    private readonly Action<TPropType> _onPropertyChanged;
    private readonly string _modelPropertyname;

    /// <summary>
    /// Constructor for a property changed proxy
    /// </summary>
    /// <param name="source">The source object to listen for property changes</param>
    /// <param name="selectorExpression">Expression to the property of the source</param>
    /// <param name="onPropertyChanged">Action to take when a property changed was fired</param>
    public PropertyChangedProxy(TSource source, Expression<Func<TSource, TPropType>> selectorExpression, Action<TPropType> onPropertyChanged)
    {
        _source = source;
        _onPropertyChanged = onPropertyChanged;
        // Property "getter" to get the value
        _getValueFunc = selectorExpression.Compile();
        // Name of the property
        var body = (MemberExpression)selectorExpression.Body;
        _modelPropertyname = body.Member.Name;
        // Changed event
        _source.PropertyChanged += SourcePropertyChanged;
    }

    private void SourcePropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == _modelPropertyname)
        {
            _onPropertyChanged(_getValueFunc(_source));
        }
    }
}
 4
Author: Roemer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-20 14:38:49

Uznałem ten artykuł za pomocny: http://social.msdn.microsoft.com/Forums/vstudio/en-US/3eb70678-c216-414f-a4a5-e1e3e557bb95/mvvm-businesslogic-is-part-of-the-?forum=wpf

Moje podsumowanie:

Ideą organizacji MVVM jest umożliwienie łatwiejszego ponownego użycia widoków i modeli, a także umożliwienie oddzielenia testów. Twój model widoku to model, który reprezentuje podmioty widoku, twój model reprezentuje podmioty biznesowe.

A gdybyś chciał zagrać później w pokera? Większość interfejsu użytkownika powinna być wielokrotnego użytku. Jeśli logika gry jest związana z modelem widoku, bardzo trudno byłoby ponownie użyć tych elementów bez konieczności przeprogramowania modelu widoku. Co zrobić, jeśli chcesz zmienić interfejs użytkownika? Jeśli logika gry jest powiązana z logiką modelu widoku, musisz ponownie sprawdzić, czy gra nadal działa. Co zrobić, jeśli chcesz utworzyć komputer i aplikację internetową? Jeśli twój model widoku zawiera logikę gry, próba utrzymania tych dwóch elementów byłaby skomplikowana aplikacje obok siebie, ponieważ logika aplikacji nieuchronnie byłaby związana z logiką biznesową w modelu widoku.

Powiadomienia o zmianie danych i walidacja danych mają miejsce w każdej warstwie(widok, model widoku i model).

Model zawiera reprezentacje danych (Podmioty) i logikę biznesową specyficzną dla tych podmiotów. Talia kart to logiczna "rzecz" o nieodłącznych właściwościach. Dobra talia nie może mieć duplikatów kart włożonych do niej. Musi ujawnić sposób, aby uzyskać najlepsze karty(s). Musi wiedzieć, aby nie rozdawać więcej kart, niż zostało. Takie zachowania talii są częścią modelu, ponieważ są nieodłącznym elementem talii kart. Będą też modele dealerów, modeli graczy, modeli ręcznych itp. Te modele mogą i będą współdziałać.

Model widoku będzie składał się z prezentacji i logiki aplikacji. Cała praca związana z wyświetlaniem gry jest oddzielona od logiki gry. Może to obejmować wyświetlanie rąk jako obrazy, prośby o karty do modelu dealera, ustawienia wyświetlania użytkownika itp.

Treść artykułu:

Zasadniczo, sposób, w jaki lubię to wyjaśnić, jest to, że Twoja sprawa logika i byty składają się na model. To jest to, co twoje specyficzne aplikacja jest używana, ale może być współdzielona przez wiele aplikacji.

Widok jest warstwą prezentacyjną-wszystko, co dotyczy faktycznie bezpośrednio współpracujące z użytkownikiem.

ViewModel jest zasadniczo "klej", który jest specyficzny dla Twojego aplikacja, która łączy je ze sobą.

Mam tu ładny diagram, który pokazuje jak się łączą:

Http://reedcopsey.com/2010/01/06/better-user-and-developer-experiences-from-windows-forms-to-wpf-with-mvvm-part-7-mvvm/

W Twoim przypadku-poradzimy sobie ze szczegółami...

Walidacja: zwykle występuje w dwóch formach. Walidacja związana do wejścia użytkownika nastąpiłoby w ViewModel (przede wszystkim) i widok (ie:" Numeryczne " pole tekstowe uniemożliwiające wprowadzanie tekstu jest obsługiwane dla Ciebie w widoku, itp.). W związku z tym walidacja danych wejściowych z użytkownik jest zazwyczaj problemem maszyn wirtualnych. To powiedziawszy, często jest druga "warstwa" walidacji - jest to Walidacja, że dane jest używany zgodnie z zasadami biznesowymi. Często jest to część sam model - gdy wpychasz dane do modelu, może to spowodować błędy walidacji. VM będzie wtedy musiał przeformułuj tę informację z powrotem do widoku.

Operacje " za kulisami bez widoku, jak pisanie do DB, wysyłanie wiadomości e-mail itp.": Jest to naprawdę część " specyficznej dla domeny Operacje " w moim diagramie i jest naprawdę czysto częścią modelu. To jest to, co próbujesz ujawnić za pomocą aplikacji. Na ViewModel działa jak pomost do ujawniania tych informacji, ale operacje są czysto modelowe.

Operacje dla ViewModel: ViewModel potrzebuje więcej niż tylko INPC - wymaga również operacji specyficznych dla Twojej aplikacji (nie logiki biznesowej), takich jak zapisywanie preferencji i stanu użytkownika, itd. To będzie różna aplikacja. przez app., nawet podczas łączenia ten sam "model".

Dobry sposób na przemyślenie tego - powiedzmy, że chcesz zrobić 2 wersje swojego system zamówień. Pierwszy znajduje się w WPF, a drugi w sieci interfejs.

Wspólna logika, która dotyczy samych rozkazów (wysyłanie e-maili, wpisując w DB, itp.) jest modelem. Twoja aplikacja to ujawnienie tych operacji i danych użytkownikowi, ale robi to w 2 sposoby.

W aplikacji WPF interfejs użytkownika (co przeglądarka współdziała z) jest "widok" - w aplikacji internetowej jest to w zasadzie kod, który (przynajmniej w końcu) zamienia się w javascript + html + css na klienta.

ViewModel to reszta "kleju", który jest wymagany do dostosowania swojego model (czynności te związane z zamówieniem) aby to działało z określoną technologią widoku / warstwą, której używasz.

 2
Author: VoteCoffee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-20 19:29:23

Powiadomienie na podstawie INotifyPropertyChangedi INotifyCollectionChanged jest dokładnie tym, czego potrzebujesz. Aby uprościć sobie życie z subskrypcją zmian właściwości, walidacją nazwy właściwości w czasie kompilacji, unikaniem wycieków pamięci, radzę użyć PropertyObserverz Josh Smith ' s MVVM Foundation. Ponieważ ten projekt jest open source, możesz dodać tylko tę klasę do swojego projektu ze źródeł.

Aby zrozumieć, jak korzystać z PropertyObserver przeczytaj Ten artykuł .

Przyjrzyj się też dokładniej Reactive Extensions (Rx) . Możesz wystawić IObserver ze swojego modelu i subskrybować go w widoku model.

 2
Author: Vladimir Dorokhov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-04 14:15:17

Chłopaki wykonali niesamowitą robotę odpowiadając na to, ale w takich sytuacjach naprawdę czuję, że wzór MVVM jest bólem, więc poszedłbym użyć kontrolera nadzorującego lub podejścia pasywnego widoku i puścił system wiążący przynajmniej dla obiektów modelowych, które same generują zmiany.

 1
Author: Ibrahim Najjar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-15 22:31:14

Jestem zwolennikiem modelu kierunkowego - > View Model - > View flow of changes od dłuższego czasu, jak widać w sekcji Flow of Changes mojego artykułu MVVM z 2008 roku. Wymaga to implementacji INotifyPropertyChanged Na modelu. Z tego co wiem, stało się to powszechną praktyką.

Ponieważ wspomniałeś Josha Smitha, spójrz na jego własność . Jest to klasa pomocnicza do subskrybowania zdarzenia INotifyPropertyChanged.PropertyChanged modelu.

Możesz w rzeczywistości posłużę się tym podejściem znacznie dalej, ponieważ niedawno stworzyłem moją klasę PropertiesUpdater . Właściwości w modelu widoku są obliczane jako złożone wyrażenia, które zawierają jedną lub więcej właściwości w modelu.

 1
Author: HappyNomad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-16 01:03:44

Nie ma nic złego w zaimplementowaniu INotifyPropertyChanged wewnątrz modelu i wysłuchaniu go wewnątrz ViewModel. W rzeczywistości można nawet kropkę do właściwości modelu w XAML: {Binding Model.ModelProperty}

Jeśli chodzi o zależne / obliczone właściwości tylko do odczytu, do tej pory nie widziałem nic lepszego i prostszego niż to: https://github.com/StephenCleary/CalculatedProperties. jest to bardzo proste, ale niezwykle przydatne, to naprawdę "formuły Excel dla MVVM" - po prostu działa tak samo jak Excel propagujący zmiany w komórkach formuły bez dodatkowego wysiłku z twojej strony.

 1
Author: KolA,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-04 11:23:22

Możesz wywoływać zdarzenia z modelu, do którego viewmodel musiałby się zapisać.

Na przykład ostatnio pracowałem nad projektem, dla którego musiałem wygenerować treeview(oczywiście model miał hierarchiczny charakter). W modelu miałem obserwowalną kolekcję o nazwie ChildElements.

W modelu viewmodel zapisałem odniesienie do obiektu w modelu i zapisałem Zdarzenie CollectionChanged z observablecollection, tak: ModelObject.ChildElements.CollectionChanged += new CollectionChangedEventHandler(insert function reference here)...

Wtedy twój viewmodel dostaje automatycznie powiadamiany po zmianie w modelu. Możesz zastosować tę samą koncepcję używając PropertyChanged, ale będziesz musiał jawnie podnieść zdarzenia zmiany właściwości ze swojego modelu, aby to zadziałało.

 0
Author: Mash,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-15 18:52:19

Wydaje mi się to bardzo ważne pytanie - nawet jeśli nie ma presji, aby to zrobić. Pracuję nad projektem testowym, który obejmuje przegląd drzewa. Istnieją elementy menu i takie, które są mapowane do poleceń, na przykład Delete. Obecnie aktualizuję zarówno model, jak i model widoku z poziomu modelu widoku.

Na przykład,

public void DeleteItemExecute ()
{
    DesignObjectViewModel node = this.SelectedNode;    // Action is on selected item
    DocStructureManagement.DeleteNode(node.DesignObject); // Remove from application
    node.Remove();                                // Remove from view model
    Controller.UpdateDocument();                  // Signal document has changed
}
To proste, ale wydaje się mieć bardzo podstawową wadę. Typowy test jednostkowy wykonywałby polecenie, a następnie sprawdzał wynik w zobacz model. Ale to nie sprawdza, czy aktualizacja modelu była poprawna, ponieważ oba są aktualizowane jednocześnie.

Więc być może lepiej jest użyć technik takich jak PropertyObserver, aby aktualizacja modelu wyzwalała aktualizację modelu widoku. Ten sam test jednostkowy byłby teraz skuteczny tylko wtedy, gdyby obie akcje zakończyły się sukcesem.

To nie jest potencjalna odpowiedź, zdaję sobie sprawę, ale wydaje się, że warto tam umieścić.

 0
Author: Art,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-04 22:57:14