I have struggled to save my combobox selected value when operating inside a datagrid. When I make a test solution with no datagrid things are working ok. The context are person names with associated countries. The countries are stored in a xml file. Here is a snapshot of the initial view:
You see here the (important parts of the)PersonList.xaml:
<UserControl.Resources>
<XmlDataProvider x:Key="Dataxml" Source="\Properties\AllCountries.xml" />
<model:Person x:Key="Person"/>
</UserControl.Resources>
<UserControl.DataContext>
<viewModel:PersonListViewModel />
</UserControl.DataContext>
<DataGrid ItemsSource="{Binding Persons}" AutoGenerateColumns="False" IsReadOnly="False" CanUserAddRows="False" SelectionUnit="FullRow" SelectedItem="{Binding SelectedPerson}" >
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" CanUserSort="true" ></DataGridTextColumn>
<DataGridTemplateColumn Header="Country">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox
Width="150"
SelectedValuePath="country"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding Source={StaticResource Dataxml}, XPath=/countries/country}"
SelectedIndex="{Binding CountryIndex}"
SelectedItem="{Binding Path=XmlCountry, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}, {1}">
<Binding XPath="name" />
<Binding XPath="iso" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
This grid is populated from a PersonListViewModel, that has a private ObservableCollection<Person> _persons
attribute that implements INotifyPropertyChanged and is the ItemsSource for the grid. You also see the SelectedItem="{Binding SelectedPerson}"
in the grid. That part works OK.
The Person model class has CountryIndex (string, index in the xml-file, computed), Country (string, the country name) and now i implemented the XmlCountry attribute (XmlElement, the xmlnode in the xml-file. The xml file looks like this:
?xml version="1.0" encoding="utf-8"?>
<countries>
<country>
<iso>AF</iso>
<name>Afghanistan</name>
</country>
<country>
<iso>AL</iso>
<name>Albania</name>
</country>
<country>
<iso>DZ</iso>
<name>Algeria</name>
</country>
<country>
<iso>AS</iso>
<name>American Samoa</name>
</country>
<country>
<iso>AD</iso>
<name>Andorra</name>
</country>
etc, etc, ....
When I load the persons in the ViewModel constructor the person's country name is used to compute the country index that is used to set the initial values as you see in the screen shot. I achieved this by using the SelectedIndex="{Binding CountryIndex}"
in the xaml above.
And then the problem started; I cannot get the selection of countries in the combobox to call anything on the Person
model OR the PersonListViewModel
. I have tried almost anything ... :P
It is obvious that the key to the solution is this binding in the combobox:
SelectedItem="{Binding Path=XmlCountry, Mode=TwoWay}"
The property 'XmlCountry' here resides in the Person
model. I have tried to put it in the PersonListViewModel
with no luck. The "Save Person" button works ok - it takes the "SelectedPerson" bound property and sends to the database. Except that it does not get the updated combobox value.
I would apperciate any help on the SelectedItem/SelectedIndex
binding in the combobox. And also other suggestions: Do I need a PersonViewModel
to wrap the Person
model class maybe? Should I make a "AllCountries" attribute on my PersonListViewModel
from the xml-file and use that instead of the xml-file directly?
UPDATE:
As I suspected: The devil was in the SelectedItem="{Binding Path=XmlCountry, Mode=TwoWay}"
setting.
When I changed to:
SelectedItem="{Binding XmlCountry, **UpdateSourceTrigger=PropertyChanged**}"
Everything works fine. I am now passing the right data to my "Save Person" method. However it's the first time I have had to set UpdateSourceTrigger
to keep the view and viewmodel in synch....