2011-06-24 9 views
13

Mam datagrid, który jest powiązany z listą w modelu widoku. Zawartość siatki nie aktualizuje się, dopóki nie kliknę nagłówka wiersza. Kliknięcie w różne komórki nie ma na nie wpływu. Muszę kliknąć na nagłówek.Wiązanie Datagrid WPF nie jest aktualizowane, dopóki nie zostanie kliknięty nagłówek wiersza

To DataGrid w 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> 

A to z modelu Widok:

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

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

Jest to edycja jednej z pozycji, w modelu Widok:

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

    MainWindowViewModel.ViewLoader.ShowDialog(viewModel); 

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

Po tym uruchomieniu, mogę umieścić punkt przerwania na pobierającym TransactionDetailList, a kolekcja h jako przedmiot w nim. Jednak datagrid jest pusty. Jeśli kliknę wiersz nagłówka, element pojawi się w siatce.

Mam taki sam problem podczas edycji.

Zrobiłem to z powodzeniem wcześniej, więc nie jestem pewien, co tutaj jest inaczej. Czy brakuje mi czegoś oczywistego? Dlaczego siatka nie wyświetla jej zawartości, dopóki nie kliknę w wiersz nagłówka?

Właśnie zauważyłem coś interesującego. Kiedy klikam nagłówek siatki, punkt przerwania w pobierającym transakcję TransactionDetailList nie zostanie trafiony, ale dane nadal będą wyświetlane. Tak, to jest tak, jakby siatka zawierała informacje, po prostu nie jest wyświetlana, dopóki nagłówek nie zostanie kliknięty.

Po zmianie na ObserveableCollection zadziałało. Ale teraz mam ten sam problem z edycji (siatka nie aktualizuje aż klikając nagłówek):

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

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

    RaisePropertyChanged("TransactionDetailList"); 
} 

Czy moja jednostka należy wdrożyć INotifyPropertyChanged? Jeśli zmienię kolekcję i zadzwonię do RaisePropertyChanged, czy to nie powinno spowodować aktualizacji siatki?

Odpowiedz

10

Problem polega na tym, że gdy dodajesz lub usuwasz element z kolekcji, seter nie jest wywoływany. Oznacza to, że INotifyPropertyChanged nie jest wywoływane, a widok nie może wiedzieć, że musi zostać odświeżony.

WPF rozwiązuje ten problem, wspierając także interfejs INotifyCollectionChanged.

Spróbuj użyć ObservableCollection<TransactionDetail> zamiast List<TransactionDetail>. ObservableCollection<T> jest wbudowany i implementuje INotifyCollectionChanged, więc nie będziesz musiał wiele robić na swoim kodzie.

Upewnij się również, że kontynuujesz implementację INotifyPropertyChanged w modelu widoku, tak jak już masz. W ten sposób widok zostanie powiadomiony, gdy zastąpisz całą kolekcję (gdy wywoływacz zostanie wywołany).

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

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

Patrz:

Edycja:

Ponadto, należy wdrożyć INotifyPropertyChanged na TransactionDetail też. Jeśli nie możesz, umieść go w klasie, która implementuje INotifyPropertyChanged.

Jeśli nie zaimplementujesz go na TransactionDetail, wprowadzone zmiany, które nie mają wpływu na listę, ale będą miały wpływ na właściwości instancji TransactionDetail, nie będą wyświetlane w interfejsie użytkownika, dopóki nie odświeżysz całej listy.

Jeśli próbowałeś to naprawić, wywołując RaisePropertyChanged we właściwości listy, to twój UI uważa, że ​​cała lista (a więc i cały zestaw obiektów interfejsu użytkownika) musi zostać wyrzucona i zaktualizowana. Zabije to wydajność i spowolni działanie aplikacji.

+0

Kiedy zmieniam pozycję na liście, czy ta linia powinna spowodować aktualizację datagridu, pokazując w nim zaktualizowany element? RaisePropertyChanged ("TransactionDetailList"); –

+1

@Bob: Nie. Twój seter działa tak, jak każdy inny ustawodawca nieruchomości w danym języku. Zostaje on wywołany tylko po zastąpieniu całej 'TransactionDetailList'. Nie jest to bardzo przydatne w przypadku interfejsu użytkownika, dlatego właśnie stworzyli 'INotifyCollectionChanged' i' ObservableCollection '. –

+1

@ Bob: Oh, czekaj, masz na myśli ostatni w swoim pytaniu? Nie, nie powinieneś informować UI, że cała lista zmienia się, gdy zmieniasz tylko wartości jednej z właściwości jednego z elementów, które * dzieje się *, które mają być przechowywane na liście. To całkowicie zabije twój perf. Zamiast tego zaimplementuj 'INotifyPropertyChanged' na klasie' TransactionDetail'. –

2

Jeśli chcesz, aby siatka aktualizowała się z chwilą zmiany listy IEnumerable, do której jest przypisana, ustaw ją jako listę, która implementuje INotifyCollectionChanged. Wbudowany typ danych, który ma to jest ObservableCollection (also here). Jeśli więc sprawisz, że Twoja nieruchomość będzie wyglądać następująco:

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

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

Twoja siatka automatycznie pobierze wszystkie przedmioty dodane lub usunięte z listy.
Efektywnie to, co tu robisz, powiadamia o zmianie listy (tj. O liście), ale nie powiadamiasz, kiedy zmieniła się lista zawartości.

+0

Zmieniłem na ObservableCollection, a siatka się aktualizuje. Zrobiłem to wcześniej, używając tylko Listy , i zadziałało. –

+1

@Bob: Prawdopodobnie zadzwoniłeś do setera i zastąpiłeś całą listę.Albo to zrobiłeś, albo zrobiłeś swoje aktualizacje, zanim zaczęto sprawdzać listę. –

Powiązane problemy