WPF - odświeżanie widoku ObservableCollection, która zawiera obiekty z samymi getterami (za zmianę stanu tych obiektów odpowiada wstrzyknięty do nich inny obiekt wywolyway w getterach)

0

Na swoim widoku mam ListView która wyswietla zawartość takiej kolekcji.

private ObservableCollection<KalkulowanaOperacjaWydania> listaKalkulowanychOperacji;
        public ObservableCollection<KalkulowanaOperacjaWydania> ListaKalkulowanychOperacji
        {
            get { return listaKalkulowanychOperacji; }
        }

do tej kolekcji dodaje i usuwam obiekty 'KalkulowanaOperacjaWydania' jak w listingu ktory wkleiłem tutaj:

[reakcja na dodawanie i usuwanie obiektow z ObservableCollection<KalkulowanaOperacjaWydania> ListaKalkulowanychOperacji]https://4programmers.net/Forum/Algorytmy/357926-szukam_algorytmu_po_podpowiedziach_pewnie_pojawi_sie_tu_w_tytule_nazwa_tego_algorytmu?p=1819822#id1819822)

obiekt 'KalkulowanaOperacjaWydania' to model, nie implementuje 'INotifyPropertyChanged', i sklada się z samych wlasciwosci tylko do odczytu, za aktualą wartosc tych wlasciwosci odpowiada obiekt nastaw ktory jest wywolywany w kazdym getterze:

public class KalkulowanaOperacjaWydania
    {
        private readonly OperacjaTechnologiczna operacjaOryginalna;
        private readonly IEnumerable<ParaIndexNrOperacjiZwiazanej> pelnyBomIndexu;
        private NastawyKalkulacjiCzasowWydan nastawy;
        private KryteriaDoboruOperacjiWydan filtrOperacjiWydan;

        public KalkulowanaOperacjaWydania(OperacjaTechnologiczna operacja, IEnumerable<ParaIndexNrOperacjiZwiazanej> pelnaListaBom, 
            NastawyKalkulacjiCzasowWydan nastawy, KryteriaDoboruOperacjiWydan zakresIndexowOrazOperacji)
        {
            this.operacjaOryginalna = operacja;
            this.nastawy = nastawy;
            this.pelnyBomIndexu = pelnaListaBom;
            this.filtrOperacjiWydan = zakresIndexowOrazOperacji;
        }

        public int LicznikWystapien         { get; set; }
        public OperacjaTechnologiczna OryginalnaOperacjaTechnologiczna { get { return operacjaOryginalna; } }

        public bool CzyGenerowacPRN         { get; set; }
        public string Index                 { get { return operacjaOryginalna.IndexArtykulu; } }
        public string AltNrMarszruty        { get { return operacjaOryginalna.NrMarszruty; } }
        public int NrOperacji               { get { return operacjaOryginalna.NrOperacji; } }
        public string KodOperacjiWydania    { get { return operacjaOryginalna.KodStanowiska; } }
        public int LiniiDoWydania           { get { return ListaMaterialowWydawanychZTejOperacji.Count(); } }

        public CzasScala Oryginalny_Tpz     { get { return operacjaOryginalna.CzasPrzygotowania; } }
        public CzasScala Oryginalny_Tr      { get { return operacjaOryginalna.CzasRealizacji; } }
        public CzasScala OryginalnyCzasWydaniaMalego 
                                            { get { return Oryginalny_Tpz + Oryginalny_Tr.PrzemnozCzasPrzez(nastawy.WielkoscMalegoZlecenia); } }
        public CzasScala OryginalnyCzasWydaniaDuzego 
                                            { get { return Oryginalny_Tpz + Oryginalny_Tr.PrzemnozCzasPrzez(nastawy.WielkoscDuzegoZlecenia); } }

        public CzasScala Nowy_Tpz           { get { return nastawy.Zwroc_Tpz_DlaIlosciLiniiWBom(ListaMaterialowWydawanychZTejOperacji.Count()); } }
        public CzasScala Nowy_Tr            { get { return nastawy.Zwroc_Tr_DlaIlosciLiniiWBom(ListaMaterialowWydawanychZTejOperacji.Count()); } }
        public CzasScala NowyCzasWydaniaMalego      
                                            { get { return Nowy_Tpz + Nowy_Tr.PrzemnozCzasPrzez(nastawy.WielkoscMalegoZlecenia); } }
        public CzasScala NowyCzasWydaniaDuzego      
                                            { get { return Nowy_Tpz + Nowy_Tr.PrzemnozCzasPrzez(nastawy.WielkoscDuzegoZlecenia); } }

(.......)
        
    }
}

