[ perun85 @ 24.09.2008. 21:06 ] @
Imam dva forme, Form1 na kojoj se nalazi dataGridView1, i Form2 pomocu koga unosim podatke u samu bazu. Naravno nakon unosa podaci se ne prikazuju u dataGridView1 na prvoj formi. Posto sam video da dosta ljudi ima problema sa ovim na netu, i da je najkoriscenije resenje ponovno pozivanje Fill metoda DataAdaptera, interesuje me postoji li neko funkcionalnije resenje?
Pored toga zanima me kako da pozovem public metod iz klase Form1 kada je vezan za anonimni objekat pocetne forme aplikacije, na koji se ne moze referencirati njegovim imenom (taj metod bi pozivao iz klase Form2 i on bi mi osvezavao dataGridView1)?

Hvala na pomoci.
[ marko1981 @ 25.09.2008. 00:35 ] @
Jedan od nacina je da glavnu formu, neka bude da je to klasa MainForm, koristis kao singleton i da joj tako pristupas iz forme Form1 (neka bude klasa FormView) i Form2 (neka bude klasa FormEdit).

Postoji dosta raznih implementacija singleton-a, ova koju sam ubacio je verovatno najjednostavnija i bezbedna u smislu thread-safe za ovo sto ti treba jer pretpostavljam da neces kreirati instancu MainForm nikad osim na pocetku u Program.cs (po default-u).

Opsirnije o nacinima implementacije singleton-a na http://www.yoda.arachsys.com/csharp/singleton.html.


Slede delovi koda:

Code:

namespace MyApplication;

public MainForm : Form
{
    public MainForm()
    {
       instance = this;
       ...
       ...
       ...
    }

    public static MainForm Instance
    {
        get
        {
            return instance;
        }
    }

    public FormView FrmView
    {
        get
        {
            return frmView;
        }
    }

    public FormEdit FrmEdit
    {
        get
        {
            return frmEdit;
        }
    }

    private static MainForm instance = new MainForm();
    private FormView frmView = null;
    private FormEdit frmEdit = null;
}


Pretpostavljam da iz glavne forme kreiras i prikazujes (Show) instance ove dve forme i to neka budu ove dve privatne promenljive u njoj.

Zatim, u kodu forme FormView ubaci jednu public metodu (i jedan delegat ako su ti potrebni parametri za metodu koja osvezava DataGridView)

Code:

public FormView : Form
{
   ...
   ...
   ...

   // varijanta bez parametara

   public void RefreshDataGridView()
   {
      // radis ovako da bi metoda bila thread-safe (da bi dataGridView1 pozivao iz iste niti iz koje je kreirana)
      if (base.InvokeRequired == true)
      {
          base.BeginInvoke(new MethodInvoker(RefreshDataGridView), new object[] { });
      }
      else
      {
          //
          // ovde ubaci kod kojim osvezavas DataGridView u ovoj formi
          //
          // odavde mozes da "vidis" formu FrmEdit ako treba, koristeci MainForm.Instance.FrmEdit, a time i sve njene public field-ove i metode
          //
      }
   }


   // varijanta sa parametrima (ovo je samo primer ako su 2 parametra, jedan int i jedan string)

   public void RefreshDataGridView(int param1, string param2)
   {
      if (base.InvokeRequired == true)
      {
          base.BeginInvoke(new RefreshDataGridViewHandler(RefreshDataGridView), new object[] { param1, param2});
      }
      else
      {
          //
          // ovde ubaci kod kojim osvezavas DataGridView u ovoj formi i u kome koristis parametre
          //
          // odavde mozes da "vidis" formu FrmEdit ako treba, koristeci MainForm.Instance.FrmEdit, a time i sve njene public field-ove i metode
          //
      }
   }

   private void delegate RefreshDataGridViewHandler(int par1, string par2);
}


Ovako si dobio metodu koju si trazio, a koja bi osvezavala dataGridView1 tako sto bi je iz koda forme FrmEdit pozivao sa

Code:

MainForm.Instance.FrmView.RefreshDataGridView();

// odnosno sa

MainForm.Instance.FrmView.RefreshDataGridView(param1, param2);


(Pretpostavka je da su sve 3 forme u istom namespace-u)


Jedan od jednostavnih nacina kako mozes ovo iskoristiti je da u formi FrmView imas neku promenljivu koja ce ti biti DataSource za ovaj DataGridView (na primer DataTable) i da tu promenljivu menjas cim promenis nesto u FrmEdit, pa ce ti se i DataGridView "automatski" azurirati.

Primer koda:

U FrmView:

Code:

private DataTable dataSource = new DataTable();

// negde u kodu (recimo u konstruktoru ili pri inicijalizaciji kad vec imas strukturu dataSource-a u smislu kolona), stavis
this.dataGridView1.DataSource = this.dataSource;

