Problem z przekazaniem wskaźnika na metodę pomiędzy w klasami

0

Witam, temat trochę długi i może na pierwszy rzut oka nie czytelny problem. Ale już tłumaczę o co dokładnie chodzi.
W aplikacji którą tworzę będzie spora ilość DataGridView dla różnych części systemu np. dla formatki odpowiedzialnej za zarządzanie użytkownikami, kontrahentami, itp. Zamieszczam również kod, może komuś się przyda, a może ktoś inny zauważy rażące błedy i zaproponuje ich rozwiązanie. Stworzyłem mini toolBox dla DataGridView, klasa 'ToolBoxDataGridView' udostępnia między innymi obrazki, które zmieniają np. wizualizację, kopiują zaznaczone elementy DataGridView, itp. Są tam również funkcje odpowiedzialne za tworzenie TextBox'ów odpowiedzialnych za filtrowanie wierszy DataGridView według kolumn... Formatka zarządzająca urzytkownikami pobiera metody do obsługi elementów z klasy SystemBase, klasa ta udostępnia wszystkie niezbędne jej metody między innymi: sb.FillUser(ref DataGridView dgw, ref Label lbl, List<TextBox> listTB); Dodatkowo formatka zarządzająca użytkownikami wywołuje klasę ToolBoxDataGridView. Problem zaczyna się w momencie gdy użytkownik wpisuje tekst do TextBox'ów, które sortują w zdarzeniu TextBox_Changed, nie mam wskaźnika do klasy SystemBase i metody FillUser. Czytałem o delegatach, ale nic co znalazłem nie ułatwiło mi rozwiązania problemu. W załączniku przesyłam print screna z formatki. Mógłbym oczywiscie przekazać oolBoxDataGridView dostęp do klasy SystemBase, ale jest to całkowicie nie porządane :/ Bo klas podobnych do SystemBase będzie kilka... wolałbym użyć delegata tylko na chwilę obecną w ogóle mi to nie wychodzi...