jego aktualnosc zalezy od obiektu typu 'NastawyKalkulacjiCzasowWydan' który z koleii jest powiazany z widokiem poprzez ViewModel i w czasie rzeczywistym jest synchronizowany z tym co uzytkownik ustawi w widoku.

Glowny problem polega na tym ze, ListView na Widoku do ktorego zbindowana jest 'ObservableCollection<KalkulowanaOperacjaWydania> ListaKalkulowanychOperacji' nie jest odswiezany na bieząco po zmianach nastaw.

Jak to osiagnac aby podgladac wyniki przeliczen po kazdej zmianie nastaw?

@neves @Piotr.Net - bedę wdzięczny za podpowiedzi.

tutaj najwazniejsze elementu ViewModelu:

public class CzasyWydanVM : UserControl_ViewModelBase
    {
        private NastawyKalkulacjiCzasowWydan nastawy = new NastawyKalkulacjiCzasowWydan();
        private KryteriaDoboruOperacjiWydan zakresIndexowOrazOperacji = new KryteriaDoboruOperacjiWydan();
       
        public CzasyWydanVM(ObservableCollection<ArtykulScalaVM> kolekcja, ISmartReader reader) : base(kolekcja, reader)
        {
            NazwaViewModelu = nameof(CzasyWydanVM);
            kolekcjaArtykulowZaCheckowanychNaListViewNaOknieGlownym.CollectionChanged += SynchronizacjaPrzeliczaniaZacheckowanychArtykulow;
            listaKalkulowanychOperacji = new ObservableCollection<KalkulowanaOperacjaWydania>();
        }

        public int WielkoscMalegoZlecenia
        {
            get { return nastawy.WielkoscMalegoZlecenia; }
            set { nastawy.WielkoscMalegoZlecenia = value;
                OnPropertyChanged(nameof(WielkoscMalegoZlecenia)); }
        }
        public int WielkoscDuzegoZlecenia
        {
            get { return nastawy.WielkoscDuzegoZlecenia; }
            set { nastawy.WielkoscDuzegoZlecenia = value;
                OnPropertyChanged(nameof(WielkoscDuzegoZlecenia));
            }
        }

        public int DolnaGranica_PrzedzialuPierwszego
        {
            get { return nastawy.DolnaGranica_Przedz_1; }
            set { nastawy.DolnaGranica_Przedz_1 = value;
                OnPropertyChanged(nameof(DolnaGranica_PrzedzialuPierwszego)); }
        }
        public int GornaGranica_PrzedzialuPierwszego
        {
            get { return nastawy.GornaGranica_Przedz_1; }
            set { nastawy.GornaGranica_Przedz_1 = value;
                OnPropertyChanged(nameof(GornaGranica_PrzedzialuPierwszego));
                OnPropertyChanged(nameof(DolnaGranica_PrzedzialuDrugiego)); }
        }
        public decimal Tpz_PrzedzialuPierwszego
        {
            get { return nastawy.Tpz_Przedz_1; }
            set { nastawy.Tpz_Przedz_1 = value;
                OnPropertyChanged(nameof(Tpz_PrzedzialuPierwszego)); }
        }
        public decimal Tr_PrzedzialuPierwszego
        {
            get { return nastawy.Tr_Przedz_1; }
            set { nastawy.Tr_Przedz_1 = value;
                OnPropertyChanged(nameof(Tr_PrzedzialuPierwszego)); }        
        }

(...)
1

Do końca nie wiem czemu listaKalkulowanychOperacji miałoby być aktualizowane po zmianie nastaw. Czy przy OnPropertyChanged którejś z nich jest zmieniany stan listaKalkulowanychOperacji? Coś powinno się zadziać w setterze własności co zmieni listaKalkulowanychOperacji

0

Tutaj więcej kodu

moze na interfejsie bedzie mi lepiej to wyjasnic.

W sekcji 'Symulacje wyliczonych czasów' wyswietlona jest wlasnie kolekcja 'listaKalkulowanychOperacji'.
W sekcji 'Nastawy do wyliczania czasow wydań' sa utawiane parametry obiektu .nastawy'.

Chcialbym zrobic tak aby po przestawieniu jakiejkolwiek nastawy w sekcji 'Nastawy do wyliczania czasow wydań' zmiana przeliczenia zostala widoczna w tabelce.
Po prostu taka logika bedzie bardziej przyjazna dla tego kto to bedzie robil.

PrzechwytywanieN.PNG

1

Rozumiem, że pod debugiem te obiekty z listy mają dobrze przeliczone wartości po zmianach w "nastawy do wyliczana czasów wydań" ?
W jaki sposób na podstawie obiektu NastawyKalkulacjiCzasowWydan aktualizujesz zaznaczony na liście obiekt?

0

tak nastawy działaja bardzo dobrze. sa synchronizowane na biezaco.

Co do aktualizowania obiektow 'KalkulowanaOperacjaWydania' na liscie listaKalkulowanychOperacji to wlasnie one nie maja swojego stanu.
wartosci ich wlasciwosci sa wyliczane w momencie wywolania gettera, a liczone sa w oparciu o to co jest na biezaco w 'nastawach'

fragment wlasciwosci 'KalkulowanaOperacjaWydania''

        public CzasScala Nowy_Tpz           { get { return nastawy.Zwroc_Tpz_DlaIlosciLiniiWBom(ListaMaterialowWydawanychZTejOperacji.Count()); } }
        public CzasScala Nowy_Tr            { get { return nastawy.Zwroc_Tr_DlaIlosciLiniiWBom(ListaMaterialowWydawanychZTejOperacji.Count()); } }
        public CzasScala NowyCzasWydaniaMalego      
                                            { get { return Nowy_Tpz + Nowy_Tr.PrzemnozCzasPrzez(nastawy.WielkoscMalegoZlecenia); } }
        public CzasScala NowyCzasWydaniaDuzego      
                                            { get { return Nowy_Tpz + Nowy_Tr.PrzemnozCzasPrzez(nastawy.WielkoscDuzegoZlecenia); } }

0

zaimplementowalem w 'KalkulowanaOperacjaWydania', 'INotifyPropertyChanged', dodalem settery w metodach ktore chce zeby sie odswiezaly na biezaco.

public class KalkulowanaOperacjaWydania : ViewModelBase
    {
        private readonly OperacjaTechnologiczna operacjaOryginalna;
        private readonly IEnumerable<ParaIndexNrOperacjiZwiazanej> pelnyBomIndexu;
        private NastawyKalkulacjiCzasowWydan nastawy;
        private KryteriaDoboruOperacjiWydan filtrOperacjiWydan;
        (......)
        private CzasScala nowy_Tpz;
        public CzasScala Nowy_Tpz           
        { 
            get { return nastawy.Zwroc_Tpz_DlaIlosciLiniiWBom(ListaMaterialowWydawanychZTejOperacji.Count()); }
            set { nowy_Tpz = value;
                OnPropertyChanged(nameof(Nowy_Tpz)); }
        }

        private CzasScala nowy_Tr;
        public CzasScala Nowy_Tr            
        { 
            get { return nastawy.Zwroc_Tr_DlaIlosciLiniiWBom(ListaMaterialowWydawanychZTejOperacji.Count()); }
            set { nowy_Tr = value;
                OnPropertyChanged(nameof(Nowy_Tr)); }
        }

        private CzasScala nowyCzasWydaniaMalego;
        public CzasScala NowyCzasWydaniaMalego
        {
            get { return Nowy_Tpz + Nowy_Tr.PrzemnozCzasPrzez(nastawy.WielkoscMalegoZlecenia); }
            set { nowyCzasWydaniaMalego = value;
                OnPropertyChanged(nameof(NowyCzasWydaniaMalego)); }
        }

        private CzasScala nowyCzasWydaniaDuzego;
        public CzasScala NowyCzasWydaniaDuzego      
        { 
            get { return Nowy_Tpz + Nowy_Tr.PrzemnozCzasPrzez(nastawy.WielkoscDuzegoZlecenia); }
            set { nowyCzasWydaniaDuzego = value;
                OnPropertyChanged(nameof(NowyCzasWydaniaDuzego)); }
        }
        (....)
    }

A w ViewModel tego widoku, pododawalem do wlasciwosci odpowiedzilanych za nastawy wg ktorych przelicza sie czasy takie settery w ktorych wywoluje metode 'ZglosDoPrzeliczenia()', ale to rozwiazanie zabilo aplikacje. zamulilo niesamowicie. teraz NumericUpDown reaguja na klik dobry kawał sekundy.

Jak to przyspieszyc? czy uruchomienie 'ZglosDoPrzeliczenia()' w innym watku pomoze? Jak uruchomic ją w innym watku? wielowatkowosci jeszcze w ogole nie ruszalem.

public int WielkoscMalegoZlecenia
        {
            get { return nastawy.WielkoscMalegoZlecenia; }
            set { nastawy.WielkoscMalegoZlecenia = value;
                ZglosDoPrzeliczenia();
                OnPropertyChanged(nameof(WielkoscMalegoZlecenia)); }
        }
        public int WielkoscDuzegoZlecenia
        {
            get { return nastawy.WielkoscDuzegoZlecenia; }
            set { nastawy.WielkoscDuzegoZlecenia = value;
                ZglosDoPrzeliczenia();
                OnPropertyChanged(nameof(WielkoscDuzegoZlecenia));
            }
        }

        (......)

public void ZglosDoPrzeliczenia()
        {
            foreach (var item in ListaKalkulowanychOperacji)
            {
                item.LicznikWystapien = item.LicznikWystapien;
                item.NowyCzasWydaniaDuzego = item.NowyCzasWydaniaDuzego;
                item.NowyCzasWydaniaMalego = item.NowyCzasWydaniaMalego;
                item.Nowy_Tpz = item.Nowy_Tpz;
                item.Nowy_Tr = item.Nowy_Tr;
            }
        }
1

Jak zmieniasz jedną właściwość to są liczone wszystkie inne, na które zmieniona właściwość nie ma sensu i to wydłuża czas metody.
Bez sensu są dodane te settery, skoro tych pól nie używasz, a wartości liczysz z obiektu NastawyKalkulacjiCzasowWydan
Przyznam szczerze, że nie do końca rozumiem jak to powinno działać i niestety kod się słabo czyta. Dodatkowo takie linie jak
get { return Nowy_Tpz + Nowy_Tr.PrzemnozCzasPrzez(nastawy.WielkoscDuzegoZlecenia); } sprawiają, że kod wygląda jak spaghetti.
Przez to ciężko mi pomóc na Twoim przykładzie.
Ale według mnie powinno to być tak:

  • viewmodel, który ma listę IEnumerable<KalkulowanaOperacjaWydania> powinien mieć też właściwość, który przechowuje zaznaczony element z listy
  • gdy zaznaczymy element to do viewmodelu NastawyKalkulacjiCzasowWydan przekazywany jest zaznaczony obiekt z listy
  • tam są ustawiane wartości dla zaznaczonego obiektu z listy, który implementuje INotifyPropertyChanged.
    W klasie KalkulowanaOperacjaWydania wywal logikę z geta, a potrzebne właściwości licz i ustawiaj w klasie NastawyKalkulacjiCzasowWydan
1

Niewiele więcej mam do dodania, gettery i settery powinny być jak najgłupsze, nie powinny niczego liczyć, tylko wyświetlać gotowe dane skoro skoro to tylko do odczytu VM. W szczególności jeśli będziesz chciał robić obliczenia o dzielnym wątku, to one muszą być oderwane od interfejsu użytkownika. Pierw sobie gdzieś liczysz coś na boku, a potem wypełniasz VM gotowymi wynikami.

I wszystkie fragmenty kodu byłoby dobrze umieszczać w kontekście klasy w której się znajdują, bo powklejałeś jakieś metody i propertisy bez tego, i ciężko sobie wyobrazić jak to wszystko jest złożone do kupy.

2

Po tym jak program zadziałał jak chciałem, usunąłem te przeliczanie w getterach, zdefiniowałem zdarzenia w Nastawach.. które wywołuje za każdym razem gdy jakaś nastawa zostanie zmieniona, a wszystkie "KalkulowaneOperacje..." zostały subskrybentem tych zdarzeń i przeliczają i ustawiają swoje właściwości w metodach obsługi zdarzeń. Wszystkie ObservableCollection zdecydowanie odżyły jak wyczyściłem gettery właściwości obiektów trzymanych w tych kolekcjach z przeliczen. Jak już wszystko działa to powolutku dalej staram się to przerabiać żeby było bardziej po ludzku.

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