ComboBox.SelectedValue non mis à jour à partir de la source de liaison
-
05-07-2019 - |
Question
Voici mon objet source de liaison:
Public Class MyListObject
Private _mylist As New ObservableCollection(Of String)
Private _selectedName As String
Public Sub New(ByVal nameList As List(Of String), ByVal defaultName As String)
For Each name In nameList
_mylist.Add(name)
Next
_selectedName = defaultName
End Sub
Public ReadOnly Property MyList() As ObservableCollection(Of String)
Get
Return _mylist
End Get
End Property
Public ReadOnly Property SelectedName() As String
Get
Return _selectedName
End Get
End Property
End Class
Voici mon 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" ObjectInstance="" />
</Window.Resources>
<Grid>
<ComboBox Height="23"
Margin="24,91,53,0"
Name="ComboBox1"
VerticalAlignment="Top"
SelectedValue="{Binding Path=SelectedName, Source={StaticResource MyListObject}, Mode=OneWay}"
ItemsSource="{Binding Path=MyList, Source={StaticResource MyListObject}, Mode=OneWay}"
/>
<Button Height="23"
HorizontalAlignment="Left"
Margin="47,0,0,87"
Name="btn_List1"
VerticalAlignment="Bottom"
Width="75">List 1</Button>
<Button Height="23"
Margin="0,0,75,87"
Name="btn_List2"
VerticalAlignment="Bottom"
HorizontalAlignment="Right"
Width="75">List 2</Button>
</Grid>
</Window>
Voici le code-behind:
Class Window1
Private obj1 As MyListObject
Private obj2 As MyListObject
Private odp As ObjectDataProvider
Public Sub New()
InitializeComponent()
Dim namelist1 As New List(Of String)
namelist1.Add("Joe")
namelist1.Add("Steve")
obj1 = New MyListObject(namelist1, "Steve")
.
Dim namelist2 As New List(Of String)
namelist2.Add("Bob")
namelist2.Add("Tim")
obj2 = New MyListObject(namelist2, "Tim")
odp = DirectCast(Me.FindResource("MyListObject"), ObjectDataProvider)
odp.ObjectInstance = obj1
End Sub
Private Sub btn_List1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles btn_List1.Click
odp.ObjectInstance = obj1
End Sub
Private Sub btn_List2_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles btn_List2.Click
odp.ObjectInstance = obj2
End Sub
End Class
Lorsque la fenêtre est chargée pour la première fois, les liaisons sont correctement reliées. La ComboBox contient les noms " Joe " et " Steve " et " Steve " est sélectionné par défaut. Toutefois, lorsque je clique sur un bouton pour faire basculer ObjectInstance sur obj2, le ComboBox ItemsSource est rempli correctement dans la liste déroulante, mais SelectedValue est défini sur Nothing au lieu d'être égal à obj2.SelectedName.
La solution
Nous avons eu un problème similaire la semaine dernière. Cela concerne la façon dont SelectedValue
met à jour ses composants internes. Ce que nous avons constaté, c’est que si vous définissez SelectedValue
, le changement que nous devions définir ne définissait pas SelectedItem
, qui mettrait correctement à jour tout. Ma conclusion est que SelectedValue
est conçu pour les opérations et non définies . Mais cela peut être juste un bogue dans la version actuelle de 3.5sp1 .net
Autres conseils
Pour susciter une conversation de deux ans:
Si vous souhaitez utiliser des chaînes, vous pouvez également les lier à la propriété Text de la liste déroulante.
<ComboBox Text="{Binding Test}">
<ComboBoxItem Content="A" />
<ComboBoxItem Content="B" />
<ComboBoxItem Content="C" />
</ComboBox>
Cela est lié à quelque chose comme:
public class TestCode
{
private string _test;
public string Test
{
get { return _test; }
set
{
_test = value;
NotifyPropertyChanged(() => Test); // NotifyPropertyChanged("Test"); if not using Caliburn
}
}
}
Le code ci-dessus est bidirectionnel, donc si vous définissez Test = "B" dans le code, la liste déroulante affichera «B», puis si vous sélectionnez «A» dans la liste déroulante, la propriété bound reflétera le changement.
Utiliser
UpdateSourceTrigger=PropertyChanged
dans la liaison
Problème:
La classe ComboBox recherche l'objet spécifié à l'aide de la méthode IndexOf. Cette méthode utilise la méthode Equals pour déterminer l'égalité.
Solution:
Essayez donc de définir SelectedIndex en utilisant SelectedValue via Converter, comme ceci:
code C #
//Converter
public class SelectedToIndexConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null && value is YourType)
{
YourType YourSelectedValue = (YourType) value;
YourSelectedValue = (YourType) cmbDowntimeDictionary.Tag;
YourType a = (from dd in Helper.YourType
where dd.YourTypePrimaryKey == YourSelectedValue.YourTypePrimaryKey
select dd).First();
int index = YourTypeCollection.IndexOf(a); //YourTypeCollection - Same as ItemsSource of ComboBox
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value!=null && value is int)
{
return YourTypeCollection[(int) value];
}
return null;
}
}
Xaml
<ComboBox
ItemsSource="{Binding Source={StaticResource YourDataProvider}}"
SelectedIndex="{Binding Path=YourValue, Mode=TwoWay, Converter={StaticResource SelectedToIndexConverter}, UpdateSourceTrigger=PropertyChanged}"/>
Bonne chance! :)
Le type de SelectedValuePath
et de SelectedValue
doit être EXACTEMENT le même.
Si, par exemple, le type de SelectedValuePath
est Int16
et que le type de la propriété liée à SelectedValue
est int
cela ne fonctionnera pas.
Je passe des heures à trouver cela, et c'est pourquoi je réponds ici après tant de temps que la question a été posée. Peut-être qu’un autre pauvre type avec le même problème, comme moi, peut le voir.
Je suis tombé sur quelque chose de similaire, enfin je viens de m'abonner à l'événement SelectionChanged pour le menu déroulant et de définir ma propriété de données avec celui-ci. Silly et souhaite que ce n'était pas nécessaire, mais cela a fonctionné.
Est-il raisonnable de définir SelectedValuePath = " Content " dans le XAML de la liste déroulante, puis utilisez SelectedValue comme liaison?
Il semble que vous disposiez d'une liste de chaînes et que vous souhaitiez que la liaison ne fasse que faire correspondre les chaînes au contenu réel de l'élément dans la liste déroulante. Par conséquent, si vous lui indiquez la propriété à utiliser pour SelectedValue, elle devrait fonctionner; au moins, cela a fonctionné pour moi quand j'ai rencontré ce problème.
Il semble que Content serait un paramètre par défaut raisonnable pour SelectedValue, mais ce n’est peut-être pas le cas?
Avez-vous essayé de générer un événement signalant que SelectName a été mis à jour, par exemple, OnPropertyChanged (" SelectedName ")? Cela a fonctionné pour moi.
Dans mon cas, j'étais lié à une liste alors que je devrais être lié à une chaîne.
Ce que je faisais:
private ObservableCollection<string> _SelectedPartyType;
public ObservableCollection<string> SelectedPartyType { get { return
_SelectedPartyType; } set {
_SelectedPartyType = value; OnPropertyChanged("SelectedPartyType"); } }
À quoi devrait ressembler
private string _SelectedPartyType;
public string SelectedPartyType { get { return _SelectedPartyType; } set {
_SelectedPartyType = value; OnPropertyChanged("SelectedPartyType"); } }
Le mode de liaison doit être OneWayToSource ou TwoWay car la source correspond à ce que vous souhaitez mettre à jour. Mode OneWay est source à cible et crée donc la source en lecture seule, ce qui empêche la mise à jour de la source.
Vous savez ... Je me bats avec ce problème depuis des heures et vous savez ce que j'ai découvert? C'était un problème de DataType! La liste qui remplissait la ComboBox était Int64 et j'essayais de stocker la valeur dans un champ Int32! Aucune erreur n'a été commise, cela ne stockait pas les valeurs!
Vient de résoudre ce problème. Hein !!! Soit utiliser [l'un des ...] .SelectedValue | .SelectedItem | .SelectedText Conseil: La valeur sélectionnée est préférable pour ComboStyle.DropDownList alors que .SelectedText est pour ComboStyle.DropDown.
- Cela devrait résoudre votre problème. m'a pris plus d'une semaine pour résoudre cette petite fyn. hah !!