Laden...

WPF MVVM - Richtig umgesetzt?

Erstellt von Denis1501 vor 9 Jahren Letzter Beitrag vor 9 Jahren 8.309 Views
D
Denis1501 Themenstarter:in
16 Beiträge seit 2014
vor 9 Jahren
WPF MVVM - Richtig umgesetzt?

Hallo zusammen,

Nach stundenlanger suche im Internet, bin ich immer noch nicht schlauer..
Habe ich mein MVVM - Pattern richtig umgesetzt? Kann ich irgendetwas verbessern oder vielleicht alles neu machen?

Es würde mich sehr freuen, wenn ihr mir kurz zu meinem Quellcode ein Review geben könntet.

MfG Denis1501



Mein View:

<Window x:Class="DataBinding.View"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="View" Height="350" Width="525">
    <StackPanel>
        <TextBlock Name="lblDate" HorizontalAlignment="Center" Text="{Binding Path=Date}" />
        <TextBlock Name="lblTime" HorizontalAlignment="Center" Text="{Binding Path=Time}" />
    </StackPanel>
</Window>




Mein ViewModel:

    public class ViewModel : BindingBase
    {
        Model myModel;

        public ViewModel()
        {
            myModel = new Model();
            myModel.PropertyChanged += myModel_PropertyChanged;
        }

        void myModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "Time": Time = myModel.Time;
                    break;
                case "Date": Date = myModel.Date;
                    break;
                default:
                    break;
            }
        }

        #region Properties

        private string _Date;
        public string Date
        {
            get { return _Date; }
            set { SetProperty(ref _Date, value); }
        }

        private string _Time;
        public string Time
        {
            get { return _Time; }
            set { SetProperty(ref _Time, value); }
        }

        #endregion
    }




Meine BindingBase:

    public class BindingBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        protected void SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
        {
            if (!Equals(storage, value))
            {
                storage = value;
                OnPropertyChanged(propertyName);
            }
        }
    }




Mein Model:

    public class Model : BindingBase
    {
        public Model()
        {
            DispatcherTimer dpt = new DispatcherTimer();

            dpt.Interval = new TimeSpan(0, 0, 1);
            dpt.Tick += new EventHandler(dpt_Tick);

            dpt.Start();
        }

        private void dpt_Tick(object sender, EventArgs e)
        {
            new Thread(UpdateData).Start();
        }

        private void UpdateData()
        {
            Date = DateTime.Now.ToString("d");
            Time = DateTime.Now.ToString("T");
        }

        #region Properties

        private string _Date;
        public string Date
        {
            get { return _Date; }
            set { SetProperty(ref _Date, value); }
        }

        private string _Time;
        public string Time
        {
            get { return _Time; }
            set { SetProperty(ref _Time, value); }
        }

        #endregion
    }


2.207 Beiträge seit 2011
vor 9 Jahren

Hallo Denis1501,

du hast das mit dem INotifyPropertyChanged noch nicht (komplett) verstanden 😉.

Du brauchst das Event nicht abonnieren. Durch dein Setter im Property läuft ja das NotifyPropertyChanged ja schon.

Du setzt von aussen einfach dein Property am ViewModel neu, dann läuft dein INotifPropChanged und dein UI wird informiert.

Kannst auch mal Wpf Basics I – How to make first steps of Databinding und Wpf Basics II – INotifyPropertyChanged schauen.

Die Forensuche bringt auch:
Wieso Model, wenn man das ViewModel nutzen kann?
[erledigt] XAML Update bei Property Änderung
MVVM in Verbindung mit der 3 Schichten-Architektur

Gruss

Coffeebean

P
1.090 Beiträge seit 2011
vor 9 Jahren

@Coffeebean,

wenn ich das richtig sehe Aboniert er im VM das PropertyChange des Models.
Wenn das VM auf Änderungen des Models Reagieren soll, ist da auch korrekt.

