WPF MVVM DataGrid nie odświeża

0

Witam.

Mam problem z bindowaniem do DataGrid. Mam listę klientów, którą odpalam z menu głównego. Datagrid w tym widoku przedstawia się tak:

<DataGrid Name="ClientsTable" IsReadOnly="True" ItemsSource="{Binding ListOfClients}" AutoGeneratingColumn="DataGrid_AutoGeneratingColumn" Height="600" Margin="10" Width="800"/>
            <Grid.InputBindings>
            <MouseBinding Gesture="LeftDoubleClick" Command="{Binding OpenClientDetails}" CommandParameter="{Binding ElementName=ClientsTable,Path=SelectedItem}"/>
        </Grid.InputBindings>

Mam tu dodatkowo opcję, że po podwójnym klknięciu na wiersz przechodzi do tego rekordu oraz generowanie nazw kolumn na podstawie atrybutów pola ClientForView. Ale ja nie o tym.
Otóż jak edytuję klienta to nie odświeża mi tego DataGrida. Nie oczekuję, że samoczynnie go odświeży, tylko zamykam okno z listą klientów, odpalam na nowo i dalej bez zmian... Muszę zamknąć program i odpalić od nowa. Po dodaniu klienta klient pokazuje się w tabeli, tylko podczas edycji nie aktualizuje danych.

Czy ktoś może pomóc?

Poniżej kolekcja, którą binduję oraz metoda, którą wykonuję w konstruktorze ViewModelu okna z datagrid.

private void LoadAllClients()
        {
            listOfClients = new ObservableCollection<ClientForList>();
            var clients = clientService.GetAllClientsForList();
            foreach (var client in clients)
            {
                listOfClients.Add(client);
            }
        }

        private ObservableCollection<ClientForList> listOfClients;
        public ObservableCollection<ClientForList> ListOfClients
        {
            get { return listOfClients; }
            set { SetProperty(ref listOfClients, value); }
        }
0

Musiałbyś podać kod swojego ViewModelu, w którym momencie jest wywołana metoda ładowania danych. Zapewne dane są po edycji nie są przeładowane, a jedynie w momencie ładowania formy po raz pierwszy. Postaw sobie breakpointa na swoją kolekcję w setterze i zobacz kiedy elementy się zmieniają.

0

Tak jak napisałem metoda ładująca dane umieszczona jest w konstruktorze ViewModelu i odpala się za każdym razem mimo to dane pozostają stare.
Po postawieniu breakpointa metoda jest uruchamiana i dane się nie zmieniają. Dopiero jak zamknę aplikacje to mam odświeżone.

0

Witam,

A jesteś pewien że robisz wszystko jak należy? Może lekko zmodyfikuj swój kod by WPF wiedział co ma robić.

private void LoadAllClients()
        {
            ListOfClients.Clear();
            var clients = clientService.GetAllClientsForList();
            foreach (var client in clients)
            {
                ListOfClients.Add(client);
            }
        }

        private ObservableCollection<ClientForList> listOfClients = new ObservableCollection<ClientForList>();
        public ObservableCollection<ClientForList> ListOfClients
        {
            get { return listOfClients; }
            set { SetProperty(ref listOfClients, value); }
        }

Pozdrawiam,

mr-owl

0

@mr-owl: tutaj aż się prosi o async, await dla metody LoadAllClients. :-)
No i nie trzeba czyścić kolekcji tylko utworzyć zwyczajnie nową, za każdym razem kiedy potrzeba załadować klientów.

0

Owszem, przerobię na async, await, w sumie muszę, aby działał mi MetroDialog z biblioteki MahappsMetro, ale najpierw chcę ogarnąć, aby to w ogóle działało.

Zmieniłem kod na:

public ListOfClientsViewModel(IClientService clientService, IEventAggregator eventAggregator)
        {
            this.clientService = clientService;
            this.eventAggregator = eventAggregator;
            ListOfClients.AddRange(clientService.GetAllClientsForList());
        }

        private ObservableCollection<ClientForList> listOfClients = new ObservableCollection<ClientForList>();
        public ObservableCollection<ClientForList> ListOfClients
        {
            get { return listOfClients; }
            set { SetProperty(ref listOfClients, value); }
        }

I nic. Gaszę okno z lista klientów, odpalam je od nowa w tak sposób:

void ExecuteOpenListOfClientsWindow()
        {
            ListOfClients listOfClientsWindow = new ListOfClients();
            listOfClientsWindow.DataContext = new ListOfClientsViewModel(IClientService, EventAggregator);
            listOfClientsWindow.ShowDialog();
        }

Niestety dane pozostają te same mimo, że stawiam breakpointa na metodzie AddRange, która ładuje mi do kolekcji klientów już ze zmienionymi danymi.... Nie ogarniam normalnie. Przecież logicznie myśląc ładuję do kolekcji dane, więc powinno mi je zbindować, a nie trzymać poprzednią wersję. Nie znam aż tak WPF i Prism, może jest tam jakiś cache czy coś...

