2017-01-10 8 views
0

Я начинаю работать с WPF и MVVM. У меня все еще есть проблема с привязкой данных в случае обратной привязки. Я хотел бы привязать selectedValues ​​Comboboxes к моей Oberservable Collection. Я узнал, что можно связать значение combobox с свойством, но в этом случае я хотел бы привязываться к свойству коллекции, и коллекция является родительской.WPF MVVM Databinding Nested Datagrid

Может ли кто-нибудь объяснить мне, как привязать выделенные значения combobox к моему наблюдаемому коллекциям?

У меня есть обходное решение, чтобы сделать для каждого combobox новое свойство в моей модели viewmodel и собирать все значения и хранить по кнопке, нажимая эти значения в мою коллекцию, но это кажется мне неправильным, потому что это не поведение привязки данных.

EDIT Элементы comboboxes исправлены, заполненные из каждой модели, но как я могу привязать выбранное значение combobox к свойству коллекции?

<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, 
             AncestorType={x:Type Window}}, 
             Path=DataContext.Cities}" 
             DisplayMemberPath="Name" 
             SelectedValue="{Binding Path=RowEntries }"/> 

The SelectedValue="{Binding Path=RowEntries}" не соответствует действительности или все верно.

EDIT 2

Я добавил Listview привязываться к моей коллекции, чтобы увидеть, если свойства переплетены в SelectedValue моего выпадающего списка, но держит пустым.

<ListView ItemsSource="{Binding RowEntries}" BorderBrush="Black" BorderThickness="1"> 
      <ListView.ItemTemplate> 
       <DataTemplate> 
        <StackPanel Orientation="Horizontal"> 
         <TextBlock Text="{Binding Path=CityName}"></TextBlock> 
         <TextBlock Text="{Binding Path=CountryName}"></TextBlock> 
        </StackPanel> 
       </DataTemplate> 
      </ListView.ItemTemplate> 
     </ListView> 

У меня есть такое решение:

Solution

Мои модели:

// INPC implemented by Propertychanged.Fody 
    public class RowEntry : BaseModel 
    { 
     public string CityName { get; set; } 
     public string CountryName { get; set; } 
    } 

    // INPC implemented by Propertychanged.Fody 
    public class City : BaseModel 
    { 
     public string Name { get; set; } 
    } 
    // INPC implemented by Propertychanged.Fody 
    public class Country : BaseModel 
    { 
     public string Name { get; set; } 
    } 

Мой ViewModel:

public class TestViewModel : ViewModelBase 
{ 
    #region properties 
    // INPC implemented by Propertychanged.Fody 
    public ObservableCollection<City> Cities { get; set; } = new ObservableCollection<City>(); 
    public ObservableCollection<Country> Countries { get; set; } = new ObservableCollection<Country>(); 
    public ObservableCollection<RowEntry> RowEntries { get; set; } = new ObservableCollection<RowEntry>(); 
    #endregion 

    #region constructors and destructors 

    /// <summary> 
    /// Initializes a new instance of the MainViewModel class. 
    /// </summary> 
    public TestViewModel() 
    { 
     // Sample Data 
     var temp = new City { Name = "Rom" }; 
     Cities.Add(temp); 
     var temp2 = new City { Name = "Sydney" }; 
     Cities.Add(temp2); 

     var temp3 = new Country { Name = "Italy" }; 
     Countries.Add(temp3); 
     var temp4 = new Country { Name = "Australia" }; 
     Countries.Add(temp4); 

     RowEntries.Add(new RowEntry()); 
    } 
    #endregion 
} 

Мой Ui:

