0

I am trying to create a list onscreen of all animals in a database in an MVVM WPF application, but this list must contain properties that are specific to the animals' respective sex (represented by a class).

The model consists of Male and Female classes inheriting from MustInherit Animal. Following this example, The ViewModel is therefore also split into MaleViewModel and FemaleViewModel which both inherit from a generic MustInherit AnimalViewModel, below

Public MustInherit Class AnimalViewModel(Of T as Animal)
    Inherits GalaSoft.MvvmLight.ViewModelBase

    Public Property Animal As T

    Protected Sub New(NewAnimal as T)
        Me.Animal = NewAnimal
    End Sub

    Public Overrides Function ToString() as String
        Return String.Format("{1}{2} ""{3}"" | {4}",
                             Me.Animal.RightEarTag,
                             Me.Animal.LeftEarTag,
                             Me.Animal.ShortName,
                             Me.SexIdentifierName)
    End Function

    'Makes a distinction between "bull", "cow", "steer", "heifer",
    'or other classes as needed
    Public MustOverride Function SexIdentifierName as String

End Class

Public Class MaleViewModel
    Inherits AnimalViewModel(Of Male)

    Public Sub New(AnAnimal as Male)
        MyBase.New(AnAnimal)
    End Sub

    Public Overrides Function SexIdentifierName as String
        'Logic goes here
    End Function
End Class

I have also created an AnimalListWorkspace ViewModel, with an AnimalList property that is bound to a UserControl on the View. I would like to add the correct type of ViewModel to this list, but it is invalid to cast a base type to an inherited type, as I tried in the following code.

Public Class AnimalListWorkspace
    Inherits WorkspaceViewModel

    Public ReadOnly Property AnimalList as IEnumerable(Of AnimalViewModel(Of Animal))
        Get
            Dim animalVmList = New List(Of AnimalViewModel(Of Animal))

            For Each an in AnimalDatabase.Animals
                If TypeOf an Is Male Then
                    animalVmList.Add(New MaleViewModel(Ctype(an, Male)))
                ElseIf TypeOf an Is Female Then
                    animalVmList.Add(New FemaleViewModel(Ctype(an, Female)))
                Else
                    Throw New InvalidCastException("Unknown sex/type of animal")
                End If
            Next

            Return animalVmList        
        End Get
    End Property

What is the best way to deal with these computed, MustOverride properties? I have considered

  1. Moving their implementation up to the AnimalViewModel

  2. Altering the database object to retrieve Males and Females specifically

These solutions might work for this example because there are so few inherited members, but they both seem tightly-coupled and hard to refactor later.

Milliron X
  • 1,174
  • 14
  • 26

1 Answers1

0

The type arguments seem unnecessary. The base class' constructor accepts an Animal and knows only about animals anyway. Male is a specific type of Animal. The following should work, i.e. you can add any type of specific AnimalViewModel to a List(Of AnimalViewModel).

View Models:

Public MustInherit Class AnimalViewModel
    Inherits GalaSoft.MvvmLight.ViewModelBase

    Public Property Animal As Animal

    Protected Sub New(NewAnimal As Animal)
        Me.Animal = NewAnimal
    End Sub

    Public Overrides Function ToString() As String
        Return String.Format("{1}{2} ""{3}"" | {4}",
                             Me.Animal.RightEarTag,
                             Me.Animal.LeftEarTag,
                             Me.Animal.ShortName,
                             Me.SexIdentifierName)
    End Function

    Public MustOverride Function SexIdentifierName() As String

End Class

Public Class MaleViewModel
    Inherits AnimalViewModel

    Public Sub New(AnAnimal As Male)
        MyBase.New(AnAnimal)
    End Sub

    Public Overrides Function SexIdentifierName() As String
        Return "Male"
    End Function
End Class

Models:

Public Class Animal
    Public Property RightEarTag As String
    Public Property LeftEarTag As String
    Public Property ShortName As String
End Class

Public Class Male
    Inherits Animal

End Class

Workspace:

Public Class AnimalListWorkspace

    Public ReadOnly Property AnimalList As IEnumerable(Of AnimalViewModel)
        Get
            Dim animalVmList = New List(Of AnimalViewModel)

            For Each an In AnimalDatabase.Animals
                If TypeOf an Is Male Then
                    animalVmList.Add(New MaleViewModel(CType(an, Male)))
                ElseIf TypeOf an Is Female Then
                    animalVmList.Add(New FemaleViewModel(CType(an, Female)))
                Else
                    Throw New InvalidCastException("Unknown sex/type of animal")
                End If
            Next

            Return animalVmList
        End Get
    End Property
End Class
mm8
  • 163,881
  • 10
  • 57
  • 88