2013-07-25 17 views
6

Sto usando un ComboBox nella mia applicazione WPF e seguendo MVVM. C'è una lista di stringhe che voglio mostrare nel mio ComboBox.Ripristina combobox elemento selezionato sul set usando MVVM

XAML:

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

Vista Modello:

public Collection<string> ItemsCollection; // Suppose this has 10 values. 
private string _selectedItem; 
public string SelectedItem 
{ 
    get { return _selectedItem; } 
    set 
    { 
     _selectedItem = value; 
     Trigger Notify of property changed. 
    } 
} 

Ora questo codice sta lavorando assolutamente bene. Sono in grado di selezionare dalla vista e posso ottenere modifiche in ViewModel e se cambio SelectedItem dal mio ViewModel posso vederlo nella mia vista.

Ora ecco quello che sto cercando di ottenere. Quando cambio la voce selezionata dalla mia vista, devo mettere un controllo sul fatto che il valore sia buono/cattivo (o qualsiasi altra cosa) imposta la voce selezionata altrimenti non la imposta. Quindi il mio modello di vista cambia in questo modo.

public string SelectedItem 
{ 
    get { return _selectedItem; } 
    set 
    { 
     if (SomeCondition(value)) 
      _selectedItem = value;   // Update selected item. 
     else 
      _selectedItem = _selectedItem; // Do not update selected item. 
     Trigger Notify of property changed. 
    } 
} 

Ora, quando eseguo questo codice e SomeCondition (valore) restituisce false, SelectedItem restituisce vecchio valore stringa, ma a mio avviso elemento selezionato nella ComboBox è il valore che ho selezionato. Quindi supponiamo di avere una collezione di 10 stringhe mostrate nel mio ComboBox. Tutti i valori sono validi tranne il secondo e il quarto elemento (SomeCondition restituisce false per il 2 ° e il 4 ° valore). Quello che voglio è che se seleziono il secondo o il quarto elemento selezionato, l'elemento non cambia. Ma il mio codice non lo fa correttamente. Se seleziono il secondo elemento, la visualizzazione mostra ancora il secondo elemento come selezionato. So che c'è qualcosa di sbagliato nel mio codice. Ma cos'è?

+1

Questo non è un design molto intuitivo. Se seleziono qualcosa in una casella combinata, mi aspetto che sia il mio elemento selezionato. Devi invece rimuovere le opzioni non valide dalla casella combinata. Se una validità delle selezioni è basata su un valore selezionato di un altro elemento dell'interfaccia utente, la modifica di tale selezione dovrebbe attivare la ricostruzione di ItemSource della casella combinata. –

+1

Questo è il requisito per mostrare tutti gli elementi, non è possibile cambiarlo. –

+1

Accetto che non mostri opzioni non valide o che non li visualizzi in grigio e ne disabiliti la selezione, ovvero a cosa serve un'interfaccia utente. –

risposta

14

Questa è una domanda molto interessante. Innanzitutto sono d'accordo con altri ragazzi sul fatto che questo è un approccio non raccomandato per gestire una selezione non valida. Come suggerisce @blindmeis, IDataErrorInfo è uno dei buoni modi per risolverlo.

Torna alla domanda stessa. Una soluzione che soddisfa ciò @Faisal Hafeez vuole è:

public string SelectedItem 
{ 
    get { return _selectedItem; } 
    set 
    { 
     var oldItem=_selectedItem; 
     _selectedItem=value; 
     OnPropertyChanged("SelectedItem") 

     if (!SomeCondition(value)) //If does not satisfy condition, set item back to old item 
      Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => SelectedItem = oldItem), 
               DispatcherPriority.ApplicationIdle); 
    } 
} 

Dispatcher è un modo elegante per gestire alcuni sincronizzazione UI durante un'altra sincronizzazione UI. Ad esempio, in questo caso, si desidera ripristinare la selezione durante il binding di selezione.

Una domanda qui è perché dobbiamo aggiornare la selezione comunque all'inizio. Questo perché SelectedItem e SelectedValue sono assegnati separatamente e ciò che viene visualizzato su ComboBox non dipende da SelectedItem (forse SelectedValue, non sono sicuro). E un altro punto interessante è se ChangeValue cambia, SelectedItem deve cambiare ma SelectedItem non aggiorna SelectedValue quando cambia. Pertanto, è possibile scegliere di associare a SelectedValue in modo da non dover assegnare prima.

+0

Ha funzionato, grazie per questo. –

+0

Abbiamo avuto esattamente lo stesso problema e la tua soluzione funziona. Vogliamo anche mostrare tutti gli articoli anche se non è possibile selezionarne uno. E non vogliamo disabilitare il controllo perché è solo un breve periodo di tempo che non è possibile selezionare un altro elemento. C'è un modo per scrivere un comportamento che assicuri che un elemento dell'interfaccia utente selettore mostri sempre il giusto valore di proprietà? – Lumo

3

provare a cambiare il codice XAML per questo

<ComboBox ItemsSource="{Binding ItemsCollection}" SelectedItem="{Binding SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> 
+0

"Mode = TwoWay" è necessario? Ho provato a impostare il valore predefinito nel mio costruttore del modello di vista, che funzionava perfettamente. Ma fallire nel settarlo dentro setter. –

+0

@FaisalHafeez si, perché stai cambiando proprietà in View e ViewModel pure –

Problemi correlati