2015-01-28 7 views
6

Während ich an einer Universal App arbeite (derzeit nur auf der WP8.1-Seite), bin ich auf die folgende seltsame Sache gestoßen.Universal App - Loading Combobox 'ItemsSource Async gibt seltsames Verhalten

Ich habe eine ComboBox, das UserControl (befindet sich im WindowsPhone-Projekt) es ist an eine VM im Shared-Projekt gebunden. Sowohl ItemsSource als auch SelectedItem sind mit ihren jeweiligen Eigenschaften in der VM verknüpft.

Wenn Sie die Anwendung ausführen, wenn Sie ein Element außer dem ersten auswählen, funktioniert es perfekt. Aber, wenn ich das erste Element auszuwählen, die angezeigte Zeichenfolge in der ComboBox zeigt die .ToString() -Methode der VM statt ...

(BTW, es ist eine einfache List<string>, das ausgewählte Element ist ein string. Es kann nicht viel einfacher als das: p)

Ich habe eine Beispiel-App erstellt, die nur diese Combobox und die VM enthält. Ich konnte dies reproduzieren, in dem Moment, in dem ich Eigenschaften, die mit ItemsSource verknüpft sind, asynchron ausfülle. Wenn es von einer synchronen Methode aus geschieht, funktioniert es. Aber nur das Füllen von einer asynchronen Methode liefert das obige Problem.

Einige Screenshots:

Die erste zeigt die App, wenn es geladen wird. Wenn sich die Sammlung ändert, wird das erste Element der Liste ausgewählt. Es wird hier gezeigt:

After is app loaded

Wenn Sie auf die ComboBox klicken Sie seine Elemente wie gewohnt zu sehen bekommen: enter image description here

Sagen Sie bitte nicht die erste auf ein beliebiges Element klicken, erhalten Sie noch normales Verhalten: enter image description here

So weit, so normal. Klicken Sie nun auf den ersten Eintrag. Sie erhalten diese: enter image description here

...

ich eine Vielzahl von Dingen versucht haben, wie es eine Liste eines Objekts statt nur Strings zu machen. Das Hinzufügen eines Konverters zu den verknüpften Objekten, nur zu Debugging-Zwecken, ergibt nur die tatsächlichen String-Werte. Ich habe keine Ahnung, wie, noch warum die binded SelectedItem zeigt plötzlich die Datacontext des ComboBox ...

Sie die Beispiel-App hier herunterladen können: http://1drv.ms/1DhklCQ (enthält keine Binärdateien, nur der Code)

Hat jemand irgendwelche Ideen?


EDIT: Der Code benötigt, um dieses Problem zu reproduzieren:

Erstellen Sie eine leere Universal-Store App (8.1). Im WindowsPhone-Projekt, die Datei MainPage.xaml: Ich habe eine einfache Combobox hinzugefügt, und fangen Sie das Loaded-Ereignis.

<ComboBox ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" /> 

In seinem Code hinter. Ich habe den DataContext der VM zugewiesen. Und im Loaded-Event rufe ich asynchron die VM an.Loaddata()

private VM _vm = new VM(); 
public MainPage() 
{ 
    this.InitializeComponent(); 
    this.DataContext = _vm; 
} 

private async void Page_Loaded(object sender, RoutedEventArgs e) 
{ 
    await _vm.LoadDataAsync(); 
} 

Das VM-Objekt definiert ist wie folgt:

public class VM : INotifyPropertyChanged 
{ 
    private List<string> _items; 
    public List<string> Items 
    { 
     get { return _items; } 
     set 
     { 
      _items = value; 
      _selectedItem = _items.FirstOrDefault(); 
      RaisePropertyChanged("Items"); 
      RaisePropertyChanged("SelectedItem"); 
     } 
    } 

    private string _selectedItem; 
    public string SelectedItem 
    { 
     get { return _selectedItem; } 
     set 
     { 
      _selectedItem = value; 
      RaisePropertyChanged("SelectedItem"); 
     } 
    } 

    public VM() 
    { 
    } 

    public async Task LoadDataAsync() 
    { 
     this.Items = new List<string>() 
     { 
      "a", 
      "b", 
      "c", 
      "d", 
      "e", 
      "f", 
     }; 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
    private void RaisePropertyChanged(string propName) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propName)); 
     } 
    } 
} 
+0

Warum postest du den Code hier nicht? – Sajeetharan

+0

Ich habe den Code zum ursprünglichen Post hinzugefügt. –

+0

Für was es wert ist, haben wir auch das gleiche Problem in unserer Anwendung, die viele asynchrone Muster verwendet. Unsere Schlussfolgerung ist, dass es ein Fehler mit der ComboBox ist. –

Antwort

1

