DataGridView -> zdarzenie wykrywające zmianę wartości komórki ukrytej

0

Dzień dobry,

Napisałem klasę, którą podpiąłem do grida za pomocą DataSource (Klasa zwraca listę obiektów, które wyświetlane są w gridzie).
Wykonując obliczenia w klasie za pomocą klasy automatycznie aktualizuje się grid.

Jedna z ukrytych kolumn określa widoczność wiersza (takie mini filtrowanie mające które ma ustawić dany wiesz jako tylko do odczytu lub nie).
Do tej pory robiłem to tak, że za każdym razem po filtrowaniu puszczałem pętle po wszystkich wierszach grida i na podstawie informacji z ukrytej kolumny ustawiałem tryb do odczytu dla danego wiersza. Proste i skuteczne - ale jak się ma kilkanaście/kilkadziesiąt wpisów bo przy większej liczbie wpisów taka pętelka wykonuje się za długo.

Wymyśliłem, że jeżeli uda mi się podpiąć zdarzenie wykrywające zmianę w wierszu (ukrytej komórce) grid będzie automatycznie ustawiał tryb do odczytu. Dzięki temu gdy wyłączę widoczność dla 3 rekordów z miliona to zajmie to chwilę. (o ile to jest w ogóle możliwe)

Nie mogę/nie potrafię odnaleźć odpowiedniego zdarzenia. CellValueChanged nie działa ponieważ ono wykrywa utratę focusa z komórki, a w tym przypadku ona po prostu nie następuje bo jest ukryta.

Czy moglibyście mi poradzić jak sobie z tym poradzić?

0

Na jakiej podstawie rozróżniasz, czy wiersz ma być readonly, czy nie?

0

Do tej pory robiłem to tak, że za każdym razem po filtrowaniu puszczałem pętle po wszystkich wierszach grida i na podstawie informacji z ukrytej kolumny ustawiałem tryb do odczytu dla danego wiersza. Proste i skuteczne - ale jak się ma kilkanaście/kilkadziesiąt wpisów bo przy większej liczbie wpisów taka pętelka wykonuje się za długo.

Ja do tego używam LINQ , przykladowo

var rowsIndex= dataGridView1.Rows.Cast<DataGridViewRow>()
                    .Where(r => int.Parse(r.Cells[indeks_kolumny_sprawdzanej_komórki].Value.ToString()) == 1)
                    .Select(r => r.Index).ToList();

i do listy pobrane masz indeksy wierszy spełniające jakiś tam warunek.
Później przelatuje pętlą po elementach mojej listy i wiem gdzie ustawić wartość na readonly i nie muszę przeszukiwać wtedy wszystkich wierszy, przykładowo:

foreach(int i in rowsIndex)
{
        dataGridView1.Rows[i].ReadOnly=true;
}

Jeżeli ktoś zna lepszą drogę, też chętnie się dowiem :)

pzdr

1
cjancik napisał(a):

Ja do tego używam LINQ , przykladowo

var rowsIndex= dataGridView1.Rows.Cast<DataGridViewRow>()
                    .Where(r => int.Parse(r.Cells[indeks_kolumny_sprawdzanej_komórki].Value.ToString()) == 1)
                    .Select(r => r.Index).ToList();

Później przelatuje pętlą po elementach mojej listy i wiem gdzie ustawić wartość na readonly i nie muszę przeszukiwać wtedy wszystkich wierszy, przykładowo:

A jak myślisz, jak działa LINQ? Musi przelecieć wszystkie wiersze, żeby sprawdzić wszystkie wartości. Dodatkowo LINQ ma pewien narzut, a więc Twoja wersja będzie wolniejsza niż zwykłe przelecenie wszystkich wierszy zwykłym forem.

Takie rzeczy się sprawdza podczas wypełniania DataGrida.

0
Juhas napisał(a):
cjancik napisał(a):

Ja do tego używam LINQ , przykladowo

var rowsIndex= dataGridView1.Rows.Cast<DataGridViewRow>()
                    .Where(r => int.Parse(r.Cells[indeks_kolumny_sprawdzanej_komórki].Value.ToString()) == 1)
                    .Select(r => r.Index).ToList();

Później przelatuje pętlą po elementach mojej listy i wiem gdzie ustawić wartość na readonly i nie muszę przeszukiwać wtedy wszystkich wierszy, przykładowo:

A jak myślisz, jak działa LINQ? Musi przelecieć wszystkie wiersze, żeby sprawdzić wszystkie wartości. Dodatkowo LINQ ma pewien narzut, a więc Twoja wersja będzie wolniejsza niż zwykłe przelecenie wszystkich wierszy zwykłym forem.

Takie rzeczy się sprawdza podczas wypełniania DataGrida.

hmmm....faktycznie nie wyłapałem tego przy ilości danych na których pracuje, dzięki za poprawkę. Lecę poprawiać kod.... :P

0
Juhas napisał(a):

Na jakiej podstawie rozróżniasz, czy wiersz ma być readonly, czy nie?

W DataGridView mam ukrytą kolumnę "widoczny" typu bool.
Gdy użytkownik korzysta z filtrowania jakie mu udostępniłem klasa automatycznie ustawia wartość w tej kolumnie.

