2011-10-10 10 views
10

Ho una pagina in un'app di Windows Phone 7 in cui l'utente può modificare o eliminare un oggetto Transaction. L'oggetto Transaction è una classe Linq-to-Sql che ha una relazione con la classe Account e la classe Category. Nella pagina, io uso un ListPicker per consentire all'utente di selezionare l'account e la categoria per la transazione dato, in questo modo:Errore ListPicker SelectedItem deve sempre essere impostato su un valore valido

<toolkit:ListPicker Grid.Row="1" FullModeHeader="Choose the Account" FullModeItemTemplate="{StaticResource FullModeItemTemplate}" ExpansionMode="FullScreenOnly" Background="#26000000" Margin="10,0,10,0" Name="Account" SelectedItem="{Binding Account, Mode=TwoWay}" Tap="ListPicker_Tap" /> 

<toolkit:ListPicker Grid.Row="7" FullModeHeader="Choose the Category" FullModeItemTemplate="{StaticResource FullModeItemTemplate}" ExpansionMode="FullScreenOnly" Background="#26000000" Margin="10,0,10,0" Name="Category" SelectedItem="{Binding Category, Mode=TwoWay}" Tap="ListPicker_Tap" /> 

L'evento ListPicker_Tap è una correzione per un bug nella versione Ago/2011 del WPF Toolkit per Windows Phone ed è semplicemente questo:

private void ListPicker_Tap(object sender, System.Windows.Input.GestureEventArgs e) 
    { 
     ListPicker lp = (ListPicker)sender; 
     lp.Open(); 
    } 

Se all'utente di modificare la transazione, tutto va bene, ma se l'utente tenta di eliminarlo, ottengo un errore che dice che "SelectedItem deve sempre essere impostato su un valore valido ".

Ecco il codice se l'utente clicca il pulsante di eliminazione nella appbar nelle TransactionPage.xaml.cs:

private void appBarDelete_Click(object sender, EventArgs e) 
    { 
     MessageBoxResult result = MessageBox.Show("Are you sure?\n", "Confirm", MessageBoxButton.OKCancel); 

     if (result == MessageBoxResult.OK) 
     { 
      App.ViewModel.DeleteTransaction(transaction); 
     } 

     NavigationService.GoBack(); 
    } 

mio metodo ViewModel.DeleteTransaction:

public void DeleteTransaction(Transaction transaction) 
    { 
     AllTransactions.Remove(transaction); 
     transactionRepository.Delete(transaction); 
    } 

mio transactionRepository.Delete metodo:

public void Delete(Transaction transaction) 
    { 
     Context.Transactions.DeleteOnSubmit(transaction); 
     Context.SubmitChanges(); 
    } 

Ho ricevuto l'errore nel Context.SubmitChanges() L'esecuzione, i punti di debug al NotifyPropertyChanged all'interno della classe Transaction, la linea dove ottengo l'errore è questo:

protected virtual void SendPropertyChanged(String propertyName) 
    { 
     if ((this.PropertyChanged != null)) 
     { 
      this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 

Nel propertyName attribuiscono il valore è "Categoria". Sembra che quando si elimina l'oggetto invii l'evento propertychanged di categoria e account, e poiché il listpicker è in modalità TwoWay, ha qualche problema nel gestirlo. Come posso ripararlo? Ho bisogno di aiuto.

+0

è possibile collegare il pieno XAML? O se è troppo lungo, XAML parziale andrà bene finché si vedrà che cosa {{Binding Account, Mode = TwoWay} 'e' {Binding Category, Mode = TwoWay} 'si riferiscono. – Amry

risposta

1

Il Problema è che si aspetta la ListPicker il SelectedItem essere una ListPickerItem mentre si sta legandola a un oggetto di tipo Transaction. È possibile aggirare il problema associando invece la proprietà SelectedIndex e quindi selezionare l'oggetto appropriato dal ViewModel in base all'indice.

Inoltre, se il motivo avete il gestore Tap definito è a causa del bug in cui il ListPicker non si apre quando collocato all'interno di un ScrollViewer, dare un'occhiata a patch ID 10247. Se ricompilate il toolkit con quella patch, risolve il problema.

+0

'ListPicker.SelectedItem' può anche essere associato all'oggetto dati, non solo a' ListPickerItem'. – Amry

+0

@Amry Hai provato a farlo? Ho avuto lo stesso identico problema e ho dovuto lavorare con 'SelectedIndex' – Praetorian

+0

Se' ListPicker' è un database, quindi l'uso di un oggetto dati con 'SelectedItem' dovrebbe funzionare correttamente. Forse puoi aprire una nuova domanda per il tuo caso. :) – Amry

2

Ci sono solo due i controlli che getta l'InvalidOperationException su SelectedItem

  1. Listpicker elementi è nullo (dichiarativa:. Ordine degli attributi questioni se SelectedItem deve comparire dopo ItemSource (programmatico: assicurarsi ItemSource viene caricato)
  2. Listpicker applica indexOf su Articoli per impostare elemento selezionato. Quindi assicuratevi di sovrascrivere equals, se necessario.

Debug con la vigilanza su l istpicker.Articoli e ignorato Equals metodo ci aiuterà a identificare problema

+0

Nota anche: se si esegue il binding a una proprietà secondaria, è necessario inizializzarla, altrimenti si verificherà lo stesso errore (poiché la prima proprietà è null). – kamranicus

12

Questo errore può anche essere causato da l'ordine delle proprietà XAML:

questo non funziona (genera l'eccezione, perché l'ItemsSource è nullo quando il SelectedItem è impostato):

<toolkit:ListPicker DisplayMemberPath="Title" SelectionMode="Single" 
SelectedItem="{Binding SelectedCategory, Mode=TwoWay}" 
ItemsSource="{Binding Categories}" /> 

Questo funziona come l'ItemsSource viene inizializzata prima:

<toolkit:ListPicker DisplayMemberPath="Title" SelectionMode="Single" 
ItemsSource="{Binding Categories}" 
SelectedItem="{Binding SelectedCategory, Mode=TwoWay}" /> 
+1

Sì, questo è chiaramente un bug nel controllo .NET in quanto dovrebbe gestire tali scenari senza arresti anomali ... (progettare i propri controlli con questo problema in mente :) –

+0

Questa soluzione ha fatto per me. –

3

ListPicker Items.IndexOf utilizza per ottenere l'i ndex dell'istanza dell'oggetto che dovrebbe selezionare.

Se l'istanza non corrisponde (non è un'istanza di oggetto dalla raccolta) IndexOf restituirà -1 e l'InvalidOperationException viene generata con il messaggio: "SelectedItem deve sempre essere impostato su un valore valido".

Sovrascrivi Metodo uguale al tipo di elemento nella raccolta e funzionerà come previsto.

Esempio:

public override bool Equals(object obj) 
{ 
     var target = obj as ThisType; 
     if (target == null) 
      return false; 

     if (this.ID == target.ID) 
      return true; 

     return false; 
} 

Speranza che aiuta

Problemi correlati