I'm using the excellent MVVM Light Toolkit. My ViewModel exposes:
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 has a 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>
The DataGrid has an ItemsSource, as you can see, of CourtCodes. I want the CourtType column to be a drop down of all enumerated CourtTypes that are contained within CourtCodesTypeCourt. For the life of me, I can't seem to populate the DataGridComboBoxColumn with anything. The current failed attempt is looking to use RelativeSource... what am I doing wrong?
In addition to not working, the two errors I see are:
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')
and
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')
Here I have found answer http://cinch.codeplex.com/discussions/239522
For the DataGridComboBoxColumn you have to create a StaticRecource of the ItemsSource like:
<CollectionViewSource Source="{Binding Element=theView, Path=DataContext.ViewModelCollection1}" x:Key="ViewModelCollection1" />
and bind it to the DataGridComboBoxColumn with following:
ItemsSource="{Binding Source={StaticResource ViewModelCollection1}}"
Thats because the DataGridColumns are not a part of the visual tree.
And if you want to bind on a collection of a item of the DataGrid you have to set the ItemsSource over the two styles:
<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>
DataGrid
column definitions don't participate in the logical tree in the way you would expect. It's ridiculous, but last I checked you have to do something like this:
<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>
You'll notice I've also changed your TextBinding
to a SelectedItemBinding
. I'm not sure if you actually intended a TextBinding
, but if you just want to allow the user to select between the list, then SelectedItemBinding
is likely what you want.
Also, your VMs don't exactly follow best practices. You're using List<T>
instead of ObservableCollection<T>
, and you're exposing it as List<T>
rather than something simpler such as ICollection<T>
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With