Sollte man mal gelesen haben:

Clean Code Developer
Entwurfsmuster
Anti-Pattern

2.207 Beiträge seit 2011
vor 9 Jahren

Hallo Palin,

ja, habs auch gesehen. Trotzdem: Das Update zu abonnieren ist erstmal nicht verkehrt, wenn es darum geht das VM irgendwie in Kenntnis darüber zu setzen, dass woanders was passiert ist. Aber dann mit einem Switch/Case da durch zu laufen ist, bei mehreren Properties einfach nicht sauber. Dein Switch/Case wächst und wächst...

Gruss

Coffeebean

D
Denis1501 Themenstarter:in
16 Beiträge seit 2014
vor 9 Jahren

Sollte ich dann mein Model von INotifyPropertyChanged erben lassen
und für jede Eigenschaft, die ich im ViewModel brauch, ein Event erstellen?

@Coffeebean:
Deine Links hab ich mir angeschaut, aber wirklich weitergeholfen haben sie mir nicht, trotzdem Danke!

Gruß,
Denis1501

2.207 Beiträge seit 2011
vor 9 Jahren

Hallo Denis1501,

du lässt im Moment dein Model **und ** dein VM erben von BindingBase. Also schmeisst du das Event, dass sich etwas geändert hat, zwei mal. Du bindest aber nur auf das Property im ViewModel. Du musst das Notify nur an der Stelle schmeissen, auf das das UI auch "hört". Das Switch/Case ist hässlich, das wollen wir weghaben.

Möglichkeit 1) Schmeiss das NotifPropChanged im ViewModel. Somit: Das Model informiert das VM, dass sich etwas geändert hat, nachdem es fertig ist. Model schmeisst das Event. Im VM machst du dann auf die Properties ein NotifyPropertyChanged. Das Model kann das VM schon kennen, setzt die Properties direkt darauf (Durch dein "SetProperty" schmeisst du dann das Update automatisch.)
(Die Möglichkeit und die Tatsache, dass du das schmeisst, finde ich nicht so schön)

Möglichkeit 2) Dein Model hat ja schon die Properties und dort sind sie auch richtig. Damit arbeitest du ja. Somit: Binde vom UI über das Model auf deine Properties im Model. Biete das Model als Property an. Ich würde es auch nicht "Model" nennen, sondern in dem Fall "TimerService" oder sowas. (Über die Namensgebung will ich nicht diskutieren hier 😉 ). Im XAML bindest du dann auf das Property vom Service. Und das setzt du ja im Service. Dann brauchst du im ViewModel dein BindingBase nicht mehr. Die Properties können dann aus dem ViewModel raus. Auch dein Eventhandler und dein Switch/Case.

Mach für den Service und für das ViewModel noch Interfaces.

Gruss

Coffeebean

D
Denis1501 Themenstarter:in
16 Beiträge seit 2014
vor 9 Jahren

Hallo Coffeebean,

Wenn ich dich richtig verstehe ist dann ja mein ViewModel nutzlos?
Ich bräuchte dann nur mein View und mein Model?

Gruß,
Denis1501

2.207 Beiträge seit 2011
vor 9 Jahren

Wenn ich dich richtig verstehe ist dann ja mein ViewModel nutzlos?

Um himmels Willen, diese Annahme ist fundamental falsch.

Dein ViewModel representiert deine View. Wenn ich als Entwickler wissen will, welche Infos eine View hat, nehme ich das Interface vom ViewModel und schaue, was da so drauf ist. Du benutzt es nur als Fassade und bietest die Infos nicht flach, sondern einfach eine Stufe tiefer an.

Stell dir vor es kommt noch ein Service dazu, der komplett andere Properties hat. Irgendwann würde dein VM so "voll" werden, dass man es nicht mehr versteht. Daher kapselst du das in den Service, der wiederum die Props hat.

