Подтвердить что ты не робот

Связывание WPF Datagrid не обновляется до щелчка заголовка строки

У меня есть datagrid, связанный с List в модели представления. Содержимое сетки не обновляется до тех пор, пока я не нажму на заголовок строки. Щелчок в разных ячейках не влияет на него. Я должен нажать на заголовок.

Это datagrid в XAML:

<DataGrid x:Name="TransactionDetailsGrid" Grid.Row="1" AutoGenerateColumns="False" SelectionMode="Extended" IsReadOnly="True" HeadersVisibility="Column"
                  ItemsSource="{Binding TransactionDetailList}" SelectedItem="{Binding SelectedTransactionDetail}" GridLinesVisibility="None">
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding Path=Account.AccountNumber}" Header="Account No." HeaderStyle="{StaticResource DataGridHeaderStyleCenter}" Width="120" />
        <DataGridTextColumn Binding="{Binding Path=Account.AccountName}" Header="Account Name" HeaderStyle="{StaticResource DataGridHeaderStyleCenter}" Width="*" />
        <DataGridTextColumn Binding="{Binding Path=Amount}"  Header="Amount" HeaderStyle="{StaticResource DataGridHeaderStyleCenter}" Width="120" />
    </DataGrid.Columns>
</DataGrid>

И это из модели вида:

public List<TransactionDetail> TransactionDetailList
{
    get { return this._transactionDetailList; }

    set
    {
        this._transactionDetailList = value;
        RaisePropertyChanged("TransactionDetailList");                
    }
}

Это редактирование одного из элементов в модели представления:

private void AddTransactionDetail()
{
    TransactionDetailViewModel viewModel = new TransactionDetailViewModel();

    MainWindowViewModel.ViewLoader.ShowDialog(viewModel);

    if (viewModel.TransactionDetail != null)
    {
        this.TransactionDetailList.Add(viewModel.TransactionDetail);
        RaisePropertyChanged("TransactionDetailList");
    }
}

После этого я могу установить точку останова на получателе TransactionDetailList, и в коллекции есть элемент в нем. Однако, datagrid пуст. Если я нажму на строку заголовка, элемент появится в сетке.

У меня такая же проблема при редактировании.

Я сделал это успешно раньше, поэтому я не уверен, что здесь отличает. Мне что-то не хватает? Почему сетка не покажет свое содержимое, пока я не нажму на строку заголовка?

Я только что заметил что-то интересное. Когда я нажимаю на заголовок сетки, точка останова в получателе TransactionDetailList не попадает, но данные все же появляются. Таким образом, он, как сетка, имеет информацию, он просто не показывает ее до тех пор, пока не будет нажат заголовок.

После изменения использования ObservableCollection это сработало. Но теперь у меня такая же проблема с редактированием (сетка не обновляется до нажатия на заголовок):

private void EditTransactionDetail()
{
    TransactionDetailViewModel viewModel = new TransactionDetailViewModel(this.SelectedTransactionDetail);

    MainWindowViewModel.ViewLoader.ShowDialog(new TransactionDetailViewModel(this.SelectedTransactionDetail));

    RaisePropertyChanged("TransactionDetailList");
}

Должен ли мой объект реализовать INotifyPropertyChanged? Если я изменю коллекцию и вызову RaisePropertyChanged, не должно ли это вызывать обновление сетки?

4b9b3361

Ответ 1

Проблема заключается в том, что при добавлении или удалении элемента из коллекции установщик не вызывается. Это означает, что INotifyPropertyChanged не вызывается, и представление не имеет способа узнать, что его нужно обновить.

WPF решает это, поддерживая также интерфейс INotifyCollectionChanged.

Попробуйте использовать ObservableCollection<TransactionDetail> вместо List<TransactionDetail>. ObservableCollection<T> встроен и реализует INotifyCollectionChanged, поэтому вам не придется много чего делать с вашим кодом.

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

public ObservableCollection<TransactionDetail> TransactionDetailList
{
    get { return this._transactionDetailList; }

    set
    {
        this._transactionDetailList = value;
        RaisePropertyChanged("TransactionDetailList");                
    }
}

См:

Edit

Кроме того, вы должны реализовать INotifyPropertyChanged в TransactionDetail тоже. Если вы не можете, заверните его в класс, который реализует INotifyPropertyChanged.

Если вы не реализуете его на TransactionDetail, чем сделанные вами изменения, которые не влияют на список, но влияют на свойства экземпляра TransactionDetail, не будут отображаться в пользовательском интерфейсе, пока вы не обновите весь список.

Если вы попытались исправить это, вызвав RaisePropertyChanged в свойстве списка, ваш пользовательский интерфейс подумает, что весь список (и, следовательно, весь набор объектов интерфейса пользователя) должен быть выброшен и обновлен. Это убьет вашу производительность и сделает ваше приложение вялым.

Ответ 2

Если вы хотите, чтобы ваша сетка обновлялась, когда вы меняете список IEnumerable, она обязана сделать ее типом списка, который реализует INotifyCollectionChanged. Встроенный тип данных, в котором есть ObservableCollection (также здесь). Поэтому, если вы создадите свою собственность следующим образом:

public ObservableCollection<TransactionDetail> TransactionDetailList
{
    get { return this._transactionDetailList; }

    set
    {
        this._transactionDetailList = value;
        RaisePropertyChanged("TransactionDetailList");                
    }
}

ваша сетка автоматически подберет любые элементы, которые вы добавите или удалите из списка.
Эффективно то, что вы делаете здесь, уведомляет, когда список изменился (например, ссылка на список), но вы не уведомляете, когда содержимое списка изменилось.