2009-12-15 14 views
5

Ho visto questa domanda posta numerose volte e ho ripassato il mio codice più e più volte. Ma quando assegno alla mia proprietà SelectedItem -bound con un oggetto, esso non aggiorna l'elemento selezionato dello schermo. Sembra che il ListBox pensi che l'oggetto che assegno non sia un membro dei suoi articoli.ListBox TwoWay bind to SelectedItem

public class MainViewModel : ViewModelBase 
{ 
    //... 
    public SortedObservableCollection<TubeViewModel> Items { get; private set; } 
    public TubeViewModel SelectedTube { //get, set, propertychanged, etc. } 
} 

<ListBox x:Name="TubeList" 
     Margin="10" 
     ItemsSource="{Binding Items}" 
     ItemTemplate="{StaticResource TubeTemplate}" 
     SelectedItem="{Binding SelectedTube, Mode=TwoWay}" 
     SelectionMode="Single" 
     VirtualizingStackPanel.IsVirtualizing="False"> 
</ListBox> 

Ecco l'impl da uno dei luoghi in cui cerco di impostare SelectedTube - sicuramente si verifica sul thread principale.

var match = 
    from t in Items 
    where t.Model.DataFileName == filename 
    select t; 
if (match.Any()) 
    SelectedTube = match.First(); 

stavo notando che il SelectedTube non è mai stato messo in evidenza a meno che non ho cliccato manualmente su di esso, ma tipo di ignorato. Ma poi ho voluto ScrollIntoViewCentered l'elemento selezionato, quindi ho aggiunto un DependencyProperty a mio avviso per vedere le modifiche di SelectedItem. Il gestore inizialmente sembrava così:

private void OnSelectedItemChanged(DependencyObject target, DependencyPropertyChangedEventArgs e) 
{ 
    if (TubeList.SelectedItem == null) 
     return; 

    TubeList.ScrollIntoViewCentered(TubeList.SelectedItem); 
} 

Ma non ha funzionato se ho impostato il SelectedItem attraverso il mio legame. Dopo aver deciso che volevo scorrere solo se non fosse sullo schermo, ho cambiato il codice a questo:

private void OnSelectedItemChanged(DependencyObject target, DependencyPropertyChangedEventArgs e) 
{ 
    if (TubeList.SelectedItem == null) 
     return; 

    var container = TubeList.ItemContainerGenerator.ContainerFromItem(TubeList.SelectedItem) as FrameworkElement; 

    if(!container.IsVisible) 
     TubeList.ScrollIntoViewCentered(TubeList.SelectedItem); 
} 

Se SelectedItem è impostato esternamente, il contenitore è nullo. Ogni volta. Ho anche aggiunto il codice per verificare la presenza di null e quindi scorrere lo ItemsSource alla ricerca di una corrispondenza di nome file, quindi aggiornare SelectedItem per assicurarmi che SelectedItem fosse sicuramente un oggetto nella casella di riepilogo. Senza fortuna.

Non è una visibilità, se l'elemento è sullo schermo, non viene evidenziato. Devo implementare una sorta di funzione di uguaglianza? Ho perso più tempo di quanto si possa pensare possibile su questo.

grazie.

+0

Non sono riuscito a riprodurre ciò con quello che vediamo del codice. Ho creato una classe fittizia per TubeViewModel e ho utilizzato tutto il codice pubblicato e ha funzionato come previsto. Qualcosa deve succedere altrove. –

+0

Grazie mille, Ben e Kent. Sono in vacanza per un po ', questo dovrà aspettare. – Thomas

risposta

5

Forse questo è anche legato al fatto che ItemContainerGenerators sono generati in un thread separato ... (at least in the TreeView)

Prova a chiamare UpdateLayout() prima di chiedere la proprietà ItemContainerGenerators.

+0

Non capisco perché sia ​​necessario, ma sono felice che lo sia. Grazie mille. – Thomas

3

Niente mi salta come se fosse ovviamente sbagliato, ma hai sorvolato molto. Posso solo suggerirti di semplificare le cose finché non trovi il problema o hai un esempio completo non funzionante che puoi pubblicare.

1

Hai provato a verificare l'hashcode di ogni oggetto nell'origine elementi rispetto all'hashcode dell'oggetto che stai tentando di impostare? La query di Linq restituirà qualcosa di diverso.

Come test durante il tentativo di impostazione di SelectedTube su Articoli [0].