Zweitens kann es dazu noch Properties geben, die keinen Service (oder eine Kapselung) verdienen. Beispielsweise ein "IsXYZVisible" meinetwegen. (Auch hier kommt es wieder drauf an, aber gehen wir mal von einem einfachen Fall aus). Das würde man auf das VM nehmen. Flach, weil es sehr nah an der View hängt.

Wie gesagt: Es kommt immer drauf an. 😉 Nutzlos ist dein VM nie! Es ist ja dein DataContext für deine View!

Gruss

Coffeebean

5.299 Beiträge seit 2008
vor 9 Jahren

ich bin malwieder böse und widerspreche:
Die Trennung von Viewmodel und Model ist in einfachen Fällen eben doch nutzlos.
Tatsächlich müssen die Fälle sogar ziemlich kompliziert werden, damit diese Trennung architektonisch plausibel wird.
Und ich bin immer für KISS, also nicht komplizierter coden als nötig.
Denn bei vorauseilender Verkomplizierung (könnte ja mal ein Service hinzukommen, könnte ja mal in Teamwork Absprachen mit Designer-Kollegen zu berücksichtigen sein) macht mans zu 90% falsch, was sich aber erst dann erweist, wenn die vorausgeeilte Verkomplizierung tatsächlich in Anspruch genommen werden soll.
Und dann hat man nicht nur das einfache Modell zu überarbeiten, sondern auch noch seine fehlerhafte Verkomplizierung erstmal rückzubauen.
Daher trenne ich Viewmodel und Model erst, wenns sich tatsächlich als nötig erweist, nicht vorher.

Der frühe Apfel fängt den Wurm.

2.207 Beiträge seit 2011
vor 9 Jahren

Daher trenne ich Viewmodel und Model erst, wenns sich tatsächlich als nötig erweist, nicht vorher.

Nichts anderes versuchte ich zu sagen. Ich mache es gern von Anfang an so, aber das ist wieder so ein "Kommt-drauf-an"-Ding

Danach müsste der Service oben die Properties einfach auf dem ViewModel setzen. Auch die Möglichkeit habe ich in einem Vorschlag gezeigt.

Gruss

Coffeebean

D
Denis1501 Themenstarter:in
16 Beiträge seit 2014
vor 9 Jahren

Hallo ErfinderDesRades und Coffeebean,

@ErfinderDesRades:

Ich weiß, für mein Beispiel ist das MVVM vielleicht übertrieben, aber es geht mir
vielmehr darum, dass ich dieses Pattern verstehe und deswegen habe ich mir ein relativ simples Beispiel ausgesucht 😃

@Coffeebean:

Dieser Satz hat mich verwirrt 😃

Möglichkeit 2) ... Binde vom UI über das Model auf deine Properties im Model. ...

Du hast warscheinlich gemeint, dass ich über das ViewModel auf mein Model binden soll!

Mein Code sieht jetzt so aus:


View:

<Window x:Class="DataBinding.View"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="clr-namespace:DataBinding"
        Title="View" MinHeight="170" Height="170" MinWidth="300" Width="300" Background="LightBlue">
    <Window.DataContext>
        <vm:ViewModel />
    </Window.DataContext>
    <Grid>
        <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
            <TextBlock Name="lblDate" HorizontalAlignment="Center" Text="{Binding Path=myModel.Date}" FontSize="50" FontWeight="ExtraBold"/>
            <TextBlock Name="lblTime" HorizontalAlignment="Center" Text="{Binding Path=myModel.Time}" FontSize="50" FontWeight="ExtraBold"/>
        </StackPanel>
    </Grid>
</Window>


ViewModel:

namespace DataBinding
{
    public class ViewModel
    {
        public Model myModel { get; set; }

        public ViewModel()
        {
            myModel = new Model();
        }
    }
}


Model:

using System;
using System.Threading;
using System.Windows.Threading;