<StackPanel> 
     <DataGrid ItemsSource="{Binding RowEntries}" AlternationCount="{Binding Items.Count, RelativeSource={RelativeSource Self}}" AutoGenerateColumns="False"> 
      <DataGrid.Columns> 
       <DataGridTextColumn Binding="{Binding AlternationIndex, RelativeSource={RelativeSource AncestorType=DataGridRow}}" Header="#"/> 
       <DataGridTemplateColumn Header="City"> 
        <DataGridTemplateColumn.CellTemplate> 
         <HierarchicalDataTemplate> 
          <ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, 
             AncestorType={x:Type Window}}, 
             Path=DataContext.Cities}" 
             DisplayMemberPath="Name" 
             SelectedValue="{Binding Path=RowEntries }"/> 
         </HierarchicalDataTemplate> 
        </DataGridTemplateColumn.CellTemplate> 
       </DataGridTemplateColumn> 
       <DataGridTemplateColumn Header="Countries"> 
        <DataGridTemplateColumn.CellTemplate> 
         <HierarchicalDataTemplate> 
          <ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, 
             AncestorType={x:Type Window}}, 
             Path=DataContext.Countries}" 
             DisplayMemberPath="Name"/> 
         </HierarchicalDataTemplate> 
        </DataGridTemplateColumn.CellTemplate> 
       </DataGridTemplateColumn> 
      </DataGrid.Columns> 
     </DataGrid> 
     <Button Content="Add Row" Margin="0,0,1797,0"></Button> 
    </StackPanel> 
+1

Какая у вас проблема? Также покажите разметку XAML. –

+0

Извините. Пожалуйста, проверьте мой полный пост – Shazter

+1

Ваш RelativeSource кажется неправильным, можете ли вы попробовать этот RelativeSource = {RelativeSource AncestorType = {x: Type Window}} –

ответ

1

Вы должны связать SelectedValue свойства ComboBoxes к свойствам CITYNAME и COUNTRYNAME объекта RowEntry и установить SelectedValuePath свойство ComboBoxes к «Имени». Также установите UpdateSourcePropertyTrigger привязок к PropertyChanged:

<DataGrid.Columns> 
    <DataGridTextColumn Binding="{Binding AlternationIndex, RelativeSource={RelativeSource AncestorType=DataGridRow}}" Header="#"/> 
    <DataGridTemplateColumn Header="City"> 
     <DataGridTemplateColumn.CellTemplate> 
      <HierarchicalDataTemplate> 
       <ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.Cities}" 
             DisplayMemberPath="Name" 
             SelectedValuePath="Name" 
             SelectedValue="{Binding Path=CityName, UpdateSourceTrigger=PropertyChanged}"/> 
      </HierarchicalDataTemplate> 
     </DataGridTemplateColumn.CellTemplate> 
    </DataGridTemplateColumn> 
    <DataGridTemplateColumn Header="Countries"> 
     <DataGridTemplateColumn.CellTemplate> 
      <HierarchicalDataTemplate> 
       <ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.Countries}" 
             DisplayMemberPath="Name" 
             SelectedValuePath="Name" 
             SelectedValue="{Binding Path=CountryName, UpdateSourceTrigger=PropertyChanged}"/> 
      </HierarchicalDataTemplate> 
     </DataGridTemplateColumn.CellTemplate> 
    </DataGridTemplateColumn> 
</DataGrid.Columns> 

Тогда сеттеров свойств источника (CITYNAME и COUNTRYNAME) будет вызываться при выборе элемента в ComboBoxes.

Если вы хотите выбрать несколько значений сначала, вы просто установить эти свойства для некоторых значений, которые присутствуют в ComboBoxes:

public TestViewModel() 
{ 
    ... 
    RowEntries.Add(new RowEntry() { CityName = "Sydney", CountryName = "Australia" }); 
} 
+0

Большое спасибо. Я могу проверить это завтра до тех пор, пока у меня есть вопрос к вашему решению, чтобы лучше понять.SelectedValuePath имеет смысл для меня, но почему я должен использовать UpdateSourceTrigger = PropertyChanged для использования? Я думал, что событие поднято до шаблона mvvm. – Shazter

+0

Свойство UpdateSourceTrigger контролирует * когда * устанавливается свойство source: https://msdn.microsoft.com/en-us/library/system.windows.data.binding.updatesourcetrigger(v=vs.110).aspx – mm8