public class ToolBoxDataGridView
    {
        private DataGridView dgv = null;
        private ImageList image16x16 = null;
        private Panel p = null;

        private PictureBox pbSelectAll = new PictureBox();
        private PictureBox pbCopy = new PictureBox();
        private PictureBox picPrinter = new PictureBox();
        private PictureBox picPDF = new PictureBox();
        private PictureBox picXLS = new PictureBox();
        private PictureBox picSelectFullRow = new PictureBox();
        private PictureBox picBorder = new PictureBox();
        private PictureBox picTextBox = new PictureBox();

        private List<TextBox> lTb;

        private bool afterLoad = false;
        private int firstColumnVisable, lastColumnVisable = 0;
        private int shiftTextBox = 0;
        
        public void SetPanel(ref Panel p)
        {
            this.p = p;

            this.p.Controls.Add(pbSelectAll);
            this.p.Controls.Add(pbCopy);
            this.p.Controls.Add(picPrinter);
            this.p.Controls.Add(picPDF);
            this.p.Controls.Add(picXLS);
            this.p.Controls.Add(picSelectFullRow);
            this.p.Controls.Add(picBorder);
            this.p.Controls.Add(picTextBox);
        }

        public List<TextBox> GetListTextBoxForFiltrDataGridView()
        {
            return lTb;
        }

        public ToolBoxDataGridView(Point p, ImageList image16x16, ref DataGridView dgv, ref Panel panel, ref List<TextBox> lTb)
        {
            this.dgv = dgv;
            this.image16x16 = image16x16;
            this.p = panel;
            this.lTb = lTb;
            
            CreateTextBoxFiltrForDataGridView();

            pbSelectAll.Location = p;
            pbSelectAll.Size = new System.Drawing.Size(16, 16);
            pbSelectAll.Image = this.image16x16.Images["table_select_all.png"];
            pbSelectAll.TabIndex = 1;
            pbSelectAll.Visible = true;
            pbSelectAll.Click += new System.EventHandler(this.pbSelectAll_Click);
            this.p.Controls.Add(pbSelectAll);

            p.X += 22;

            pbCopy.Location = p;
            pbCopy.Size = new System.Drawing.Size(16, 16);
            pbCopy.Image = this.image16x16.Images["page_copy.png"];
            pbCopy.TabIndex = 2;
            pbCopy.Visible = true;
            pbCopy.Click += new System.EventHandler(this.pbpbCopy_Click);
            this.p.Controls.Add(pbCopy);

            p.X += 22;

            picPrinter.Location = p;
            picPrinter.Size = new System.Drawing.Size(16, 16);
            picPrinter.Image = this.image16x16.Images["printer.png"];
            picPrinter.TabIndex = 3;
            picPrinter.Visible = true;
            picPrinter.Click += new System.EventHandler(this.printer_Click);
            this.p.Controls.Add(picPrinter);

            p.X += 44;

            picPDF.Location = p;
            picPDF.Size = new System.Drawing.Size(16, 16);
            picPDF.Image = this.image16x16.Images["file_extension_pdf.png"];
            picPDF.TabIndex = 4;
            picPDF.Visible = true;
            picPDF.Click += new System.EventHandler(this.picPDF_Click);
            this.p.Controls.Add(picPDF);

            p.X += 22;

            picXLS.Location = p;
            picXLS.Size = new System.Drawing.Size(16, 16);
            picXLS.Image = this.image16x16.Images["file_extension_xls.png"];
            picXLS.TabIndex = 5;
            picXLS.Visible = true;
            picXLS.Click += new System.EventHandler(this.picXLS_Click);
            this.p.Controls.Add(picXLS);

            p.X += 44;

            picTextBox.Location = p;
            picTextBox.Size = new System.Drawing.Size(16, 16);
            picTextBox.Image = this.image16x16.Images["textfield_add.png"];
            picTextBox.TabIndex = 7;
            picTextBox.Visible = true;
            picTextBox.Click += new System.EventHandler(this.picTextBox_Click);
            this.p.Controls.Add(picSelectFullRow);

            p.X += 22;

            picSelectFullRow.Location = p;
            picSelectFullRow.Size = new System.Drawing.Size(16, 16);
            picSelectFullRow.Image = this.image16x16.Images["table_select_big.png"];
            picSelectFullRow.TabIndex = 6;
            picSelectFullRow.Visible = true;
            picSelectFullRow.Click += new System.EventHandler(this.picSelectFullRow_Click);
            this.p.Controls.Add(picBorder);
            
            p.X += 22;

            picBorder.Location = p;
            picBorder.Size = new System.Drawing.Size(16, 16);
            picBorder.Image = this.image16x16.Images["border_1.png"];
            picBorder.TabIndex = 7;
            picBorder.Visible = true;
            picBorder.Click += new System.EventHandler(this.picBorder_Click); 
            this.p.Controls.Add(picTextBox);

        }

        private void pbSelectAll_Click(object sender, EventArgs e)
        {
            this.dgv.SelectAll();
        }

        private void pbpbCopy_Click(object sender, EventArgs e)
        {
            if (this.dgv.SelectedRows.Count > 0)
            {
                DataObject data = this.dgv.GetClipboardContent();
                Clipboard.SetDataObject(data, true);
            }
        }

        private void printer_Click(object sender, EventArgs e)
        {
            
        }

        private void picPrinter_Click(object sender, EventArgs e)
        {

        }

        private void picPDF_Click(object sender, EventArgs e)
        {

        }

        private void picXLS_Click(object sender, EventArgs e)
        {
          
        }

        private void picSelectFullRow_Click(object sender, EventArgs e)
        {
            if (this.dgv.SelectionMode == DataGridViewSelectionMode.FullRowSelect)
            {
                this.dgv.SelectionMode = DataGridViewSelectionMode.CellSelect;
                this.picSelectFullRow.Image = this.image16x16.Images["table_select_row.png"];
            }
            else
            {
                this.dgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
                this.picSelectFullRow.Image = this.image16x16.Images["table_select_big.png"];
            }
        }

        private void picBorder_Click(object sender, EventArgs e)
        {
            switch (this.dgv.CellBorderStyle)
            {
                case DataGridViewCellBorderStyle.Sunken:
                    {
                        this.dgv.CellBorderStyle = DataGridViewCellBorderStyle.None;
                        this.picBorder.Image = this.image16x16.Images["border_1_none.png"];
                    }
                    break;
                case DataGridViewCellBorderStyle.None:
                    {
                        this.dgv.CellBorderStyle = DataGridViewCellBorderStyle.SingleHorizontal;
                        this.picBorder.Image = this.image16x16.Images["border_1_hor.png"];
                    }
                    break;
                case DataGridViewCellBorderStyle.SingleHorizontal:
                    {
                        this.dgv.CellBorderStyle = DataGridViewCellBorderStyle.Sunken;
                        this.picBorder.Image = this.image16x16.Images["border_1.png"];
                    }
                    break;
            }
        }

        private void picTextBox_Click(object sender, EventArgs e)
        {
            if (this.picTextBox.Name == "textfield_delete")
            {
                this.picTextBox.Image = this.image16x16.Images["textfield_add.png"];
                this.picTextBox.Name = "textfield_add";

                foreach (TextBox tb in this.lTb)
                {
                    tb.Visible = false;
                }
            }
            else
            {
                afterLoad = true;
                CheckLocationAndWidthTextBox();

                foreach (TextBox tb in this.lTb)
                {
                    tb.Visible = true;
                }

                this.picTextBox.Image = this.image16x16.Images["textfield_delete.png"];
                this.picTextBox.Name = "textfield_delete"; 
            }
        }

        private void CreateTextBoxFiltrForDataGridView()
        {
            int nextTextBoxLocationX = 0;

            for (int i = 0; i < dgv.ColumnCount; i++)
                if (dgv.Columns[i].Visible == true)
                {
                    TextBox tb = new TextBox();

                    if (nextTextBoxLocationX == 0)
                        nextTextBoxLocationX = dgv.Location.X + dgv.RowHeadersWidth;

                    tb.Location = new Point(nextTextBoxLocationX, dgv.Location.Y - 24);
                    tb.Name = dgv.Columns[i].Name;
                    tb.Width = dgv.Columns[i].Width - 1;
                    tb.Visible = false;
                    tb.TextChanged += new System.EventHandler(this.TextBox_Changed);
                    this.p.Controls.Add(tb);

                    this.lTb.Add(tb);

                    nextTextBoxLocationX += dgv.Columns[i].Width + 1;

                    // Wyznaczenie pierwszej widocznej tabeli
                    if (firstColumnVisable == 0)
                        firstColumnVisable = i;

                    // Wyznaczenie ostatniej widocznej tabeli
                    lastColumnVisable = i;
                }
        }

        private void CheckLocationAndWidthTextBox()
        {
            // Lokalna zmienna przechowująca przesunięcie dla poszczególnych TextBox'ów
            int localShiftTextBox = dgv.Location.X + dgv.RowHeadersWidth;

            // Pętla wyszukująca wszystkie kolumny dla których wartość Visible = true
            for (int i = 0; i < dgv.ColumnCount; i++)

                // Sprawdzenie czy wartość Visible kolumny = true
                if (dgv.Columns[i].Visible == true)

                    // Pętla wyszukująca wszystkie TextBox'y odpowiadające za filtrowanie danych
                    foreach (TextBox tb in lTb)
                    {
                        // Porównanie nazwy kolumny z nazwą TextBox'a
                        if (tb.Name == dgv.Columns[i].Name)
                        {
                            // Zmiana pozycji TextBox'a
                            tb.Location = new Point(localShiftTextBox, dgv.Location.Y - 24);
                            // Zmiana długości TextBox'a
                            tb.Width = dgv.Columns[i].Width - 1;

                            // Dodanie do wartości przesunięcia wartość TextBox'a dla którego wywołano zdarzenie
                            localShiftTextBox += dgv.Columns[i].Width + 1;
                        }
                    }
        }

        public void ChcengeWidthTextBox(string column_name)
        {
            // Sprawdzenie czy wczytano już cały DataGridView
            // Jeżeli tak algorytm ustawia długość poszczególnych TextBox'ów
            if (this.afterLoad == true)
            {
                // Sprawdzenie czy algorytm wykonuje dla pierwszego TextBox'a
                if (shiftTextBox == 0)
                {
                    // Zmienna 'shiftTextBox' przechowuje przesunięcie
                    // Początkowa wartość to DataGridView.Location.X (lokalizacja) +  DataGridView.RowHeadersWidth (margines)
                    shiftTextBox = dgv.Location.X + dgv.RowHeadersWidth;

                    // Sprawdzenie czy przesuwana kolumna nie jest pierwszą
                    // Jeżeli nie jest należy do wartości 'shiftTextBox' dodać długość wcześniejszych TextBox'ów
                    if (dgv.Columns[firstColumnVisable].Name != column_name)
                    {
                        // Pętla sumująca długości wcześniejszych TextBox'ów
                        // Działa do momentu natrafienia na kolumnę przesuwaną przez użytkownika
                        foreach (TextBox tb in this.lTb)
                        {
                            if (tb.Name == column_name)
                                break;
                            else
                                shiftTextBox += tb.Width + 2;
                        }
                    }
                }

                // Pętla wszykująca TextBox'a któego nazwa odpowiada nazwie kolumny dla której wywołano zdarzenie
                foreach (TextBox tb in this.lTb)
                {
                    // Sprawdzenie czy dla tego TextBox'a wywołano zdarzenie
                    if(tb.Name == column_name)
                    {
                        // Zmiana pozycji TextBox'a
                        tb.Location = new Point(shiftTextBox, dgv.Location.Y - 24);
                        // Zmiana długości TextBox'a
                        tb.Width = dgv.Columns[column_name].Width - 1;

                        // Dodanie do wartości przesunięcia wartość TextBox'a dla którego wywołano zdarzenie
                        shiftTextBox += dgv.Columns[column_name].Width + 1;
                    }
                }
            }

            if (dgv.Columns[column_name].Index == lastColumnVisable)
                shiftTextBox = 0;

            // Do ustalenia ostatniego widocznego kolumny
            // MessageBox.Show(dgv.Columns[column_name].Index.ToString());
        }

        private void TextBox_Changed(object sender, EventArgs e)
        {
            //TextBox tb = (TextBox) sender;
            //MessageBox.Show(tb.Name.ToString() + " " + tb.Text);
            
        }
    }