Nicht asynchron nur - wenn Sie setzen _vm.Items = new List... in OnLoaded Ereignis statt await _vm.LoadDataAsync(); - Sie werden das gleiche Problem bekommen.

Scheint, dass das Problem nicht auftritt, sobald Sie Ihre Elemente vor dem Festlegen des DataContext festlegen.

Die andere Sache ist, dass das Problem nicht angezeigt (wie ich versucht habe), wenn Sie nicht festlegen aus dem Code Ausgewählte Artikel:

public ObservableCollection<string> Items 
{ 
    get { return _items; } 
    set 
    { 
     _items = value; 
    // _selectedItem = _items.FirstOrDefault(); 
     RaisePropertyChanged("Items"); 
    // RaisePropertyChanged("SelectedItem"); 
    } 
} 

Was jetzt habe ich keine Ahnung, warum diese das passiert.

+0

Ja, wenn ich das ausgewählte Element nicht einstellen, funktioniert es ... Sehr seltsam. Vielleicht sollte ich meinen Anwendungsfall ändern, damit ich nicht wirklich einen Standardartikel auswählen muss. –

+0

@TomWuyts Es scheint sich um einen Fehler zu handeln, daher müssen Sie eine Problemumgehung verwenden. – Romasz

2

Ich habe es überprüft und ich kann kein Problem mit Ihrem Code sehen, also denke ich, es ist ein Fehler in der ComboBox.

Das Verstehen des Problems und das Finden eines echten Fixes kann einige Zeit in Anspruch nehmen, daher würde ich vorschlagen, dass Sie eine Workaround verwenden, die für Sie funktioniert. Ich habe versucht, die folgenden und es schien zu funktionieren:

  1. Ändern Sie die Eigenschaft Items in der VM sein vom Typ ObservableCollection<string>
  2. die Eigenschaft/Feld im Konstruktor auf eine leere Sammlung VM initialisieren.
  3. Wenn Sie die Elemente laden, füllen Sie einfach die Sammlung (fügen Sie Elemente mit der Methode Add() hinzu), anstatt sie zu ersetzen.

Bearbeiten: Beispiel, wie ich es getestet fülle.

public class VM : INotifyPropertyChanged 
{ 
    private ObservableCollection<string> _items; 
    public ObservableCollection<string> Items 
    { 
     get { return _items; } 
     set 
     { 
      _items = value; 
      _selectedItem = _items.FirstOrDefault(); 
      RaisePropertyChanged("Items"); 
      RaisePropertyChanged("SelectedItem"); 
     } 
    } 

    private string _selectedItem; 
    public string SelectedItem 
    { 
     get { return _selectedItem; } 
     set 
     { 
      _selectedItem = value; 
      RaisePropertyChanged("SelectedItem"); 
     } 
    } 


    public VM() 
    { 
     this._items = new ObservableCollection<string>(); 
    } 

    public async Task LoadDataAsync() 
    { 
     var items = new List<string>() { 
      "1", 
      "b", 
      "c", 
      "d", 
      "e", 
      "f", 
      "f", 
      "f", 
      "f", 
      "f", 
      "f", 
     }; 

     foreach (var i in items) { 
      this._items.Add(i); 
     } 
     this.SelectedItem = items.FirstOrDefault(); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
    private void RaisePropertyChanged(string propName) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propName)); 
     } 
    } 
} 

Das funktioniert gut für mich.

+0

Danke für den Vorschlag, ich werde es heute Abend ausprobieren. –

+0

Ich habe das versucht, aber wenn ich die Sammlung mit 'Add()' füllen, setze ich das SelectedItem auf das erste Element. Und dann erscheint der Fehler, wenn ich ihn auswähle. –

+0

@TomWuyts Ich habe meine Antwort geändert und den Code hinzugefügt, mit dem ich sie getestet habe. Das SelectedItem funktioniert in diesem Fall (zumindest für mich). – yasen

7

Eine Problemumgehung gefunden, weil vorherige Lösungen mein Problem nicht gelöst haben.

Fügen Sie einfach eine Pause zwischen der Bindung und dem Auswählen eines Elements oder Indexes Ihrer Combobox hinzu.

-Code unten:

myCombobox.ItemsSource = myList; 
await Task.Delay(100); 
myCombobox.SelectedIndex = 12; 

hoffe, das hilft!

+0

Hatte Fehler bei der Datenbindung. Dies löste meinen Bug der verbindenden Elementquelle. Danke –

+0

Nur mögliche Lösung, itemsource Bindung oder ausgewählte Element Manipulation auf andere Weise führt zu diesem unglaublichen Fehler, so schlecht QA. Dies geschieht übrigens auch bei der Auswahl eines Combobox-Vollbilds, aber das Ergebnis ist ein leeres ausgewähltes Element, das Combobox nicht richtig binden kann – Keoz