namespace DataBinding
{
    public class Model : BindingBase
    {
        public Model()
        {
            DispatcherTimer dpt = new DispatcherTimer();

            dpt.Interval = new TimeSpan(0, 0, 1);
            dpt.Tick += new EventHandler(dpt_Tick);

            dpt.Start();
        }

        private void dpt_Tick(object sender, EventArgs e)
        {
            new Thread(UpdateData).Start();
        }

        private void UpdateData()
        {
            Date = DateTime.Now.ToString("d");
            Time = DateTime.Now.ToString("T");
        }

        #region Properties

        private string _Date;
        public string Date
        {
            get { return _Date; }
            set { SetProperty(ref _Date, value); }
        }

        private string _Time;
        public string Time
        {
            get { return _Time; }
            set { SetProperty(ref _Time, value); }
        }

        #endregion
    }
}


BindingBase:

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace DataBinding
{
    public class BindingBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        protected void SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
        {
            if (!Equals(storage, value))
            {
                storage = value;
                OnPropertyChanged(propertyName);
            }
        }
    }
}

So hast du es gemeint, oder?

Gruß,
Denis1501

2.207 Beiträge seit 2011
vor 9 Jahren

Möglichkeit 2) ... Binde vom UI über das Model auf deine Properties im Model. ...

Natürlich. Entschuldige: Ich meinte "über das ViewModel...".

ErfinderDesRades meinte nicht, dass MVVM übertrieben wäre! Hier geht es darum, was man abstrahiert und was nicht. Ich bin eher Fan von dieser Variante (ViewModel als Fassade). Aber es geht natürlich auch "einfacher" die Props im VM anzubieten, das Model dann arbeiten zu lassen und dem VM bescheid zu sagen.

Aber ja, das wäre eine Möglichkeit. Wie gesagt, du kannst auch dein Model die Properties auf deinem VM setzen lassen. Dann kannst du direkt auf die Props im VM binden. So, wie jetzt, hast dus halt eine Ebene tiefer. KISS beachten. Das meinte ErfinderDesRades in seinem Beitrag. Was eben für dich in Frage kommt.

Aber so sollte es funktionieren. Achte noch auf die C#-Coding-Conventions.

Gruss

Coffeebean

D
Denis1501 Themenstarter:in
16 Beiträge seit 2014
vor 9 Jahren

Dann bedanke ich mich herzlich 😃

Welchen Punkt von der Coding Conventions meinst du im speziellen?

Gruß,
Denis1501

2.207 Beiträge seit 2011
vor 9 Jahren

Hallo Denis1501,

eigentlich wollte ich auf die Naming-Guidelines hinaus. Felder sollten nach camelCase benannt werden. Properties werden jedoch gross geschrieben.

Gruss

Coffeebean

D
Denis1501 Themenstarter:in
16 Beiträge seit 2014
vor 9 Jahren

Ok, vielen Dank!
Werde ich mir zu herzen nehmen.

Der Beitrag kann geschlossen werden 😃

Gruß,
Denis1501

F
10.010 Beiträge seit 2004
vor 9 Jahren

Nein, bitte nicht.

Denn das was du da als letztes gepostest hast ist nicht MVVM, sondern eine Mischung aus MVVM und MVC.

Der View sollte bei echtem MVVM nicht aufs Model zugreifen, sondern immer übers VM gehen.
Wie willst du z.b. bei einem reinen (nichtEdit)View, in deinem Fall das Beschreiben eines Properties unterbinden?
Dadurch das Xaml nur auf das VM zugreift, kannst du eben z.b. bei einem (nichtedit)ViewModel nur Getter machen.
In deinem Fall geht es nicht.
Und MVVM ist gerade dazu gedacht, dem Designer ( derjenige der XAML schreibt) nur genau das zu ermöglichen was der aktuelle BusinessCase verlangt.

D
Denis1501 Themenstarter:in
16 Beiträge seit 2014
vor 9 Jahren

