11

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:

Combobox with country names

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....

4

1 回答 1

11

只需引用上述问题的更新并将其放入实际答案中即可。

魔鬼在 SelectedItem="{Binding Path=XmlCountry, Mode=TwoWay}" 设置中。

当我将 Selected item 绑定更改为:

SelectedItem="{Binding XmlCountry, **UpdateSourceTrigger=PropertyChanged**}"

...一切正常。

于 2014-02-14T11:33:51.720 回答