0

Może na początek jakoś wnikliwie nie analizowałem twojego kodu, na pierwszy rzut oka wygląda przyzwoicie.
Rozwiązań jest kilka:

  1. wszystkie klasy takie jak SystemBase będą implementowały jakiś wspólny interfejs, a ToolBoxDataGridView dostanie taki obiekt implementujący interfejs i będzie na min działało
  2. ToolBoxDataGridView będzie miało zdarzenie FiltersChanged i/lub FiltersChanging i w TextBox_Changed będzie ono rzucane, z odpowiednimi argumentami, natomiast formatka podepnie się pod to zdarzenie i kiedy ono wystąpi będzie umiało odpowiednio wywołać jakąś metodę z SystemBase
  3. ToolBoxDataGridView może wywoływać jakiś delegat w TextBox_Changed, którym będzie metoda z SystemBase, ale do jest podobna sytuacja do 1), bo wszystkie klasy jak SystemBase będą musiały mieć metodę o takiej samej definicji, pasującej do delegata

Pewnie masz kłopot jak zastosować delegaty. Jeśli chodzi o wywoływanie metod, możesz zastosować istniejące generyczne delegaty Func i Action. Func zwraca wartość, a Action nie (czyli metoda ma void zamiast zwracanego typu).
Przykład:

