WPF MVVMLight: обновить сетку данных на основе выбранного элемента другой сетки данных

#c# #.net #wpf #mvvm-light #wpfdatagrid

#c# #.net #wpf #mvvm-light #wpfdatagrid

Вопрос:

Разработка WPF приложения с использованием MVVMLight .

Мой Model состоит из Attribute класса и DataSet класса с ObservableCollection<Attribute> свойством по имени Attributes .

У My MainViewModel есть DataSet свойство.

В моем, MainView для DataContext которого он MainViewModel установлен на DataGrids , у меня их два, и у меня есть два,,. У одного есть ItemsSource привязка к DataSet.Attributes , которая работает нормально:

 <DataGrid CanUserAddRows="false" AutoGenerateColumns="false" ItemsSource="{Binding DataSet.Attributes}">
//some DataGrid columns here
  

Я хочу, чтобы вторая DataGrid отображала некоторые дополнительные свойства на основе SelectedItem первой сетки данных, поэтому я сделал следующее:

1) добавлено SelectedAttribute свойство типа Attribute в моем MainViewModel :

 private Attribute selectedAttribute;
public Attribute SelectedAttribute
{
    get { return selectedAttribute; }
    set
    {
        if (selectedAttribute == value)
        {
            return;
        }
        selectedAttribute = value;
        RaisePropertyChanged(() => SelectedAttribute);
    }
}
  

2) изменил мой первый, DataGrid чтобы привязать его SelectedItem к SelectedAttribute :

 <DataGrid CanUserAddRows="false" AutoGenerateColumns="false" ItemsSource="{Binding DataSet.Attributes}" SelectedItem="{Binding SelectedAttribute}">
  

3) Обновление 1 присвоило ItemsSource второму DataGrid значение SelectedAttribute и создало столбец, привязанный к Categories свойству SelectedAttribute , которое является ObservableCollection<string> :

 <DataGrid SelectionMode="Single" EnableColumnVirtualization="True" AutoGenerateColumns="false" ItemsSource="{Binding Main.SelectedAttribute}">
    <DataGrid.Columns>
        <DataGridTextColumn Header="categories" Width="auto" Binding="{Binding Main.SelectedAttribute.Categories}"  />                      
    </DataGrid.Columns>
</DataGrid>
  

4) в моем случае MainViewModel после DataSet.Attributes заполнения я устанавливаю SelectedAttribute значение первого Attribute в коллекции (просто в качестве теста):

 SelectedAttribute = DataSet.Attributes[0];
  

Как только я запускаю это, первая DataGrid загружается нормально, но ни один элемент не выбран, а вторая DataGrid ничего не показывает. Что я делаю не так?

Комментарии:

1. SelectedAttribute — это отдельный объект, и вы пытаетесь привязать его к сетке данных, для которой необходим источник данных, реализующий IEnumerable. Попробуйте сделать SelectedAttribute наблюдаемой коллекцией и применить только один элемент в коде.

2. привет, Пол, второй столбец DataGrid фактически привязан к ObservableCollection<string> свойству Attribute , см. Обновленный пост выше.

Ответ №1:

ItemsSource сетки должен быть IEnumerable. Итак, это:

 ItemsSource="{Binding Main.SelectedAttribute}"
  

не сработает, потому что SelectedAttribute является экземпляром класса, а не каким-то списком.

Вы также привязываете что-то, что предположительно реализует IEnumerable (категории), к DataTextColumn, что также неверно; привязка столбца сетки должна быть скалярным свойством.

РЕДАКТИРОВАТЬ: Вы не сможете напрямую привязать столбцы в сетке к трем отдельным наблюдаемым коллекциям; вам нужно будет создать новый класс модели для хранения данных, которые вы хотите отобразить в сетке, например:

 public class SomeGridItem
{
    public string Category {get; set;}
    public string SecondProp {get; set;}
    public string ThirdProp [get; set;}
}
  

Затем добавьте новое свойство в вашу модель представления — это то, к чему вы будете привязывать сетку:

 public ObservableCollection<SomeGridItem> Blahs {get; set;}
  

Затем, когда SelectedAttribute изменится, вам нужно будет заполнить пустые места. Вы могли бы сделать это в параметре установки свойств для SelectedAttribute (вероятно, проще всего), или вы могли бы отреагировать на событие PropertyChanged для SelectedAttribute. Это псевдокод, но он должен дать вам представление о том, что нужно сделать.

 Blah.Clear();

for (var i = 0; i < SelectedAttribute.Categories.Count; i  ) {
   Blahs.Add(new SomeGridItem() {
        Category = SelectedAttribute.Categories[i],
        SecondProp = SelectedAttribute.SecondCollection[i],
        ThirdProp = SelectedAttribute.ThirdCollection[i]
    });
}
  

Затем привязать к вашей сетке.

 <DataGrid SelectionMode="Single" EnableColumnVirtualization="True" AutoGenerateColumns="false" ItemsSource="{Binding Main.Blahs}">
    <DataGrid.Columns>
        <DataGridTextColumn Header="categories" Width="auto" Binding="{Binding Category}"  />                      
        <DataGridTextColumn Header="categories" Width="auto" Binding="{Binding SecondProp}"  />                      
        <DataGridTextColumn Header="categories" Width="auto" Binding="{Binding ThirdProp}"  />                      
    </DataGrid.Columns>
</DataGrid>
  

Комментарии:

1. @paul-abbott-wa-us, это три столбца для трех ObservableCollection свойств Attribute ( Categories и еще 2). Вот почему я пытался привязать ItemsSource к Main.SelectedAttribute

2. Эти три наблюдаемые коллекции гарантированно будут содержать одинаковое количество элементов? И они связаны по позиции — например, значение Categories[0] соответствует значению SecondCollection[0] и ThridCollection[0]?

3. @paul-abbott-wa-us да по обоим вопросам

4. думаю, я понял, Пол, спасибо, я попробую ваше решение. Однако я не понимаю, почему я не могу напрямую привязать три столбца в сетке к трем отдельным наблюдаемым коллекциям, поскольку все они имеют одинаковый размер и связаны индексом. Есть ли другой элемент управления, который лучше соответствовал бы моим потребностям? я должен также отметить, что я планирую реализовать TwoWay привязку для этих свойств