2010-08-25 14 views
10

Utilizzo l'eccellente MVVM Light Toolkit. Il mio ViewModel espone:Utilizzo di WPF DataGridComboBoxColumn con MVVM - Collegamento alla proprietà in ViewModel

public const string CourtCodesTypeCourtPropertyName = "CourtCodesTypeCourt"; 
private List<CourtType> _courtCodesTypes = new List<CourtType>(); 
public List<CourtType> CourtCodesTypeCourt 
{ 
    get 
    { 
     return _courtCodesTypes; 
    } 

    set 
    { 
     if (_courtCodesTypes == value) 
     { 
      return; 
     } 

     var oldValue = _courtCodesTypes; 
     _courtCodesTypes = value; 

     // Update bindings and broadcast change using GalaSoft.MvvmLight.Messenging 
     RaisePropertyChanged(CourtCodesTypeCourtPropertyName, oldValue, value, true); 
    } 
} 

public const string CourtCodesPropertyName = "CourtCodes"; 
private List<Court> _courtCodes = null; 
public List<Court> CourtCodes 
{ 
    get 
    { 
     return _courtCodes; 
    } 

    set 
    { 
     if (_courtCodes == value) 
     { 
      return; 
     } 

     var oldValue = _courtCodes; 
     _courtCodes = value; 

     // Update bindings and broadcast change using GalaSoft.Utility.Messenging 
     RaisePropertyChanged(CourtCodesPropertyName, oldValue, value, true); 
    } 
} 

The View ha un DataGrid:

<DataGrid 
     ItemsSource="{Binding CourtCodes, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
     AutoGenerateColumns="False" 
     AlternatingRowBackground="{DynamicResource OffsetBrown}" 
     AlternationCount="1" Margin="45,0"> 
    <DataGrid.Columns> 
    <DataGridTextColumn Binding="{Binding Abbreviation, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
     Header="Abbreviation" 
     Width="25*" /> 
    <DataGridTextColumn Binding="{Binding FullName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
     Header="Court" 
     Width="75*" /> 
    <DataGridComboBoxColumn Header="CourtType" 
     ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.CourtCodesTypeCourt} TextBinding="{Binding CourtTypeDescription}""/> 
    </DataGrid.Columns> 
    </DataGrid> 

Il DataGrid ha un'ItemsSource, come si può vedere, di CourtCodes. Voglio che la colonna CourtType sia un elenco a discesa di tutti i CourtType enumerati contenuti in CourtCodesTypeCourt. Per la vita di me, non riesco a popolare il DataGridComboBoxColumn con qualcosa. L'attuale tentativo fallito sta cercando di usare RelativeSource ... cosa sto facendo male?

Oltre a non lavorare, i due errori che vedo sono:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Window', AncestorLevel='1''. BindingExpression:Path=DataContext.CourtCodesTypeCourt; DataItem=null; target element is 'DataGridComboBoxColumn' (HashCode=38771709); target property is 'ItemsSource' (type 'IEnumerable')

e

System.Windows.Data Error: 40 : BindingExpression path error: 'CourtCodesTypeCourt' property not found on 'object' ''Court' (HashCode=38141773)'. BindingExpression:Path=CourtCodesTypeCourt.CourtTypeDescription; DataItem='Court' (HashCode=38141773); target element is 'ComboBox' (Name=''); target property is 'Text' (type 'String')

risposta

28

DataGrid definizioni delle colonne non partecipano nella struttura logica nel modo che ci si aspetterebbe. È ridicolo, ma ultima volta che ho controllato quello che dovete fare qualcosa di simile:

<DataGridComboBoxColumn Header="CourtType" SelectedItemBinding="{Binding Type}"> 
    <DataGridComboBoxColumn.ElementStyle> 
     <Style TargetType="ComboBox"> 
      <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.CourtCodesTypeCourt}"/> 
      <Setter Property="IsReadOnly" Value="True"/> 
     </Style> 
    </DataGridComboBoxColumn.ElementStyle> 
    <DataGridComboBoxColumn.EditingElementStyle> 
     <Style TargetType="ComboBox"> 
      <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.CourtCodesTypeCourt}"/> 
     </Style> 
    </DataGridComboBoxColumn.EditingElementStyle> 
</DataGridComboBoxColumn> 

Noterete che ho anche cambiato il tuo TextBinding ad un SelectedItemBinding. Non sono sicuro che tu intenda effettivamente un TextBinding, ma se vuoi semplicemente consentire all'utente di selezionare l'elenco, allora è probabile che lo SelectedItemBinding sia quello che desideri.

Inoltre, le macchine virtuali non seguono esattamente le migliori pratiche. Stai utilizzando List<T> anziché ObservableCollection<T> e lo stai esponendo come List<T> piuttosto che come qualcosa di più semplice come ICollection<T>.

+0

Grazie per il tuo aiuto, Kent ... questo sicuramente mi avvicina. Sono d'accordo ... è ridicolo dover ricorrere a questo tipo di sintassi. Faccio fatica. Ora ho gli oggetti CourtType che popolano DataGridComboBoxColumn, ma all'interno di questa sintassi, come controllo il testo visualizzato? Attualmente elenca il nome del tipo, non la proprietà CourtTypeDescription. In secondo luogo, apprezzo il tuo feedback sulle migliori pratiche ...Forse, erroneamente, ho avuto l'impressione che MVVM Light Toolkit abbia realizzato le proprietà create da mvvminpc con snippet in ObservableCollections ... anche io me ne vado? –

+0

Ignora la domanda sulle best practice ObservableCollections ... L'ho testata un po 'e ne ho visto il valore. La possibilità di collegarsi all'evento CollectionChanged sembra valsa la pena. Potrei usare un po 'sulla sintassi per DataGridComboBoxColumn ... grazie ancora per il tuo aiuto! –

+0

@Mike: dovresti essere in grado di impostare 'DisplayMemberPath =" CourtTypeDescription "' sul tuo 'DataGridComboBoxColumn'. –

2

Qui ho trovato risposta http://cinch.codeplex.com/discussions/239522

Per il DataGridComboBoxColumn è necessario creare uno StaticRecource del ItemsSource come:

<CollectionViewSource Source="{Binding Element=theView, Path=DataContext.ViewModelCollection1}" x:Key="ViewModelCollection1" /> 

e associarlo al DataGridComboBoxColumn con le seguenti:

ItemsSource="{Binding Source={StaticResource ViewModelCollection1}}" 

Ecco perché le colonne DataGrid non fanno parte dell'albero visivo.

E se si desidera associare su una collezione di un elemento del DataGrid si devono impostare l'ItemsSource nel corso dei due stili:

<DataGridComboBoxColumn.ElementStyle> 
    <Style TargetType="ComboBox"> 
     <Setter Property="ItemsSource" Value="{Binding Path=ModelCollection1}" /> 
    </Style> </DataGridComboBoxColumn.ElementStyle> <DataGridComboBoxColumn.EditingElementStyle> 
    <Style TargetType="ComboBox"> 
     <Setter Property="ItemsSource" Value="{Binding Path=ModelCollection1}" /> 
    </Style> </DataGridComboBoxColumn.EditingElementStyle> 
Problemi correlati