class Class1
{
  private Func<int,bool> _func1;

  public Class1(Func<int,bool> func1)
  { 
    _func1 = func1;
  }

  private void TextBox_Changed(...)
  {
    if (_func1 != null)
      bool result1 = _func1(10);
  }
}

Czyli najprościej ujmując, delegat to jakby wzór metody, czyli jakie parametry przyjmuje oraz jaki typ zwraca.

0

osobiście polecam rozwiązania 1) albo 2)
charakter Twojego problemu wskazuje na to, ze jest to problem "architektury", wiec rozwiazanie lepiej bedzie ubrac w "tradycyjny", dobrze ustalony i samoopisujacy sie kształt.
wykorzystanie delegatow jako zwrotnych callbackow kusi prostotą użycia i minimalizmem kodu do napisania, ale potem moga zaczac sie problemy, gdy nagle po paru podobnych rzeczach zaczna Ci sie pojawiac metody/konstruktory pobierajace po pięć Func<string> Action<int> Func<double,string[]> i wtedy powoli zaczyna się tesknić za zwyklym prostym interfejsem opisujacym grupe potrzebnych callbackow.. :)

edit: nie żebym miał cos do Func<> i Action<>, korzystam z nich nałogowo, wrecz czasem aż nadto. pisze tak z doswiadczenia i dobrej woli, gdyz juz zdazalo mi sie popełniać klasy algorytmo/workflowo-podobne, wymagajace do swojej pracy podania im >7dmiu delegatow, a ot tak bo stwierdzilem ze mozna abstrahowac od czytania property stringName, to wiec Func<TArg, string> zamiast niego... Oj, łatwo zrobic fajny kod, ktory tylko Ty dasz rade odczytac za 2 miesiace:)

0

Swoją drogą Bert1223 ma w ogóle błędną koncepcje, bo zobacz że ToolBoxDataGridView to zwykła klasa, a nie kontrolka. Zobacz też co przyjmuje w konstruktorze: ref DataGridView dgv, ref Panel panel, ref List<TextBox> lTb. Swoją drogą ref jest zbędne.
@Bert1223 proponuję żebyś zaprojektował popraną kontrolkę z dodatkowymi przyciskami, texbboxami filtrów oraz w sobie z gridem, która przyjmie jakiś obiekt implementujący interfejs, który umożliwi ci pobieranie/modyfikowanie/usuwanie danych. Sama kontrolka będzie umiała filtrować dane na poziomie grida oraz eksportować je do excela, pdf.
Lub dwie kontrolki. Jedna z filtrami (textbox'y) i gridem oraz druga z przyciskami do eksportu etc.
Oczywiście nadal obiekt dostarczający dane dla tych kontrolek powinien być jakąś abstrakcją, implementować interfejs, aby ten sam formularz z kontrolkami zadziałał dla każdego źródła danych.

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