Hallo FZelle,

Was müsste ich denn deiner Meinung nach ändern?

Gruß,
Denis1501

2.207 Beiträge seit 2011
vor 9 Jahren

Wie willst du z.b. bei einem reinen (nichtEdit)View, in deinem Fall das Beschreiben eines Properties unterbinden?
Dadurch das Xaml nur auf das VM zugreift, kannst du eben z.b. bei einem (nichtedit)ViewModel nur Getter machen.

Nun, man kann in einem Interface vom Service auch nur Getter machen und mit Feldern arbeiten.

Und MVVM ist gerade dazu gedacht, dem Designer ( derjenige der XAML schreibt) nur genau das zu ermöglichen was der aktuelle BusinessCase verlangt.

Richtig. Daher muss man eben schauen, was geeigneter ist. Wenn man (zu) viele Properties für die View anbietet, verwirrt ein (Interface von einem) VM mehr, als dass es hilft. Daher halte ich eine Kapselung schon für sinnvoll.

Gruss

Coffeebean

F
10.010 Beiträge seit 2004
vor 9 Jahren

@Coffeebean:

Nun, man kann in einem Interface vom Service auch nur Getter machen und mit Feldern arbeiten.

Dann hast du sogar 2 Models zu dem selben Model. Das halte ich persönlich dann doch eher für zu overengineered.

@Denis1501:
Alles auf das von XAML aus zugegriffen wird ist im ViewModel.

D
Denis1501 Themenstarter:in
16 Beiträge seit 2014
vor 9 Jahren

Hallo zusammen,

Wie aktualisiere ich dann ordnungsgemäß die Daten im ViewModel?
Das Beispiel das ich hier hab ist nämlich ein stark vereinfachtes Problem von mir..

Ich bekomme in meinem Model Daten von einer SPS, und diese würde ich gerne dem View im ViewModel zur verfügung stellen.

Gruß,

Denis1501

2.207 Beiträge seit 2011
vor 9 Jahren

Was FZelle meint, haben wir vorher in den zwei Möglichkeiten schon besprochen. Es war die erste 😉

BindingBase ins ViewModel, aus dem Model raus
Lass das Model arbeiten, schmeiss ein Event, wenn es fertig ist. Du brauchst ja irgendeine Benachrichtigung, wenn dein Service fertig ist.
Fang das Event im ViewModel und aktualisiere im Eventhandler deine Properties
(Ich würde das SetProperty rausnehmen und RaisePropertyChanged explizit aufrufen, wenn sich das Prop ändert)

Wie gesagt: Beides geht. Je nach UseCase ist die Möglichkeit, die du jetzt hast besser oder eben alles "flach" auf dem ViewModel zu haben. Dann representiert dein VM auch deine View.

Gruss

Coffeebean

F
10.010 Beiträge seit 2004
vor 9 Jahren

Jede Klasse die die Änderung von Properties Signalisieren muss, sollte INotifyPropertyChanged implementieren.
Wenn du das dann im Model und im VM machen musst, ist das eben so.

Ich würde das SetProperty lassen, denn man sollte RaisePropertyChanged nur machen wenn das Property sich auch ändert.

Ich würde aber anstatt Equals den EqualityComparer benutzen.
Auch würde ich da ein CheckPropertyChanged draus machen, denn es gibt Situationen im Setter wo du bei Änderungen des Properties was machen musst, und dann hast du das gleich als Antwort.


        public bool CheckPropertyChanged<T>(ref T field, T newValue, [CallerMemberName] string propertyName = null)
        {
            if (EqualityComparer<T>.Default.Equals(field, newValue))
            {
                return false;
            }
            field = newValue;
            RaisePropertyChanged(propertyName);
            return true;
        }

5.299 Beiträge seit 2008
vor 9 Jahren

