La liaison WPF ComboBox ne fonctionne pas comme prévu
-
04-07-2019 - |
Question
Je souhaite que la propriété ItemsSource de mon WPF ComboBox soit liée à la propriété MyListObject. Le problème est que lorsque je mets à jour la propriété MyList dans le code, le ComboBox WPF ne reflète pas la mise à jour. Je soulève l'événement PropertyChanged après avoir effectué la mise à jour et je pensais que WPF était censé répondre automatiquement en mettant à jour l'interface utilisateur. Est-ce que je manque quelque chose?
Voici l'objet CLR:
Imports System.ComponentModel
Public Class MyListObject
Implements INotifyPropertyChanged
Private _mylist As New List(Of String)
Public Sub New()
_mylist.Add("Joe")
_mylist.Add("Steve")
End Sub
Public Property MyList() As List(Of String)
Get
Return _mylist
End Get
Set(ByVal value As List(Of String))
_mylist = value
End Set
End Property
Public Sub AddName(ByVal name As String)
_mylist.Add(name)
NotifyPropertyChanged("MyList")
End Sub
Private Sub NotifyPropertyChanged(ByVal info As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
End Sub
Public Event PropertyChanged(ByVal sender As Object, _
ByVal e As System.ComponentModel.PropertyChangedEventArgs) _
Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
End Class
Voici le XAML:
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300"
xmlns:local="clr-namespace:WpfApplication1"
>
<Window.Resources>
<ObjectDataProvider x:Key="MyListObject" ObjectType="{x:Type local:MyListObject}"/>
</Window.Resources>
<Grid>
<ComboBox Height="23"
Margin="24,91,53,0"
Name="ComboBox1"
VerticalAlignment="Top"
ItemsSource="{Binding Path=MyList, Source={StaticResource MyListObject}}"
/>
<TextBox Height="23"
Margin="24,43,134,0"
Name="TextBox1"
VerticalAlignment="Top" />
<Button Height="23"
HorizontalAlignment="Right"
Margin="0,43,53,0"
Name="btn_AddName"
VerticalAlignment="Top"
Width="75">Add</Button>
</Grid>
</Window>
Et voici le code-behind simple:
Class Window1
Private obj As New MyListObject
Private Sub btn_AddName_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) _
Handles btn_AddName.Click
obj.AddName(TextBox1.Text)
End Sub
End Class
Merci!
La solution
Vous vous associez à une liste de chaînes. Cette classe de liste n'implémente pas Inotifyproperty. Vous devriez plutôt utiliser une collection observable. Je remarque également dans votre code derrière vous déclarez
Private obj As New MyListObject
Ce n'est pas la ressource statique à laquelle vous êtes lié la liste déroulante. Votre appel à l'ajout ne sera donc pas reflété dans votre vue.
Autres conseils
La solution ObservableCollection est très probablement la solution, mais si elle vous pose problème, vous pouvez accéder directement à votre ressource statique en appelant le code suivant après la mise à jour de votre liste:
DirectCast(Me.FindResource("MyListObject"), ObjectDataProvider).Source = _myList
Essayez d’utiliser un BindingList (Of T) au lieu d'un Liste (de T).
Éditer: WPF est nouveau pour moi et il semble que BindingList ne soit pas une solution complète à votre problème, mais cela pourrait être un pas dans la bonne direction. J'ai pu tester le MyListObject converti en BindingList dans WinForm et l'événement ListChanged a été déclenché dans le contrôle ComboBox qui a ensuite mis à jour sa liste.
J'ai trouvé cette solution (possible) pour intégrer votre classe dans une collection Observable qui pourrait vous aider à résoudre votre problème
Activation de WPF Magic à l'aide de WCF - Partie 1
Ceci est le code pour mettre à jour votre objet en une BindingList. Combinez votre code avec le code de cette ressource et vous devriez être prêt à partir.
Public Class MyListObject
...
'Private _mylist As New List(Of String)
Private _mylist As New BindingList(Of String)
...
'Public Property MyList() As List(Of String)
' Get
' Return _mylist
' End Get
' Set(ByVal value As List(Of String))
' _mylist = value
' End Set
'End Property
Public Property MyList() As BindingList(Of String)
Get
Return _mylist
End Get
Set(ByVal value As BindingList(Of String))
_mylist = value
End Set
End Property
...
End Class