Edit: Dodam, że szukam jakiś rozwiązań w sieci. Nawet model klienta, który jest ładowany miałem na początku z Auto-Properites, a przerobiłem na:

public class ClientForList : INotifyPropertyChanged
    {

        private string id;
        private string name;
        private string firstname;
        private string lastname;
        private string city;
        private DateTime createdDate;

        [DisplayName("Numer klienta")]
        public string Id
        {
            get { return id; }
            set
            {
                if (value != this.id)
                {
                    this.id = value;
                    OnPropertyChanged();
                }
            }
        }

[.....]

public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

Nawet w ViewModelu ObservableColletion metodę set ustawiłem na prywatną i nic, zero efektu.

0

Witam,

Możesz udostępnić jakiś przykładowy kod który mogę uruchomić na swoim komputerze? Mam wrażenie że w jednym miejscu używasz Prism-a i a resztę robisz z palca.

Pozdrawiam,

mr-owl

0

Kurczę ciężko z kodem, jeśli się nie zalogujesz do aplikacji to nie otworzy tego okna, trzeba najpierw skonfigurować bazę SQL Server. Jutro po południu zmigruję projekt na GitHuba jako publiczne repo i tu dam linka, bo obecnie stoi na VSTS.

Co do tego, że w jednym miejscu używam Prisma, a w innym nie. Chodzi o to, że klasa ClientForList jest w innym projekcie bez Prisma. Jednak myślę, że czy będzie to implementacja metod BindableBase, czy INotifyPropertyChanged nie powinno mieć znaczenia.

Póki co czekając do jutra postaram się to w miarę zwięźle opisać jeśli chodzi o stan obecny.

W pliku xaml mam DataGrida:

<DataGrid Name="ClientsTable" IsReadOnly="True" ItemsSource="{Binding Path=ListOfClients, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" AutoGeneratingColumn="DataGrid_AutoGeneratingColumn" Margin="22,10,22,55" Width="800"/>

Odpowiada za niego we ViewModelu tego okna ten kod:

public ListOfClientsViewModel(IClientService clientService, IEventAggregator eventAggregator)
        {
            this.clientService = clientService;
            this.eventAggregator = eventAggregator;
            ListOfClients.AddRange(clientService.GetAllClientsForList());

        }

        private ObservableCollection<ClientForList> listOfClients = new ObservableCollection<ClientForList>();
        public ObservableCollection<ClientForList> ListOfClients
        {
            get { return listOfClients; }
            set { SetProperty(ref listOfClients, value); }
        }

Klasa, której obiekty ładuję do kolekcji, a raczej jej część:

public class ClientForList : INotifyPropertyChanged
    {
        private string id;
        private string name;
        private string firstname;
        private string lastname;
        private string city;
        private DateTime createdDate;

        [DisplayName("Numer klienta")]
        public string Id
        {
            get { return id; }
            set
            {
                if (value != id)
                {
                    id = value;
                    OnPropertyChanged();
                }
            }
        }
        [DisplayName("Nazwa")]
        public string Name
        {
            get { return name; }
            set
            {
                if (value != name)
                {
                    name = value;
                    OnPropertyChanged();
                }
            }
        }
        [......]
        [DisplayName("Data utworzenia")]
        public DateTime CreatedDate
        {
            get { return createdDate; }
            set
            {
                if (value != createdDate)
                {
                    createdDate = value;
                    OnPropertyChanged();
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

I tak, w tym oknie jak kliknę dwa razy na wierszy otwiera mi się okno podglądu klienta. Tam mogę go edytować. Po edycji zapisuję od razu do bazy danych. Zamykam okno z listą klientów. Odpalam je ponownie w ten sposób:

void ExecuteListOfClients()
        {
            ListOfClients listOfClientsWindow = new ListOfClients();
            listOfClientsWindow.DataContext = new ListOfClientsViewModel(IClientService, EventAggregator);
            listOfClientsWindow.ShowDialog();
        }

No i jak już pisałem wcześniej, dane są z przed edycji. Mimo to, że stawiając breakpointa na metodzie ładującej dane do kolekcji ObservableCollection ładowane są obiekty już po edycji.

0

Witam,

To że część jest w osobnym projekcie to chyba nie jest jakiś duży problem, zawsze możesz komunikację zrobić za pomocą EventAgregatora. Co do otwierania okienek to masz dostępną bibliotekę MvvmDialogs, całkiem fajnie to działa

Pozdrawiam,

mr-owl

0

Po prostu w drugim projekcie trzymam obiekty DTO i nie mam tam paczki z Prismem dlatego nie implementowałem BindableBase.

Co do MvvmDialogs, dzięki, pomyślę, ale najpierw muszę rozwiązać ten nie dający mi spokoju problem ;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0