jo, ich hab auch sone Methode, nenne sie aber ChangePropIfDifferent(), denn die macht ja wesentlich was anderes als nur PropertyChanged zu checken.

Der frühe Apfel fängt den Wurm.

16.807 Beiträge seit 2008
vor 9 Jahren

Davon abgesehen, dass sich der Threadersteller ohnehin sehr schwer tut macht es diese Diskussion nicht leichter.

Wenn es sich bei dem Model um zB eine (Datenbank-)Entität handelt, dann bin ich bei euch beim Thema, dass dieses ebenfalls INotifyPropertyChanged implementiert; also Model und ViewModel.
Wenn es sich beim Model allerdings um einen Service handelt, der gemäß allgemeiner Programmiercharaktere nichts von seiner Bindung wissen sollte, dann würde ich Kopf-schüttelnd Abwinken und dem Threadersteller nur empfehlen: lass den Scheiss mit dem INotifyPropertyChanged im Service.

Klar, man kann das mit dem INotifyPropertyChanged im Service schon machen; aber dann isses halt - auf Deutsch - k*cke.

Ich halt mich aber jetzt aus dem Thema wieder raus, denn je mehr Köche hier am Werk sind, desto mehr verwirrt das die Suppe des Threaderstellers.

F
10.010 Beiträge seit 2004
vor 9 Jahren

Ein Service ist kein Model, also warum sollte er INPC senden?

Manchmal muss man einfach nicht so komplex denken, dann wird vieles einfacher.

D
Denis1501 Themenstarter:in
16 Beiträge seit 2014
vor 9 Jahren

Hallo zusammen,

Wie würdet ihr dann dieses Programm programmieren?

Ihr bekommt Daten, in dem fall die Zeit von der Uhr, und die muss auf der Oberfläche angezeigt werden. Komplett in MVVM versteht sich, und keine Mischung aus MVC oder sonst was, nur reines MVVM!

Ein bisschen Code wäre an dieser stelle vielleicht nützlich 😃

Gruß,
Denis1501

5.299 Beiträge seit 2008
vor 9 Jahren

Ich hab keine Sps, von der ich Daten bekomme - da bräuchte ich einen Mock.

Also code du den DatenGenerator, dann code ich die Anzeige

Und dass die Daten nur aus "Zeit von der Uhr" bestehen kaufe ich dir nicht ab.

Und von manchem Standpunkt aus kann man meiner Lösung widersprechen, denn ich trenne Daten nur dann auf in Model und ViewModel, wenn das auch nötig ist, und sonst nicht.

Also "reines MVVM" ist ein Begriff über den keine Einigkeit besteht.

Der frühe Apfel fängt den Wurm.

D
Denis1501 Themenstarter:in
16 Beiträge seit 2014
vor 9 Jahren

Das mit der Zeit von der Uhr ist nur eine Vereinfachung, damit man sich mehr auf das MVVM selber konzentrieren kann.. Und ob es nötig ist oder nicht, darüber kann man streiten. Allerdings ist dies ja so extrem simpel gehalten, damit man das MVVM leichter versteht.

Gruß,
Denis1501

5.299 Beiträge seit 2008
vor 9 Jahren

Ja, aber das ist grad der Punkt.
Wenn da nur "Zeit von der Uhr" kommt, werde ichn Deibel tun, mich mit Model-Viewmodel-Brimborium verrückt zu machen.
Wenn aber das Programm auf bestimmte Daten-Zustände komplex reagieren muss, evtl. Steuersignale zurücksenden, Benachrichtigungen ausgeben, Funktionalität (de-)aktivieren oder whatever: dann würde das in einem Viewmodel-Klumpen sicher überaus hässlich und gehört aufgedröselt.

Der frühe Apfel fängt den Wurm.

D
Denis1501 Themenstarter:in
16 Beiträge seit 2014
vor 9 Jahren

Sollte ich mein ViewModel so aufbauen?

