Bonjour,

Toujours dans mon test de DataTemplate pour ListBox.
La hierarchie est la suivante :
le Model : un objet Person qui contient 2-3 propriétés String et une collection d'objet Phone qui contient 2 propriétés String.
Class Person :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
Public Property Name As String
Public Property SubName As String
Public Property Age As Byte
Public Property ID As Integer
Public Property Phones As Observable(Of Phone)
Class Phone:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
Public Property PhoneNumber As String
Public Property PhoneType As String
Une View principale qui contient une ListBox bindée sur une observable de Person,
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
<Grid.DataContext>
    		<Binding Source="{StaticResource MainWindowViewModelDataSource}"/>
</Grid.DataContext>
<ListBox x:Name="lbox"  Margin="5" Grid.Row="0" ItemsSource="{Binding PersonList}">
avec un DataTemplate
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
<DataTemplate>
<local:PersonMoveableItem>
   <i:Interaction.Triggers>
       <i:EventTrigger EventName="DeleteItem">
          <ei:CallMethodAction MethodName="HandleDeleteItem"  TargetObject="{Binding ElementName=lbox, Path=DataContext}"/>
       </i:EventTrigger>
   </i:Interaction.Triggers>
</local:PersonMoveableItem>
</DataTemplate>     	
</ListBox.ItemTemplate>
composé d'un UserControl (générique permettant de déplacer copier supprimer remplacer etc un item) contenant un autre UserControl (pour afficher l'objet Person),
lequel lui-même a une listbox dont le template est similaire et affiche un objet Phone.
l'item PersonMoveable:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
Public Class PersonMoveableItem
    Inherits MoveableItem
    Sub New()
        MyBase.New()
        MyBase.ItemObject = New PersonTemplate
    End Sub
End Class
View PersonTemplate :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<StackPanel HorizontalAlignment="Left">
<StackPanel Orientation="Horizontal" >
   <TextBlock Text="{Binding Name}" MinWidth="50" Margin="5"/>
   <TextBlock Text="{Binding SubName}" MinWidth="50" Margin="5"/>
   <TextBlock Text="{Binding Age}" MinWidth="50" Margin="5"/>
   <TextBlock Text="{Binding ID}" MinWidth="50" Margin="5"/>
</StackPanel>
<ListBox  ItemsSource="{Binding Phones}">       
    <ListBox.ItemTemplate>
        <DataTemplate>
         <local:PhoneMoveableItem>
         </local:PhoneMoveableItem>
       </DataTemplate>
   </ListBox.ItemTemplate>
 </ListBox>
</StackPanel>
L'item PhoneMoveable
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
Public Class PhoneMoveableItem
    Inherits MoveableItem
    Sub New()
        MyBase.New()
        MyBase.ItemObject = New PhoneTemplate
    End Sub
End Class
le Template Phone :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
<StackPanel Orientation="Horizontal" x:Name="LayoutRoot">
   <TextBlock MinWidth="50" Text="{Binding PhoneType}" Margin="2"/>
   <TextBlock MinWidth="50" Text="{Binding PhoneNumber}"/>
</StackPanel>
Un ViewModel qui me fournit la collection observable de Person et les Handle pour les routedEvent du UserControl me permettant de supprimer/ajouter etc un objet Person ou Phone.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
Private _personList As ObservableCollection(Of Person)
    Public Property PersonList() As ObservableCollection(Of Person)
        Get
            If IsNothing(_personList) Then
                _personList = GetPersonList()
            End If
            Return _personList
        End Get
        Set(ByVal value As ObservableCollection(Of Person))
            _personList = value
            OnPropertyChanged(Me, "PersonList")
        End Set
    End Property
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Public Sub HandleDeleteItem(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
 
        Select Case e.OriginalSource.GetType
            //Person deletion
            Case GetType(PersonMoveableItem)
                Dim p As PersonMoveableItem = DirectCast(e.OriginalSource, PersonMoveableItem)
                If Me.PersonList.Count > 1 Then
                    Me.PersonList.Remove(p.DataContext)
                Else
                    Me.PersonList(0) = New Person
                End If
                //phone deletion
            Case GetType(PhoneMoveableItem)
                Dim s As ContentPresenter = e.Source
                Dim p As PersonMoveableItem = s.TemplatedParent
                Dim d As Person = p.DataContext
                Dim phoneitem As PhoneMoveableItem = e.OriginalSource
                d.Phones.Remove(phoneitem.DataContext)
        End Select
 
        e.Handled = True
 
    End Sub
Tant que ma collection de Phone est déclarée Observable dans la classe Person, tout fonctionne correctement, parfait.

Mais, un peu neuf dans le MVVM, je me dis que ce n'est pas très rigoureux d'avoir un Observable dans le Model !!
Derechef, je transforme la propriété Phones dans Person en List(Of Phone) et je créé un Converter ListToObservable pour mon UserControl qui affiche la collection de Phone d'une Person.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Public Class ListToObservableConverter
    Implements IValueConverter
    //source to target
    Public Function Convert(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.Convert
        If IsNothing(value) Then
            Return value
        End If
        Dim myType As Type = value.GetType().GetProperty("Item").PropertyType
        Dim myList As IEnumerable(Of Object) = value
        Return New ObservableCollection(Of Object)(myList)
    End Function
    //target to source
    Public Function ConvertBack(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack
        Throw New NotImplementedException
    End Function
End Class
Mais, bim badaboum, le converter instancie une New observable à partir de la List(Of), donc lorsque je récupère l'évènement Delete par exemple, je supprime un élément de la liste de Phone de l'objet Person affiché, mais je supprime pas l'élément de collection observable créée et, évidemment, l'élément reste dans la liste !!

Donc, ma question est la suivante : comment respecter le modèle MVVM sans 'casser' le lien entre la collection Phone affichée et ma collection Person.Phone accessible via le ViewModel ?

Merci,

Stéphane.