CountryChooser(per flag)

  • WPF

Es gibt 62 Antworten in diesem Thema. Der letzte Beitrag () ist von asusdk.

    CountryChooser(per flag)

    Hallo Ihr lieben,

    nach dem ich nun schon gut 1 Jahr nicht mehr dazu gekommen bin dem Hobby Programmieren zu frönen möchte ich mich wieder einarbeiten, als erstes Projekt würde ich gerne für meine WPF Anwendungen, ein kleines UserControl schreiben, welches mir 7 Flaggen anzeigt und je nach dem auf welches geklickt wurde, in einer Property den Ländernamen des jeweiligen Landes anzeigt.



    Leider hab ich in dem Jahr so einiges vergessen und muss wieder reinkommen, daher wollte ich mal fragen wie Ihr das grundlegend lösen würdet, mein Grundgedanke war erstmal einfach 7 Buttons in einem UCL einzufügen, und per klick auf die jeweiligen Buttons eine Dependency Property zu setzen, anhand derer ich das gewählte Land auslesen kann, mir erschließt sich allerdings so kein Weg wie ich z.B. die gewählte Flagge dann optisch hervorheben könnte, wobei mir hier im Hinterkopf rumschwirrt das evtl. ein Converter vonnöten wäre? Evtl. denke ich auch grade über das Ziel hinaus und Ihr könnt mir einen Tipp geben wie ich das am sinnvollsten anstelle


    Lieben Gruß und danke
    AsusDK
    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If
    Hi,
    da würde sich ein ToogleButton anbieten (oder Radio wenn nur eins geklickt werden darf)
    dann mit CommandParameter arbeiten und im ViewModel im Command mit einem Switch den Parameter verarbeiten.
    Den Zustand des Button kannst Du dann im Template für das hervorheben nutzen.
    "Hier könnte Ihre Werbung stehen..."
    Hi Micha,

    danke schon mal sehr für deine Antwort, jetzt muss ich dazu gleich mal Fragen stellen, da ich bisher weder mit einem Togglebutton noch jemals mit Commandparametern gearbeitet habe, gehe ich recht in der Annahme, das Commandparameter in erster Linie dafür da sind das ich nur ein Command schreiben muss, welches ich allen Togglebuttons zuordnen würde, und anhand des Parameters welcher lediglich in der View per Button abweichend ist, dann innerhalb des Commands unterscheiden kann was geschieht? So das ich nicht pro Button ein eigenes Command brauche?

    Und zu den Togglebuttons konnte ich erstmal nichts Detailliertes finden, wie verhalten sich diese? Wenn da mehrere, wie in diesem falle 7 nebeneinander sind und einer wird geklickt, werden dann automatisch die anderen 6 "unselektiert" und nur der geklickte automatisch als selektiert, oder wie kann ich mir das vorstellen?

    Danke dir schonmal und LG
    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If

    asusdk schrieb:

    ein kleines UserControl schreiben, welches mir 7 Flaggen anzeigt und je nach dem auf welches geklickt wurde, in einer Property den Ländernamen des jeweiligen Landes anzeigt.
    Sowas sollte man mit einem ItemsControl abhandeln, und einem DataTemplate.
    Im Viewmodel dann Datensätze mit Bild-Resource-Pfad und LänderName.
    Bitte nicht anfangen, mit DependancyProperties und Kram rumzufuchteln.
    UserControl kann man schon machen, aber darauf eben besagtes ItemsControl.

    Vergleichbares findet sich zB hier: Grundlagen - MVVM-Anwendungs-Struktur - im "Variations"-Post: Zunächstmal sind da (im ersten View) die Persons in einem ItemsControl (ohne DataTemplate) dargestellt mit einem PersonView (mit DataTemplate) als Detail-Ansicht.
    Bei dir müsste das ItemsControl das DataTemplate kriegen (vergleichbar dem letzten View aus dem "Variation"-Post), und die Detail-Ansicht wäre reduziert auf einen einfachen String darzustellen.
    Danke dir erfinderdesrades, ich schau mir das mal an, allerdings müsste ich mit so einem Ansatz dann explizit ein ViewModel für das UCL erstellen? Gedacht war es hier, quasi das UCL danach eigenständig ohne weiteres ViewModel zu verwenden, da es mir in Programmen, so bereits extrem schwerfällt noch den Überblick über die viewmodels zu behalten, in endeffekt soll das UCL nach aussen auch nur eine einzelne Property abgeben, "ChoosenCountry". Und da sich die verwendeten Länder nicht ändern, sondern nur die 7 ausgewählten Verwendung finden, ist es doch sehr umständlich dies variabel zu gestalten oder?


    Lieben Gruß und Danke
    AsusDK
    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If
    Hmm - dann sind deine Programme wohl deutlich komplexer als meine.
    Weil ich finde meine Viewmodel-Ordner und ihren Inhalt bislang immer ganz fabelhaft übersichtlich.
    Aber haste recht - du müsstest für dieses UCL ein Viewmodel erstellen (genaugenommen für das DataTemplate, was darin Verwendung findet).
    So scheint mir MVVM ja auch gedacht: ein View-Element (UCL) ist (üblicherweise) assoziiert mit einem Viewmodel-Element (Klasse).

    Umständlich fände ich ein Dependancy-Property-Geraffel.
    Son Viewmodel wäre doch extrem simpel: Klasse mit 2 Properties: ImageLocation und LandName.
    Im MainModel ein Array mit 7 Instanzen dieser Klasse - feddich.
    Meinetwegen noch ein ListCollectionView, dann hast du im MainModel auch Zugriff, welches Land grad angewählt ist.
    Halt wie im Tut gezeigt, nur noch einfacher.

    Also hier mal PseudoCode, nämlich das Mainmodel des Tuts, reduziert auf nur einen Standard-Satz an Persons anzuzeigen:

    VB.NET-Quellcode

    1. Public Class MainModel : Inherits MainModelBase(Of MainModel)
    2. Private __Persons As New ObservableCollection(Of Person)()
    3. Public Property Persons() As New ListCollectionView(__Persons) ' enables to access/observe the currently selected Person
    4. Public Sub New()
    5. Enumerable.Range(0, 10).ForEach(Sub(i) __Persons.Add(Person.FromInt(i))) ' Standard-Personen generieren
    6. Persons.MoveCurrentToFirst() ' Ensure a Record as selected - for Designer-Data-Preview
    7. End Sub
    8. End Class

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Hi Erfinderdesrades,

    ich versuche mich bereits seit deinem Post vorhin, in deinen vorgeschlagenen Lösungsweg einzuarbeiten, ich habe nun:

    Ein LandModel:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. ​Imports System.ComponentModel
    2. Imports System.Runtime.CompilerServices
    3. Public Class CountryModel
    4. Public Sub New()
    5. End Sub
    6. Public Sub New(_land As String, _daybookset As String, _taxenvironment As String, _ivnlanguage As String)
    7. Land = _land : DayBookSet = _daybookset : TaxEnvironment = _taxenvironment : IVNLanguage = _ivnlanguage
    8. End Sub
    9. #Region "Propertys"
    10. Public Property Land As String = ""
    11. Public Property DayBookSet As String = ""
    12. Public Property TaxEnvironment As String = ""
    13. Public Property IVNLanguage() As String = ""
    14. #End Region
    15. #Region "Funktionen"
    16. Public Overrides Function ToString() As String
    17. Return $"{Land}"
    18. End Function
    19. #End Region
    20. End Class


    Ein LänderViewmodel:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. ​Imports System.Collections.ObjectModel
    2. Imports System.ComponentModel
    3. Imports System.Runtime.CompilerServices
    4. Public Class CountrysViewmodel
    5. Implements INotifyPropertyChanged, IDisposable
    6. Public Sub New()
    7. Seed()
    8. End Sub
    9. Private _availablelands As New ObservableCollection(Of CountryModel)
    10. Public Property AvailableLands() As ObservableCollection(Of CountryModel)
    11. Get
    12. Return _availablelands
    13. End Get
    14. Set(ByVal value As ObservableCollection(Of CountryModel))
    15. _availablelands = value
    16. RaisePropertyChanged()
    17. End Set
    18. End Property
    19. Private _selectedland As CountryModel
    20. Public Property SelectedLand() As CountryModel
    21. Get
    22. Return _selectedland
    23. End Get
    24. Set(ByVal value As CountryModel)
    25. _selectedland = value
    26. RaisePropertyChanged()
    27. End Set
    28. End Property
    29. Private Sub Seed()
    30. AvailableLands.Add(New CountryModel("Austria", "EMA-AT", "TCDE-AUT-S", "AT"))
    31. AvailableLands.Add(New CountryModel("Belgium", "EMA-BL", "TCDE-BEL-S", "EN"))
    32. AvailableLands.Add(New CountryModel("France", "EMA-FR", "TCDE-FRA-S", "EN"))
    33. AvailableLands.Add(New CountryModel("Germany", "EMA-DE", "", "GER"))
    34. AvailableLands.Add(New CountryModel("Italy", "EMA-IT", "TCDE-ITA-S", "EN"))
    35. AvailableLands.Add(New CountryModel("Netherlands", "EMA-NL", "TCDE-NLD-S", "EN"))
    36. AvailableLands.Add(New CountryModel("Spain", "EMA-ES", "TCDE-ESP-S", "EN"))
    37. SelectedLand = AvailableLands.Item(3)
    38. End Sub
    39. Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    40. ''' <summary>
    41. ''' Prozedur wirft den INotifyPropertyChanged Event welcher in der WPF benötigt wird um die UI zu verständingen
    42. ''' das eine Änderung an einem Property stattgefunden hat.
    43. ''' </summary>
    44. ''' <param name="prop">Das Propertie welches sich geändert hat. Ist Optional da als Parameter "CallerMemberName" verwendet wird. Wird Nothing übergeben werden alle PRoperties des Views aktualisiert!!</param>
    45. Protected Overridable Sub RaisePropertyChanged(<CallerMemberName> Optional ByVal prop As String = "")
    46. If prop Is Nothing OrElse prop.Length > 0 Then
    47. RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(prop))
    48. End If
    49. End Sub
    50. #Region "IDisposable Support"
    51. Private _disposedValue As Boolean
    52. ' Dient zur Erkennung redundanter Aufrufe.
    53. ' IDisposable
    54. Public Overridable Sub Dispose(disposing As Boolean)
    55. If Not _disposedValue Then
    56. If disposing Then
    57. End If
    58. End If
    59. _disposedValue = True
    60. End Sub
    61. ' Dieser Code wird von Visual Basic hinzugefügt, um das Dispose-Muster richtig zu implementieren.
    62. Public Sub Dispose() Implements IDisposable.Dispose
    63. ' Ändern Sie diesen Code nicht. Fügen Sie Bereinigungscode in Dispose(disposing As Boolean) weiter oben ein.
    64. Dispose(True)
    65. GC.SuppressFinalize(Me)
    66. End Sub
    67. #End Region
    68. End Class


    Und einen ImageConverter:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. ​Imports System.Globalization
    2. Public Class LandToFlagImageConverter
    3. Implements IValueConverter
    4. Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.Convert
    5. If value IsNot Nothing Then
    6. Dim ChoosenLand As String = DirectCast(value, String)
    7. Select Case ChoosenLand
    8. Case "Austria"
    9. Return New Uri("/Assets/Austria.png", UriKind.RelativeOrAbsolute)
    10. Case "Belgium"
    11. Return New Uri("/Assets/Belgium.png", UriKind.RelativeOrAbsolute)
    12. Case "France"
    13. Return New Uri("/Assets/France.png", UriKind.RelativeOrAbsolute)
    14. Case "Germany"
    15. Return New Uri("/Assets/Germany.png", UriKind.RelativeOrAbsolute)
    16. Case "Italy"
    17. Return New Uri("/Assets/Italy.png", UriKind.RelativeOrAbsolute)
    18. Case "Netherlands"
    19. Return New Uri("/Assets/Netherlands.png", UriKind.RelativeOrAbsolute)
    20. Case "Spain"
    21. Return New Uri("/Assets/Spain.png", UriKind.RelativeOrAbsolute)
    22. Case Else
    23. Return New Uri("/Assets/Error.png", UriKind.RelativeOrAbsolute)
    24. End Select
    25. Else
    26. Return New Uri("/Assets/Error.png", UriKind.RelativeOrAbsolute)
    27. End If
    28. End Function
    29. Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.ConvertBack
    30. Throw New NotImplementedException()
    31. End Function
    32. End Class


    Ich denke soweit ich dich richtig verstanden habe das dies der empfohlene Ansatz war ? Jedoch stoße ich gerade auf die Problematik, das in einem ItemsControl, offenbar (zumindest laut google) in diesem, gar kein Item Selektiert werden kann ?
    Verwende ich stattdessen jedoch ein Listview, werden die Images quasi in originalgröße angezeigt, irgendwie fuchs ich mich gerade an der Zielline vorbei oder hab ein brett vorm Kopf ^^


    Danke dir für deinen Input

    LG AsusDK
    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If
    • Das Disposable ist komplett fehl am Platz.
    • Den Converter kannste auch weglassen, wenn du den Uri gleich im LandModel angibst.
    • INotifyPropertyChanged sollte man in einer Viewmodel-Basisklasse implementieren - ist doch unsinn, das Geraffel in jedem Viewmodel neu zu erfinden.
    • Ein LänderViewmodel ist auch unglücklich, weil ein MainViewmodel brauchst du ja noch zusätzlich. (Es sei denn, deine Anwendung soll nichts anderes können als Länder anzeigen, dann wäre LänderViewmodel ja das Mainmodel).
      Wenn aber ein MainViewmodel gegeben, dann könnte man das LänderViewmodel weglassen, und die Initialisierung mehrerer Länder zB als Shared Method im Land anlegen. (so wie ichs mit meine Personen mache: Es gibt nur ein PersonVM, nicht auch noch ein PersonenVM)
      Das SelectedItem entnehme ich immer dem ListCollectionView - da brauchts nicht noch zusätzliche Properties für.

    Gemein gesagt: An WPF/MVVM liegts nicht, wenn dein Code dir umständlich vorkommt.

    Sorry - das ist wirklich ungerecht.
    Weil sieht mir nämlich aus, als würde das durchaus funktionieren, was du auf Beine gestellt hast - und das ist immer erstmal die Hauptsache. :thumbup:

    Dieser Beitrag wurde bereits 10 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Hi,
    ein ToggleButton ist ein Button, der einen Zustand anzeigt. Gedrückt oder nicht gedrückt.
    Für Dein Vorhaben solltest Du eher einen RadioButton nehmen.
    Auch der RadioButton hat eine eigenschaft die anzeigt ob er selektiert ist oder nicht. Diese kannst du im Button Template nutzen um den Button zu designen wenn er selektiert ist.
    Den CommandParameter kannst Du verwenden um im Viewmodel genau einen Command zu haben und in diesem Command fragst du den Parameter ab und reagierst entsprechend.
    Du kannst den RadioButton sogar an ein Enum dran klatschen und dann darauf reagieren.
    oder du nimmst ein dictionary(string,string)
    ein DataTemplate ist dennoch sinnvoll, damit die WPF weis, wie sie das UCL rendern muss wenns benötigt wird.
    Wenn du es MVVM like machen willst dann keep it simple.
    Das Model zeigt wie die Daten aussehen, das Viewmodel zeigt wie die Daten verarbeitet werden, das View zeigt wie die Daten in der Oberfläche Aussehen.
    "Hier könnte Ihre Werbung stehen..."
    Hallo Leute, ich gebe meinen Senf auch dazu ;)

    Ich weis ja das AsusDK noch nicht so weit ist und MVVM eher versucht zu meiden, hier würde ich versuchen das Problem so einfach wie möglich anzugehen.
    @asusdk ein Land-Model (ViewModel) hast du ja bereits. Dieses würde ich um die URI für ein Bild erweitern und in meinem UserControl dieses in eine List(Of LandModel) packen.

    Anders als @ErfinderDesRades würde ich aber dennoch zu einem DependencyProperty greifen da es damit über Binding-Funktionalitäten verfügt und das UserControl somit wiederverwendbar ist.
    Im XAML deines UserControls packst du einfach eine Listbox (du kannst ja das ItemsTemplate später so ändern das die Elemente horizontal angeordnet werden).
    Dann ein weiteres DependencyProperty "SelectedCountry" und im deiner ListBox bindest du SelectedItem auf dein Property "SelectedCountr". Fertich.

    Es wird lediglich eine Klasse benötigt und durch die DependencyProperties kann von aussen darauf gebunden werden. Eine feine runde und vorallem einfache Sache.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Nofear23m schrieb:

    würde ich aber dennoch zu einem DependencyProperty
    Welchen Datentyp soll die DependancyProperty haben?
    Angenommen String.
    Und wenn nun jemand per Viewmodel die Property auf "Banane" setzen will - wird das nicht gehen, denn dieses Land ist nicht vorgesehen.
    Also muss die Property vom Typ Land sein.
    Und im Viewmodel brauchst du Zugriff auf alle vorgesehenen Länder.
    Die sind aber im UCL gekapselt.
    Oder vielleicht auch nicht - vlt. kann man das lösen,... - aber glaub nicht mit nur einer Klasse.
    Auf jeden Fall scheints mir nicht so einfach, wies anfangs aussehen mag.
    Hingegen ein CollectionListView gibt dir Zugriff auf die Länder, die vorgesehen sind, und du kannst auch das selektierte Land ablesen - alles OnBord - ohne zusätzliche Klasse.

    Nein, das Propertie kann ja von Typ LandModel sein. Und er kann dann von aussen auf ein Property der LandModel Instanz binden.

    Ich sehe da kein Problem.
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Lese bitte meine Antwort. Ich sagte ja das es eine ListOf(LandModel) als DP gibt. Auswählbar soll laut Fragestellung nur ein Land sein, also gibt es ein SelectedCountry. Aus.

    Das ist 0815 in WPF. Eine Auflistung und ein selektiertes Objekt. Das war dich die Fragestellung oder nicht?

    Wieviele Länder es da gibt ist schnuppe.
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Hallöchen,

    jetzt bin ich zugegebenermaßen etwas verwirrt, was den nun der richtige Ansatz wäre. Evtl. muss ich hier etwas mehr ins Detail gehen:

    Die Application soll mir am Ende dabei Helfen, Rechnungen zu erstellen, die eigentliche Anwendung verwende ich auch bereits des längeren produktiv für die Arbeit:


    Bisher verwendete ich ein Dropdown, um das eingestellte Land festzulegen, aber da es durchaus vorkommt, dass ich 80 Rechnungen in 2 Tagen ins System kloppen muss, versuche ich mir so viel Zeit zu sparen wie nur möglich, ein simpler Klick auf die jeweilige Länderflagge geht halt doch schneller, als jedes Mal das Dropdown zu öffnen und das Land auszuwählen.
    In der besagten Application, Lade ich die verfügbaren Länder bereits im MainviewModel per Seed()
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub Seed()
    2. AvailableLands.Add(New LandViewModel("Austria", "EMA-AT", "TCDE-AUT-S", "AT"))
    3. AvailableLands.Add(New LandViewModel("Belgium", "EMA-BL", "TCDE-BEL-S", "EN"))
    4. AvailableLands.Add(New LandViewModel("France", "EMA-FR", "TCDE-FRA-S", "EN"))
    5. AvailableLands.Add(New LandViewModel("Germany", "EMA-DE", "", "GER"))
    6. AvailableLands.Add(New LandViewModel("Italy", "EMA-IT", "TCDE-ITA-S", "EN"))
    7. AvailableLands.Add(New LandViewModel("Netherlands", "EMA-NL", "TCDE-NLD-S", "EN"))
    8. AvailableLands.Add(New LandViewModel("Spain", "EMA-ES", "TCDE-ESP-S", "EN"))
    9. End Sub


    in eine observableCollection
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private _availablelands As New ObservableCollection(Of LandViewModel)
    2. Public Property AvailableLands() As ObservableCollection(Of LandViewModel)
    3. Get
    4. Return _availablelands
    5. End Get
    6. Set(ByVal value As ObservableCollection(Of LandViewModel))
    7. _availablelands = value
    8. RaisePropertyChanged()
    9. End Set
    10. End Property


    Also ansich mache ich ja bereits das was ErfinderDesRades vorgeschlagen hat, oder bin ich gerade auf dem falschen Dampfer? Wäre der Weg über ein DependencyProperty so wie ursprünglich gedacht, hier doch die bessere Wahl ?
    mein aktueller Lösungsansatz beeinhaltet auch seine letzten Vorschläge (wenn ich das richtig verstanden und umgesetzt habe). Mir ist durchaus bewusst, das ich eigentlich kein eigenes CountrysViewModel brauchen, da es sich im Moment aber um eine Reine Testapplikation handelte in der ich noch kein Mainviewmodel besaß, verwendete ich es aktuell eben über ein CountrysViewModel.

    Die momentane Test-Applikation sieht folgendermaßen aus, bitte schlagt ruhig Änderungen vor wenn ich etwas falsch gemacht habe:





    MainVievModel:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Collections.ObjectModel
    2. Public Class MainViewModel
    3. Inherits BaseViewModel
    4. Public Sub New()
    5. Seed()
    6. End Sub
    7. Private _availablelands As New ObservableCollection(Of CountryModel)
    8. Public Property AvailableLands() As ObservableCollection(Of CountryModel)
    9. Get
    10. Return _availablelands
    11. End Get
    12. Set(ByVal value As ObservableCollection(Of CountryModel))
    13. _availablelands = value
    14. RaisePropertyChanged()
    15. End Set
    16. End Property
    17. Private _selectedland As CountryModel
    18. Public Property SelectedLand() As CountryModel
    19. Get
    20. Return _selectedland
    21. End Get
    22. Set(ByVal value As CountryModel)
    23. _selectedland = value
    24. RaisePropertyChanged()
    25. End Set
    26. End Property
    27. Private Sub Seed()
    28. AvailableLands.Add(New CountryModel("Austria", "EMA-AT", "TCDE-AUT-S", "AT"))
    29. AvailableLands.Add(New CountryModel("Belgium", "EMA-BL", "TCDE-BEL-S", "EN"))
    30. AvailableLands.Add(New CountryModel("France", "EMA-FR", "TCDE-FRA-S", "EN"))
    31. AvailableLands.Add(New CountryModel("Germany", "EMA-DE", " - ", "GER"))
    32. AvailableLands.Add(New CountryModel("Italy", "EMA-IT", "TCDE-ITA-S", "EN"))
    33. AvailableLands.Add(New CountryModel("Netherlands", "EMA-NL", "TCDE-NLD-S", "EN"))
    34. AvailableLands.Add(New CountryModel("Spain", "EMA-ES", "TCDE-ESP-S", "EN"))
    35. End Sub
    36. End Class


    BaseViewModel:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.ComponentModel
    2. Imports System.Runtime.CompilerServices
    3. Public MustInherit Class BaseViewModel
    4. Inherits NotifyBase
    5. Private Shared ReadOnly HostProcesses As New List(Of String)({"XDesProc", "devenv", "WDExpress"})
    6. Private _isBusy As Boolean
    7. ''' <summary>
    8. ''' Gibt zurück ob sich die ausführung des Codes aktuell in der Entwicklungszeit oder in der Laufzeit befindet.
    9. ''' Für eine Logausgabe muss das LogAction Propertie genutzt werden.
    10. ''' </summary>
    11. ''' <returns>Wird Code des ViewModels vom XAML Designer ausgeführt wird True zurückgegeben.</returns>
    12. <Browsable(False)>
    13. Public ReadOnly Property IsInDesignMode As Boolean
    14. Get
    15. Dim ret = HostProcesses.Contains(Process.GetCurrentProcess().ProcessName)
    16. Return ret
    17. End Get
    18. End Property
    19. End Class



    NotifyBase:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.ComponentModel
    2. Imports System.Runtime.CompilerServices
    3. <Serializable>
    4. Public MustInherit Class NotifyBase
    5. Implements INotifyPropertyChanged, IDisposable
    6. #Region "IDisposable Support"
    7. Private _disposedValue As Boolean
    8. ' Dient zur Erkennung redundanter Aufrufe.
    9. ' IDisposable
    10. Public Overridable Sub Dispose(disposing As Boolean)
    11. If Not _disposedValue Then
    12. If disposing Then
    13. End If
    14. End If
    15. _disposedValue = True
    16. End Sub
    17. ' Dieser Code wird von Visual Basic hinzugefügt, um das Dispose-Muster richtig zu implementieren.
    18. Public Sub Dispose() Implements IDisposable.Dispose
    19. ' Ändern Sie diesen Code nicht. Fügen Sie Bereinigungscode in Dispose(disposing As Boolean) weiter oben ein.
    20. Dispose(True)
    21. GC.SuppressFinalize(Me)
    22. End Sub
    23. #End Region
    24. #Region "INotifyPropertyChanged"
    25. <NonSerialized>
    26. Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    27. ''' <summary>
    28. ''' Prozedur wirft den INotifyPropertyChanged Event welcher in der WPF benötigt wird um die UI zu verständingen
    29. ''' das eine Änderung an einem Property stattgefunden hat.
    30. ''' </summary>
    31. ''' <param name="prop">Das Propertie welches sich geändert hat. Ist Optional da als Parameter "CallerMemberName" verwendet wird. Wird Nothing übergeben werden alle PRoperties des Views aktualisiert!!</param>
    32. Protected Overridable Sub RaisePropertyChanged(<CallerMemberName> Optional ByVal prop As String = "")
    33. If prop Is Nothing OrElse prop.Length > 0 Then RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(prop))
    34. End Sub
    35. #End Region
    36. End Class



    CountryModel:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.ComponentModel
    2. Imports System.Runtime.CompilerServices
    3. Public Class CountryModel
    4. Inherits BaseModel
    5. #Region "Constructor"
    6. Public Sub New()
    7. End Sub
    8. 'Aus dem Land-String wird hier auch per Funktionsaufruf von StringToUri direkt der Pfad für das Icon geladen
    9. Public Sub New(_land As String, _daybookset As String, _taxenvironment As String, _ivnlanguage As String)
    10. Land = _land : DayBookSet = _daybookset : TaxEnvironment = _taxenvironment : IVNLanguage = _ivnlanguage : FlagImageUri = StringToURI(Land)
    11. End Sub
    12. #End Region
    13. #Region "Propertys"
    14. Public Property Land As String = ""
    15. Public Property DayBookSet As String = ""
    16. Public Property TaxEnvironment As String = ""
    17. Public Property IVNLanguage() As String = ""
    18. Public Property FlagImageUri() As Uri
    19. #End Region
    20. #Region "Funktionen"
    21. Public Overrides Function ToString() As String
    22. Return $"{Land}"
    23. End Function
    24. 'Gibt basierend auf dem erhaltenen Land eine passende Uri zurück
    25. Function StringToURI(ByVal BaseUriString As String) As Uri
    26. If String.IsNullOrEmpty(BaseUriString) Then
    27. Return New Uri("/Assets/Error.png", UriKind.RelativeOrAbsolute)
    28. Else
    29. Return New Uri($"/Assets/{BaseUriString}.png", UriKind.RelativeOrAbsolute)
    30. End If
    31. End Function
    32. #End Region
    33. End Class



    BaseModel:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. <Serializable>
    2. Public Class BaseModel
    3. Inherits NotifyBase
    4. Private _id As String = ToShortGuid(Guid.NewGuid)
    5. Public Property ID() As String
    6. Get
    7. Return _id
    8. End Get
    9. Set(ByVal value As String)
    10. _id = value
    11. RaisePropertyChanged()
    12. End Set
    13. End Property
    14. Private _creTime As String = DateTime.Now.ToShortDateString
    15. Public Property CreTime() As String
    16. Get
    17. Return _creTime
    18. End Get
    19. Set(ByVal value As String)
    20. _creTime = value
    21. RaisePropertyChanged()
    22. End Set
    23. End Property
    24. Private _creBy As String = Environment.UserName
    25. Public Property CreBy() As String
    26. Get
    27. Return _creBy
    28. End Get
    29. Set(ByVal value As String)
    30. _creBy = value
    31. RaisePropertyChanged()
    32. End Set
    33. End Property
    34. Private Shared Function ToShortGuid(ByVal newGuid As Guid) As String
    35. Return Convert.ToBase64String(newGuid.ToByteArray()).Replace("+"c, "-"c).Replace("/"c, "_"c).Substring(0, 22)
    36. End Function
    37. 'Private Shared Function ToLongGuid(ByVal shortGuid As String) As Guid
    38. ' Return New Guid(Convert.FromBase64String(shortGuid.Replace("-"c, "+"c).Replace("_"c, "/"c) & "=="))
    39. 'End Function
    40. End Class



    Saschas RelayCommand:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Namespace Utilitys
    2. ''' <summary>
    3. ''' Diese Klasse Implementiert das ICommand Interface, so muss man nicht in jeder Klasse eines ViewModel alles selbst implementieren.
    4. ''' Einfach eine Command wie folgt Instanzieren:
    5. ''' MyCommand = New RelayCommand(AddressOf MyCommand_Execute, AddressOf MyCommand_CanExecute)
    6. ''' </summary>
    7. Public Class RelayCommand : Implements ICommand
    8. #Region " Fields "
    9. ReadOnly _execute As Action(Of Object)
    10. ReadOnly _canExecute As Predicate(Of Object)
    11. #End Region
    12. #Region " Constructors"
    13. ''' <summary>
    14. ''' Erstellt einen neuen Command welcher NUR Executed werden kann.
    15. ''' </summary>
    16. ''' <param name="execute">The execution logic.</param>
    17. ''' <remarks></remarks>
    18. Public Sub New(execute As Action(Of Object))
    19. Me.New(execute, Nothing)
    20. End Sub
    21. ''' <summary>
    22. ''' Erstellt einen neuen Command welcher sowohl die Execute als auch die CanExecute Logik beinhaltet.
    23. ''' </summary>
    24. ''' <param name="execute">Die Logik für Execute.</param>
    25. ''' <param name="canExecute">Die Logik für CanExecute.</param>
    26. ''' <remarks></remarks>
    27. Public Sub New(execute As Action(Of Object), canExecute As Predicate(Of Object))
    28. If execute Is Nothing Then
    29. Throw New ArgumentNullException("execute")
    30. End If
    31. _execute = execute
    32. _canExecute = canExecute
    33. End Sub
    34. #End Region
    35. #Region " ICommand Members "
    36. ''' <summary>
    37. ''' Setzt die CanExecute-Methode des ICommand-Interfaces auf True oder False
    38. ''' </summary>
    39. ''' <param name="parameter"></param>
    40. ''' <returns>Gibt zurück ob die Aktion ausgeführt werden kann oder nicht</returns>
    41. ''' <remarks>
    42. ''' Benutzt DebuggerStepThrough from System.Diagnostics
    43. ''' Der Debugger überspringt diese Prozedur also, es sei den es wird explizit ein Haltepunkt gesetzt.
    44. ''' </remarks>
    45. <DebuggerStepThrough>
    46. Public Function CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute
    47. Return _canExecute Is Nothing OrElse _canExecute(parameter)
    48. End Function
    49. ''' <summary>
    50. ''' Event welches geworfen wird wenn die Propertie CanExecuteChanged sich ändert.
    51. ''' </summary>
    52. ''' <remarks></remarks>
    53. Public Custom Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged
    54. AddHandler(value As EventHandler)
    55. If _canExecute IsNot Nothing Then
    56. AddHandler CommandManager.RequerySuggested, value
    57. End If
    58. End AddHandler
    59. RemoveHandler(value As EventHandler)
    60. If _canExecute IsNot Nothing Then
    61. RemoveHandler CommandManager.RequerySuggested, value
    62. End If
    63. End RemoveHandler
    64. RaiseEvent(sender As Object, e As EventArgs)
    65. End RaiseEvent
    66. End Event
    67. ''' <summary>
    68. ''' Führt die Prozedur Execute des ICommand.Execute aus
    69. ''' </summary>
    70. ''' <param name="parameter"></param>
    71. ''' <remarks></remarks>
    72. Public Sub Execute(parameter As Object) Implements ICommand.Execute
    73. _execute(parameter)
    74. End Sub
    75. #End Region
    76. End Class
    77. End Namespace



    CountryFlagChooser:
    Spoiler anzeigen

    XML-Quellcode

    1. <UserControl x:Class="CountryFlagChooser"
    2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    5. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    6. xmlns:local="clr-namespace:CountryChooser"
    7. mc:Ignorable="d"
    8. Height="Auto"
    9. Width="auto"
    10. VisualTextRenderingMode="ClearType"
    11. RenderOptions.BitmapScalingMode="Fant"
    12. BorderBrush="Black"
    13. BorderThickness="0,1,0,1">
    14. <Viewbox>
    15. <ListView ItemsSource="{Binding AvailableLands}"
    16. BorderBrush="Black"
    17. SelectedItem="{Binding SelectedLand}">
    18. <ListView.ItemContainerStyle>
    19. <Style TargetType="{x:Type ListViewItem}">
    20. <Style.Triggers>
    21. <Trigger Property="IsSelected" Value="true">
    22. <Setter Property="Margin" Value="200,120,200,0"/>
    23. <Setter Property="Effect">
    24. <Setter.Value>
    25. <DropShadowEffect ShadowDepth="2" />
    26. </Setter.Value>
    27. </Setter>
    28. </Trigger>
    29. </Style.Triggers>
    30. </Style>
    31. </ListView.ItemContainerStyle>
    32. <ListView.ItemTemplate>
    33. <DataTemplate >
    34. <Grid>
    35. <Grid.RowDefinitions>
    36. <RowDefinition Height="*"/>
    37. <RowDefinition Height="*"/>
    38. </Grid.RowDefinitions>
    39. <Image Source="{Binding FlagImageUri}"
    40. Margin="30,0"
    41. Grid.Row="0"
    42. MaxHeight="500"
    43. MaxWidth="500"
    44. RenderOptions.BitmapScalingMode="Fant"/>
    45. <TextBlock Text="{Binding Land}"
    46. Grid.Row="1"
    47. HorizontalAlignment="Center"
    48. FontSize="120"
    49. FontWeight="Bold"
    50. FontStretch="Condensed"
    51. Margin="1,-5"/>
    52. </Grid>
    53. </DataTemplate>
    54. </ListView.ItemTemplate>
    55. <ListView.ItemsPanel>
    56. <ItemsPanelTemplate>
    57. <StackPanel Orientation="Horizontal" />
    58. </ItemsPanelTemplate>
    59. </ListView.ItemsPanel>
    60. </ListView>
    61. </Viewbox>
    62. </UserControl>


    MainWindow-Xaml:

    Spoiler anzeigen

    XML-Quellcode

    1. <Window x:Class="MainWindow"
    2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    6. xmlns:local="clr-namespace:CountryChooser"
    7. mc:Ignorable="d"
    8. Title="MainWindow" Height="450" Width="800">
    9. <Grid>
    10. <Grid.RowDefinitions>
    11. <RowDefinition Height="Auto"/>
    12. <RowDefinition Height="Auto"/>
    13. <RowDefinition Height="Auto"/>
    14. <RowDefinition Height="Auto"/>
    15. </Grid.RowDefinitions>
    16. <local:CountryFlagChooser Grid.Row="0"/>
    17. </Grid>
    18. </Window>


    Und aufgeteilt im Projekt hab ich es wie folgt:



    Ansich funktiniert es jetzt schonmal wie gewünscht, ich werde noch einiges an Arbeit in Styles stecken müßen, und das wird viel einarbeit, aber ich finde es aktuell nicht sehr toll wie das selektierte Land angezeigt wird, nur hab ich noch nicht rausgefunden wie ich etwas komplett selbst Stylen kann, naja fiel ja noch kein Meister vom Himmel ^^


    Nachtrag: Ansich find ich auch die Idee von @MichaHo ziemlich cool, ich konnte allerdings bislang nicht herausfinden, wie ich bei einem RelayCommand, eigene Parameter mitgeben und im Command dann auslesen kann.
    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If
    NotifyBase: Was zum Kuckuck willst du unbedingt disposen?
    Du hast nix zum Disposen, als hüte dich vor dem IDisposable-Interface!
    Weisst du denn, was bei GC.SuppressFinalize passiert?
    Und tatsächlich rufst du Dispose doch nirgends auf!
    Muss man aber, wenn man mit disposablen Klassen hantiert.

    CountryModel: Ähm - es ist ein Viewmodel. Du bindest das View daran.
    StringToURI - ist das private oder public?
    Wie dem auch sei: Es sollte Private Shared sein - keine Objekt-Methode.

    BaseModel - ok - wenn du entscheidest, dass alle dein Modelse diese Properties aufweisen sollen.
    Aaargh! - es geht um Viewmodels - nicht um Models. NotifyBase hat nur Sinn für Viewmodels. INotifyPropertyChanged ist ein Interface, was Databinding unterstützt, also Bindings von View an Viewmodel!

    RelayCommand - ok (glaub)

    CountryFlagChooser
    guck nochmal in meim Tut, wie einfach es ist, eine Person zu selecten (IsSynchronisizedWithCurrentItem = "true"). Ein ItemContainerStyle ist nicht unbedingt nötig - erst bei MultiSelection braucht man das.
    Ein DataTemplate ohne Angabe des Datentyps? - hmm, hmm - guck nochmal.

    MainWindow
    Ich hätte ja den DataContext definiert. Dann sieht man bereits im Designer, ob das Ucl richtig funzt - guck nochmal.

    Projekt-Aufteilung
    Wie oben gesagt: Manche Viewmodel firmieren bei dir unter Model, ausserdem manche Utils unter Model, oder Viewmodel.
    Wie ich gelegentlich sage: Das AuseinanderDividieren von Model und Viewmodel, wenn es nicht nötig ist, schafft Verwirrung und Irrtümer, ohne jeden Gewinn in Aussicht zu stellen.
    Eine Richtlinie:
    INotifyPropertyChanged ist erfunden, um Databinding zu unterstützen. Databinding verbindet UI und Klassen.
    Folglich ist, was über INotifyPropertyChanged verfügt (zb geerbt) Viewmodel - nicht Model. Weil Xaml kann daran binden.
    Die Unterscheidung Model / Viewmodel ist oft garnet nötig, aber wenn man es tut, gehören solche Klassen mit INotifyPropertyChanged ins ViewModel - nicht ins Model.

    Daraus folgt auch, dass Viewmodel-Klassen nicht einfach Model-Klassen beerben dürfen (sondern sie müssen ViewmodelBase beerben).
    Daraus wiederum folgen allerlei Probleme - die wiederum erst @Nofear' mit allerlei Infrastruktur-Utilities einigermassen befriedigend löst.
    NotifyBase: Was zum Kuckuck willst du unbedingt disposen?Du hast nix zum Disposen, als hüte dich vor dem IDisposable-Interface!Weisst du denn, was bei GC.SuppressFinalize passiert?


    Ich weiß ehrlich gesagt nicht mal wofür dieser Teil da/zuständig ist, der war mal in einem Sampleprojekt, mit dabei, bei dem Teil mit der InotifyPropertyChange, und da ich nicht herausfinden konnte ob ich das benötige oder nicht, hab ich es schlicht immer mitkopiert.

    CountryModel: Ähm - es ist ein Viewmodel. Du bindest das View daran.


    Ok, dann hab ich wohl bisher immer noch nicht verstanden, wonach das unterschieden wird, mein Wissensstand war, das das ViewModel, die Zwischenschicht zwischen Model und View darstellt, also in dem Falle das MainviewModel, als Viewmodel, und dann das CountryModel als Model oder seh ich hier etwas falsch?

    StringToURI - ist das private oder public?Wie dem auch sei: Es sollte Private Shared sein - keine Objekt-Methode.


    Ich habs nun zu Private geändert, aber bislang hab ich noch nie einen Unterschied zwischen "Function" oder "Private bzw. Shared Function" feststellen können, hat bisher immer funktioniert, Gibt es einen bestimmten Grund warum ich das Private stellen soll ?


    Aaargh! - es geht um Viewmodels - nicht um Models. NotifyBase hat nur Sinn für Viewmodels. INotifyPropertyChanged ist ein Interface, was Databinding unterstützt, also Bindings von View an Viewmodel!


    Ok, aber wie kriegt die View dann mit, wenn sich um zugrundeliegenden Modell etwas ändert? Denn die View ist ja nur mit dem ViewModel verbunden, wenn ich nun aber im Modell, das z.B. in einer ObservableCollection im Viewmodel ist, etwas ändere, wie kriegt die view das sonst mit?


    guck nochmal in meim Tut, wie einfach es ist, eine Person zu selecten (IsSynchronisizedWithCurrentItem = "true"). Ein ItemContainerStyle ist nicht unbedingt nötig - erst bei MultiSelection braucht man das.

    Ich hab mir dein Tutorial angesehen, und nicht zum ersten mal ^^ Leider kann ich nicht herausfinden was genau du eigentlich meinst, was mir hier helfen soll, bisher finde ich das ItemControl leider absolut unbrauchbar hierführ, denn ich kann darin keine Items anklicken oder dergleichen, bei der Listview funktioniert es und innerhalb der Viewbox passt auch das Scaling endlich wieder

    ​Ein DataTemplate ohne Angabe des Datentyps? - hmm, hmm - guck nochmal.

    Ok, wieso soll ich den denn angeben, wen das Datatemplate doch nur diesem einen Control zugewiesen ist ?

    Ich hätte ja den DataContext definiert. Dann sieht man bereits im Designer, ob das Ucl richtig funzt - guck nochmal.


    Das ist ja quasi das einzige das im Codebehind passiert, oder hat es einen gravierenden Vorteil dies im XAML zu tun? Ausser das ich eine grobe Ansicht dessen im Designer sehen kann, wie es Im laufenden Betrieb aussieht? (funktioniert in diesem Falle leider gar nicht, er zeigt halt stattdessen nur das Land als String an)


    Die Unterscheidung Model / Viewmodel ist oft garnet nötig, aber wenn man es tut, gehören solche Klassen mit INotifyPropertyChanged ins ViewModel - nicht ins Model.


    Ja leider muss ich zugeben, dass mich das alles meist nur verwirrt, nur findet man überall gepredigt das man das aufteilen soll, ich will im Prinzip nur:

    1.Das alles so sauber geschrieben ist wie möglich, damit ich quasi nicht das ganze Programm immer neuschreiben muss, wenn ich einen kleinen Teil ändere, und so gut wie alle tutorials die ich bisher in Bezug auf die WPF gefunden habe, drehen sich um MVVM.
    2.Das ich mir vor allem das Erstellen von Fenstern in Zukunft möglichst sparen kann, also nach Möglichkeit alles nur noch über Usercontrols/Views lösen, aber da fängt ja dann scheinbar schon mein Denkfehler an, da ich Model/ViewModel wohl falsch unterscheide. und jedes einzelne View anscheinend ein einzelnes Viewmodel braucht

    Wie hast du dir denn beigebracht das alles richtig zu Unterscheiden, ich muss zugeben das ich mich meist einfach tagelang mit google auseinandersetze und solange an einem Projekt sitze bis es halt das gewünschte Ergebnis liefert, aber so fehlt mir halt oft der Kontext, evtl. hast du da einen guten Tipp für mich ?


    LG und Danke



    Nachtrag:
    @Gonger96
    Gibt es einen Grund für deine IsInDesignMode Property? Ich verwende DesignerProperties.GetIsInDesignMode, funktioniert tadellos und ohne irgendwelche komischen Prozesse abfragen zu müssen.


    Nein, das war damals auch in dem Sample drin aus dem ich InotifyPropertyChange kopiert habe, und da auch dies ohne nähere Erklärung enthalten war hab ich das ebenso mitkopiert wie das IdisposableInterface
    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „asusdk“ ()

    Gonger96 schrieb:

    funktioniert tadellos und ohne irgendwelche komischen Prozesse

    Das hat er aus meine Klasse und ich habs von @ErfinderDesRades.

    Es gefiel mir damals gut. Warum. Weil man im ViewModel kein View reinreichen will (ich zumindest) und eine Abhängigkeit auf die PresentationFramework.dll ist da weniger hilfreich.

    Grüße
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    asusdk schrieb:

    ..., wonach das unterschieden wird, mein Wissensstand war, das das ViewModel, die Zwischenschicht zwischen Model und View darstellt, ...
    Kommt mir zunächstmal richtig vor.
    Mein Verständnis ist: Viewmodel sind die Klassen, an die im Xaml gebunden wird.
    Model, oder DataModel können davon verschiedene Klassen sein, die die Wirklichkeit modellieren, Verträge, Personen, Abrechnungen, was weissich - Länder. Ich sage "können", weil meist treffe ich diese Unterscheidung garnet.
    Wie gesagt: Ich würde eine Länder-Klasse bauen, mit Doppel-Funktion: sowohl Wirklichkeit modellierend als auch databindable.
    Eine dritte Gruppe sind Infrastruktur-Klassen, irgendwelche Helferlein für alles mögliche.
    ZB das RelayCommand - das ist ja nix spezifisches für meine Anwendung. Also hier modelliert es einen Löschen-Button, und woanders mw. einen Zufüge-Button.

    asusdk schrieb:

    ... zwischen Model und View darstellt, also in dem Falle das MainviewModel, als Viewmodel, und dann das CountryModel als Model oder seh ich hier etwas falsch?
    An beide wird gebunden, beide modellieren das View.
    Codeseitig gibt es ein KlassenObjekt, mit einer Liste Objekte einer anderen Klasse.
    Viewseitig gibt es ein Form mit einem ItemsControl mit vielen Fähnchen drinne.

    Wie gesagt: Ein Model kann ich da garnet unterscheiden, und sehe es auch noch nicht als sinnvoll an, diese Unterscheidung mit Gewalt herbeizuführen.
    Deine Viewmodel-Klassen modellieren derzeit sowohl die View, die du beabsichtigst, als auch die Wirklichkeit, also die Tatsache, dass es mehrere Länder gibt in der Welt (gibt es doch, oder?).
    Und zwar es sind dieselben Klassen, die das tun, in Personal-Union quasi.

    asusdk schrieb:

    Ok, aber wie kriegt die View dann mit, wenn sich um zugrundeliegenden Modell etwas ändert?
    Tja, weiss ich auch nicht. Wir haben auch grad kein konkretes Beispiel - weil deine Anwendung hat ja garkein vom Viewmodel unterscheidbares Modell.
    Also eine müssige Frage. Heb sie dir auf für später, wenn du mal mit dem Nur-Viewmodel nicht mehr weiter kommst.
    Versuch nicht mit Gewalt ein Problem zu konstruieren, und dann zu lösen - was nicht da ist.
    (Und lösch den Disposable-Quatsch - das ist nämlich genau sowas.)

    asusdk schrieb:

    Leider kann ich nicht herausfinden was genau du eigentlich meinst, was mir hier helfen soll, bisher finde ich das ItemControl leider absolut unbrauchbar hierführ, denn ich kann darin keine Items anklicken oder dergleichen
    Hmm?
    In meim Tut die WrapPanel-Lösung (WrapPanel erbt glaub sogar von ItemsControl - Listview übrigens auch).
    Lad dir den Code, und tausche das WrapPanel durch ein ItemsControl aus - wenn das WP dich stört.
    Wirste ebensogut in die Person-Viewse herumklicksen können wie wolle.
    Achso - du willst ja das CurrentItem im Viewmodel haben, und ich hab dir IsSynchronisizedWithCurrentItem = "true" empfohlen.
    Sorry, das war Quatsch IsSynchronisizedWithCurrentItem ist "nur" in Listbox, ListView, Datagrid,... verfügbar - also in allen Controls, die von Selector erben (welcher wiederum von ItemsControl erbt).
    Also nimm eine Listbox - wie in Post#1 des Tuts.
    Oder tu ein DataTemplate mit Type-Angabe (etwa das aus uclPerson) in die MainWindow-Resourcen des Post#1-Samples des Tuts, und hofflich kommt dann KlickiBunti in die Listbox - ohne dass deswegen die CurrentItem-Logik verloren geht. (Letztere zeigt sich ja am Delete-Button).
    Also probierma - ich garantiere für nix.

    asusdk schrieb:

    wieso soll ich den [Type] denn angeben, wenn das Datatemplate doch nur diesem einen Control zugewiesen ist ?
    Stimmt. In dem Fall muss nicht.
    Aber wenn obiges Experiment funktioniert ist glaub ein Vorzug davon gut veranschaulicht: Ein DataTemplate wendet sich aufgrund seiner Type-Angabe an.
    Aber ist auch eine Frage guten Stils: Ein DataTemplate wird numal für einen bestimmten Typ entworfen. Der Typ soll dann auch dranstehen, findich.
    Ausserdem ermöglicht das Data-Preview im Designer.
    Guck dir mal dieses Video an: Grundlagen - MVVM: "Binding-Picking" im Xaml-Editor - wieviel Wysiwyg schon zur Entwicklungszeit möglich ist, wenn man es sich nicht versaut.
    Etwa durch Unterlassen der DataTemplate-Type-Angabe.
    Oder durch DataContext im CodeBehind zuweisen statt im Xaml.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()