// a u metodi RefreshDataGridView mozes da postavljas this.dataSource citajuci sta ti treba iz FrmEdit 
// ili da prosledis DataTable kao parametar u kom slucaju bi koristio delegat
private delegate void RefreshDataGridViewHandler(DataTable dataTable) 

// i u skladu sa tim modifikujes potpis i metodu RefreshDataGridView.



U svakom slucaju, koristeci MainForm instancu kao singleton, mozes iz FrmView pozivati/menjati sta ti treba u FrmEdit i obrnuto koristeci public metode preko

Code:

MainForm.Instance.FrmView.SomePublicMethod

// odnosno

MainForm.Instance.FrmEdit.SomePublicMethod


tako da ces naci nacin koji najvise odgovara potrebama aplikacije.


Pozdrav.
[ perun85 @ 25.09.2008. 11:57 ] @
Sto se tice osvezavanja DataGridView-a radio sam ga na nacin koji si opisao, no mislio sam da neko mozda ima i bolje resenje od ovoga ili ponovnog pozivanja Fill metode DataAdaptera.
Drugi problem cu resiti ovako kako si objasnio, pomocu singletona.
Puno ti hvala na brzom i opsirnom odgovoru.

[Ovu poruku je menjao perun85 dana 25.09.2008. u 13:10 GMT+1]
[ Csharp @ 26.09.2008. 13:27 ] @
Ne bih otvarao novu temu, jer moje pitanje ima veze sa ovim,... :-)


Naime, a kako bih mogao napraviti refresh ako imam dva klijenta i jedan klijent napravi neku promjenu u tablici, a da drugi klijent odmah to vidi? :-)


Moja ideja je recimo da imam neku pomoćnu tablicu koja bi imala timestamp, id klijenta, ime tablice koja se mijenjala i klijent svako malo provjerava da li je bilo kakvih promjena od drugih klijenata. Ako je, da onda refresh-am tablice koje su "aktivne".....


Ima li tko bolju ideju?
[ perun85 @ 27.09.2008. 22:03 ] @
Evo danas sam nasao vremena da poradim na ovoj svojoj aplikaciji i suocio sam se sa problemom. Naime, nisam uspeo da implementiram sigleton pattern u svojoj aplikaciji na nacin na koji je Marko objasnio. Na kraju sam napravio projekat sa svim gore navedenim klasama i jednostavnom metodom koja bi trebala da promeni Label u objektu frmView no ni tada nije uspelo, jer uopste nisam uspeo da izvrsim Show() metod za frmView i frmEdit objekte. (pretpostavljam da sam prevideo nesto)

Pozdrav
[ marko1981 @ 27.09.2008. 22:43 ] @
Evo ceo kod (bez designer-generated koda koji je nebitan) za jednostavan projekat sa 3 forme: MainForm, FormEdit i FormView.

Klikom na Button na FrmEdit string iz TextBox-a se prepisuje u TextBox forme FormView.

Screenshot je ukljucen.

[att_img]

MainForm.cs:

Code:

  public partial class MainForm : Form
  {
    public MainForm()
    {
      instance = this;

      this.frmEdit = new FormEdit();
      this.frmView = new FormView();

      InitializeComponent();
    }

    public static MainForm Instance
    {
      get
      {
        return instance;
      }
    }

    public FormView FrmView
    {
      get
      {
        return frmView;
      }
    }

    public FormEdit FrmEdit
    {
      get
      {
        return frmEdit;
      }
    }

    private void btnShowFormView_Click(object sender, EventArgs e)
    {
      if (this.frmView == null)
      {
        this.frmView = new FormView();
      }

      this.frmView.Show();
    }

    private void btnShowFormEdit_Click(object sender, EventArgs e)
    {
      if (this.frmEdit == null)
      {
        this.frmEdit = new FormEdit();
      }

      this.frmEdit.Show();
    }

    private static MainForm instance = null;
    private FormView frmView = null;
    private FormEdit frmEdit = null;
  }


FormEdit.cs:

Code:

  public partial class FormEdit : Form
  {
    public FormEdit()
    {
      InitializeComponent();
    }

    private void btnSet_Click(object sender, EventArgs e)
    {
      MainForm.Instance.FrmView.SetText(this.txtEdit.Text);
    }
  }


FormView.cs:

Code:

  public partial class FormView : Form
  {
    public FormView()
    {
      InitializeComponent();
    }

    public void SetText(string text)
    {
      if (base.InvokeRequired == true)
      {
        base.BeginInvoke(new StringHandler(SetText), new object[] { text });
      }
      else
      {
        this.txtView.Text = text;
      }
    }

    private delegate void StringHandler(string s);
  }
[ perun85 @ 28.09.2008. 11:27 ] @
Marko izvini, nasao sam gde sam bio pogresio (umesto instance stavio sam Instance, a compiler nije prijavio gresku), a zaboravio sam ostaviti novi post. Sada sve radi odlicno. Hvala ti jos jednom na pomoci retko ko bi se bas toliko potrudio da pomogne nekome.