using System.ComponentModel;
namespace DataBinding
{
    public class ViewModel : BindingBase
    {
        Model myModel;

        public ViewModel()
        {
            myModel = new Model();
            myModel.PropertyChanged += myModel_PropertyChanged;
        }

        void myModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            OnPropertyChanged(e.PropertyName);
        }

        #region Properties

        public string Date
        {
            get { return myModel.Date; }
            set { myModel.Date = value; }
        }

        public string Time
        {
            get { return myModel.Time; }
            set { myModel.Time = value; }
        }

        #endregion
    } 
}

5.299 Beiträge seit 2008
vor 9 Jahren

ich hab nichts dagegen.
Nur ein Datum und eine Zeit sollten niemals den Datentyp string haben - dafür gibts den Datentyp DateTime.
Und es wäre nur eine Property, ein DateTime beinhaltet nämlich beides.

Und - das ist immer mein Problem: Bislang ist nichts erkennbar, was das Viewmodel kann, was das Model nicht kann. Also ein Sinn, bzw. eine Aufgabe, ein Concern.

Aber vlt müsste man das Model angucken.

Der frühe Apfel fängt den Wurm.

3.511 Beiträge seit 2005
vor 9 Jahren

Hallo,

warum das Model im ViewModel? Ist unnötig. Das Model zum ViewModel mappen und später wieder zurück. Geht es dir nur um die Anzeige der Zeit aus der Uhr? Dann brauchst du noch nicht mal ein Model. Da reicht ein ViewModel vollkommen aus.

Kleines Beispiel:
Irgendwo hast du ein Service, der dir die Uhrzeit sagt:


public interface ITimer
{
  public event EventHandler<TimerEventArgs> EventName;
}

public class TimerEventArgs: EventArgs
{
  public DateTime Value { get; set; }
}

ViewModel:


public class ViewModel: ViewModelBase
{
  private readonly ITimer _timer;
  private string _date;
  private string _time;

  private void OnEventName(object sender, TimerEventArgs e)
  {
    Time = e.Value.ToString("HH:mm");
    Date = e.Value.ToString("dd.mm.yyyy");
  }

  public ViewModel(ITimer timer)
  {
    _timer = timer;
    _timer.EventName += OnEventName;
  }

  public string Time 
  {
    get { return _time; }
    set
    {
      _time = value;
      NotifyPropertyChanged(nameof(Time));
    }
  }

  // Date sieht genau so aus
}

Zum Schluss das Ganze einfach im Xaml irgendwo mit den TwoWay Binding binden und fertig.

Stimme übrigens ErfinderDesRades zu: Date und Time nicht als String. Habe es jetzt aber absichtlich im Beispiel so gelassen.

"Jedes Ding hat drei Seiten, eine positive, eine negative und eine komische." (Karl Valentin)

5.299 Beiträge seit 2008
vor 9 Jahren

Das Model zum ViewModel mappen und später wieder zurück. Das ist jetzt noch ne Variante.
Imo ist sone hin-her-mapperei sicherlich aufwändiger, als wenn mans Model as it is mit rein-nimmt - aber egal.
Ich bin jetzt auch draussen - der TE kriegt hier so viele verschiedene Meinungen, glaub nicht, dass das ihm Orientierung gibt.

Also meine 2 Ratschlag, ganz allgemein:1.code nichts, was du nicht begründen kannst.
Also die Frage "Wieso machste das so?" musst du für jedes einzelne Wort im Code stichhaltig beantworten können.
Kannstes nicht, muss der Code weg.
Und dass irgendetwas irgendeinen Pattern befriedigt gehört nicht zu den stichhaltigen Begründungen.

1.Mach immer konsequent so einfach wie möglich (aber nicht einfacher). Mach dir keine Sorgen, wenn dir was zu einfach erscheint - normalerweise wirds eher früher als später wie von selbst kompliziert genug.

Der frühe Apfel fängt den Wurm.