Zastanawiam się nad tym czy gdyby ta kolumna była widoczna to byłbym w stanie znaleźć zdarzenie.
Gdyby wtedy nastąpiła zmiana w 1 wierszu na 10000000 mógłbym elegancko wychwycić tę zmianę i ustawić readonly dla jednego wiersza, a nie lecieć foreachem po wszystkich.

0

Zaraz... filtrowanie? Pokaż, jak filtrujesz, bo może wystarczy dodać tylko warunek.

0
Juhas napisał(a):

Zaraz... filtrowanie? Pokaż, jak filtrujesz, bo może wystarczy dodać tylko warunek.

Trochę za dużo kodu więc zacznę od początku :)
Planuje napisać aplikację mającą na celu wspomóc wystawiania korekt/zwrotów w programie Subiekt Insertu.

Idea jest prosta - po podaniu asortymentu i klienta zwracającego automatycznie pobieram z bazy wszystkie klienta dokumenty na których się się on znajdował.

Tak wygląda klasa która przechowuje informację o dokumencie.

public class Dokument
    {
        public event EventHandler OdswiezGridHandler;

        private int _id;
        private readonly int _magId;

        private decimal _wybranaIlosc;
        bool _widoczny = true;

        protected virtual void Odswiez()
        {
            if (OdswiezGridHandler != null)
                OdswiezGridHandler(this, EventArgs.Empty);
        }

        public Dokument(int id, string numer, DateTime data, int magId, decimal dostepnaIlosc, decimal cena, bool widoczny = true)
        {
            _id = id;
            Numer = numer;
            Data = data;
            _magId = magId;
            DostepnaIlosc = dostepnaIlosc;
            Cena = cena;
            Widoczny = widoczny;
            UstawSymbolMagazynu();
        }

        public void UstawSymbolMagazynu()
        {
            using (var con = new dbaseDataContext())
            {
                var symbol = (from x in con.sl_Magazyns
                                  where x.mag_Id == _magId
                                  select x.mag_Symbol).FirstOrDefault();
                MagSymbol = (symbol == "") ? "ERR" : symbol;
            }
        }

        public void UstawDostepna(decimal dostepna)
        {
            DostepnaIlosc = dostepna;
        }

        public int _Id()
        {
            return _id;
        }

        public int Id { set => _id = value; } 
        public string Numer
        {
            get;
        }
        public DateTime Data
        {
            get;
        }
        public string MagSymbol
        {
            get;
            private set;
        }
        public decimal Cena { get; set; }
        public decimal DostepnaIlosc
        {
            get;
            private set;
        }
        public decimal WybranaIlosc
        {
            get { return _wybranaIlosc; }
            set {
                if (value < 0)
                {
                    _wybranaIlosc = 0;
                    Odswiez();
                    return;
                }
                if (value > DostepnaIlosc)
                {
                    _wybranaIlosc = DostepnaIlosc;
                    Odswiez();
                    return;
                }
                _wybranaIlosc = value;
                Odswiez();
            }
        }
        public bool Widoczny
        {
            get { return _widoczny; }
            set
            {
                if(_widoczny && _wybranaIlosc != 0) _wybranaIlosc = 0;
                _widoczny = value;
                Odswiez();
            }
        }
    }

Klasa nadrzędna (do obsługi danej pozycji) tworzy listę obiektów dokument i binduje ją z DataGridView.

Gdy w klasie nadrzędnej wywołam metodę (np. skoryguj od najstarszego) ustawia ona pole WybranaIlosc dla każdego dokumentu od najstarszego dopóki suma wybranych ilości nie jest równa z wybraną. Wykonuje ona zwykły foreach na liście obiektów dokument i ustawia pole. Lista jest zbindowana z z Gridem więc automatycznie on reaguje na zmiany.
Chciałem teraz zastosować filtry bo nim użytkownik użyje automatycznego korygowania może chcieć wyłączyć część dokumentów (mające inny magazyn lub starsze niż).
Mógłbym wywalić z listy pozycje które zostały odfiltrowane, ale uznałem, że lepiej by pracownik widział jakie ma opcje.
Gdy uruchamiam filtrowanie ustawiając date klasa nadrzędna leci foreachem i ustawia pole Widoczny na false i już. Pole to zostało ukryte w gridzie bo zajmuje niepotrzebnie przestrzeń.

Załączam screen przedstawiający jak sobie wyobrażam UI do tego modułu.

0

W modelu, jaki wybrałeś do zrobienia tej aplikacji nie ma chyba innej opcji. Wszystko zawsze skończy się i tak przeleceniem przez wszystkie rekordy.
Relacyjna baza danych ma się nijak do programowania obiektowego. Relacje i dane to coś zupełnie innego niż obiekty. Dlatego nie jest łatwo połączyć jedno z drugim. Takie rzeczy można robić inaczej. W taki sposób, że wszystkie operacje wykonujesz na bazie danych, a potem pobierasz dane zwykłym selectem. Takie coś na pewno zadziała dużo szybciej.

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