[C#] Hoe een form element benaderen vanuit een andere class

Pagina: 1
Acties:
  • 438 views sinds 30-01-2008
  • Reageer

  • 4of9
  • Registratie: Maart 2000
  • Laatst online: 15:52
Hallo,

Ik ben redelijk nieuw met het OO programmeren en bezig met een projectje in C#.

Nu heb ik een winform applicatie met wat buttons en een datagrid.
ook heb ik een statusbar met 2 panels. (export.cs)

Nu heb ik ook een xmlclass om xml files te schrijven, (xml.cs) alleen nu wil ik de statusbar updaten met bepaalde informatie vanuit die xml class.

Hoe kan ik die statusbar benaderen vanuit de xml class (of liever gezegd hoe moet dat syntactisch gezien)

Als ik xml.cs laat erven van export zegt de compiler dat statusbar1 protected is dus hoe moet ik dat element nu accessen?

thx alvast!

Aspirant Got Pappa Lid | De toekomst is niet meer wat het geweest is...


  • pjvandesande
  • Registratie: Maart 2004
  • Laatst online: 14:49

pjvandesande

GC.Collect(head);

Ik zou in je xmlclass event proppen en deze in je form wiren. Dus iets van een StatusMessageEvent ofzo en dan in dat event je statusbar update.

  • whoami
  • Registratie: December 2000
  • Laatst online: 16:05
Maak een event aan in je XmlClass die je aanroept als er iets gebeurt.

In jouw geval kan je dus een event OnStatusChanged oid gaan maken in je class:

code:
1
2
3
4
class XmlClass
{
     public event EventHandler StatusChanged;
}


(Nu maak je een event van het type EventHandler, waarmee je misschien wel wat beperkt bent. Misschien is het dus beter om je eigen delegate te gaan maken:
code:
1
public delegate void MyOwnEventHandler(object sender, string message);

Je kan dan dus dit type gaan gebruiken voor jouw event.

In je XmlClass maak je dan ook een method waarmee je die event kunt gaan triggern:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
class XmlClass
{
     public event MyOwnEventHandler StatusChanged;


     protected void InvokeStatusChanged(string statusText)
     {
             if( this.StatusChanged != null )
             {
                     this.StatusChanged(this, statusText);
             }
     }
}


Zo, nu is je XmlClass klaar. Het enige wat je nu nog moet doen, is in de form waarin je die class gebruikt, een method te gaan koppelen aan je eigen event (StatusChanged).
Die method moet voldoen aan de 'signature' die je gespecifeerd hebt in je delegate definitie:

code:
1
2
XmlClass myXmlObj = new XmlClass();
myXmlObj.StatusChanged += new MyOwnEventHandler(this.UpdateStatusBar);


De UpdateStatusBar method in je form ziet er dan dus bv zo uit:
code:
1
2
3
4
public void UpdateStatusBar(object sender, string displayMessage)
{
     this.myStatusBar.Text = displayMessage;
}

https://fgheysels.github.io/


  • 4of9
  • Registratie: Maart 2000
  • Laatst online: 15:52
thx voor de uitleg, hier heb ik erg veel aan.
ik ga het meteen ff proberen!

Aspirant Got Pappa Lid | De toekomst is niet meer wat het geweest is...


  • whoami
  • Registratie: December 2000
  • Laatst online: 16:05
Owja, nog wat vergeten:
in je XmlClass moet je natuurlijk ook nog je event gaan triggeren om je statusbar te gaan updaten:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class XmlClass
{
      ...
      public void DoWork()
      {
            ...
            // Open Xml File
            InvokeOnStatusChanged("Opening xml file...");
            ..
            // Processing
            InvokeOnStatusChanged("Processing file..."); 
            ...
      }
}


Code is uit de losse hand getyped, dus er zullen wel wat foutjes enzo inzitten, maar je zou het idee wel moeten snappen...

https://fgheysels.github.io/


  • 4of9
  • Registratie: Maart 2000
  • Laatst online: 15:52
oke ik ben al een eind op weg.

moet ik nu zowel
code:
1
public event MyOwnEventHandler StatusChanged;


als

code:
1
public delegate void MyOwnEventHandler(object sender, string message);


zetten?

de compiler kan namelijk MyOwnEventHandler niet vinden in de form.

Aspirant Got Pappa Lid | De toekomst is niet meer wat het geweest is...


  • whoami
  • Registratie: December 2000
  • Laatst online: 16:05
Owja, als je het heel veilig wilt maken als je gebruik maakt van multi-threading, dan moet je wel ff checken in je InvokeOnStatusChanged method of je die method zomaar kunt aanspreken of, als je eerst een context switch moet doen.

Dit kan je doen door te checken wat het 'target' van de delegate is, en als het 'target' een Windows Control is, dan zal je er moeten voor zorgen dat die method aangeroepen wordt in de context van de thread die die control gecreeërd heeft (meestal de main thread).

Concreet:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
protected void InvokeOnStatusChanged ( string messageText )
{
   if( StatusChanged != null )
   {
       System.Windows.Control c = StatusChanged.Target as System.Windows.Control;

       if( c == null )
       {
             StatusChanged(this, messageText);
       }
       else
       {
              c.Invoke(StatusChanged, new object[] {messageText});
       }
   }
}

https://fgheysels.github.io/


  • whoami
  • Registratie: December 2000
  • Laatst online: 16:05
4of9 schreef op dinsdag 07 december 2004 @ 11:03:
oke ik ben al een eind op weg.

moet ik nu zowel
code:
1
public event MyOwnEventHandler StatusChanged;


als

code:
1
public delegate void MyOwnEventHandler(object sender, string message);


zetten?

de compiler kan namelijk MyOwnEventHandler niet vinden in de form.
Hoe bedoel je ?

Die beide lijnen code moet je er idd zetten, echter die delegate is een type, dus dat moet je buiten je XmlClass zetten.

https://fgheysels.github.io/


  • 4of9
  • Registratie: Maart 2000
  • Laatst online: 15:52
ah oke thx het werkt!

nu moet ik alleen tijdens het writen van de xmlfile zelf op ieder punt dat ik een status wil weergeven een InvokeStatusChanged doen.

Is er ook een manier om bijvoorbeeld automatisch de status weer te geven als ik de methode aanroep waarvan ik de status messages wil laten zien?

(een link of tutorial is ook oke hoor :) )

ik ben helaas nog niet op het niveau om multithreading te gaan gebruiken, dus is dat checken echt nodig? en zo ja waarom? thx again!

Aspirant Got Pappa Lid | De toekomst is niet meer wat het geweest is...


  • whoami
  • Registratie: December 2000
  • Laatst online: 16:05
4of9 schreef op dinsdag 07 december 2004 @ 11:16:

Is er ook een manier om bijvoorbeeld automatisch de status weer te geven als ik de methode aanroep waarvan ik de status messages wil laten zien?
Hoe bedoel je ?

https://fgheysels.github.io/


  • 4of9
  • Registratie: Maart 2000
  • Laatst online: 15:52
in de xmlTextWriter class zit een property "writestate"

iedere keer als ik nu in mijn writeXML method een statusupdate wil laten zien, moet ik die invokeStatusChange aanroepen.

Ik zoek een manier om tijdens het uitvoeren van het programma, automatisch status messages laten zien (in de volgorder van doorlopen van het programma) als dat mogelijk is.

Aspirant Got Pappa Lid | De toekomst is niet meer wat het geweest is...


  • pjvandesande
  • Registratie: Maart 2004
  • Laatst online: 14:49

pjvandesande

GC.Collect(head);

Lees anders dit ook is event.

InvokeEventName vind ik niet zo netjes, op MSDN vertellen ze je OnEventName te gebruiken.

  • bigbeng
  • Registratie: Augustus 2000
  • Laatst online: 26-11-2021
4of9 schreef op dinsdag 07 december 2004 @ 11:23:
in de xmlTextWriter class zit een property "writestate"

iedere keer als ik nu in mijn writeXML method een statusupdate wil laten zien, moet ik die invokeStatusChange aanroepen.

Ik zoek een manier om tijdens het uitvoeren van het programma, automatisch status messages laten zien (in de volgorder van doorlopen van het programma) als dat mogelijk is.
Alleen jouw XMLClass kan toch weten wanneer er een status change is? Laat ik het anders stellen, waar zou een andere class de informatie over de status van jouw XMLClass kunnen opvragen?

IMHO moet een processing class altijd degene zijn die dmv events de aanroeper laat weten hoe het ervoor staat.

  • 4of9
  • Registratie: Maart 2000
  • Laatst online: 15:52
bigbeng schreef op dinsdag 07 december 2004 @ 11:33:
[...]


Alleen jouw XMLClass kan toch weten wanneer er een status change is? Laat ik het anders stellen, waar zou een andere class de informatie over de status van jouw XMLClass kunnen opvragen?

IMHO moet een processing class altijd degene zijn die dmv events de aanroeper laat weten hoe het ervoor staat.
Ja zo wil ik het ook, alleen lijkt het me niet "netjes" om iedere keer handmatig te bepalen wanneer dat er een statuschange plaatsvind.

In het geval van de writestate van de xmlwriter class vind bij iedere stap een writestate verandering plaats.

Mijn vraag is nu, als ik de writeXML method toevoeg, hoe zorg ik er dan voor dat er zoiets als dit uitgevoerd word (als dat al kan)

pseudo code
code:
1
2
3
4
5
6
7
8
9
public void writeXML()
{
  ...
  //open xmlfile en schrijf weg

  //laat tijdens uitvoeren de status zien
  if(xmlwriter.WriteState= veranderd)
   OnStatusChange(xmlwriter.WriteState.ToString());
}


zoiets dus.
zoals ik al zei, OO is voor mij redelijk nieuw dus vandaar mijn stortvloed aan vragen, ondanks dat ik met een boek op mijn schoot zit ;)

Aspirant Got Pappa Lid | De toekomst is niet meer wat het geweest is...


  • whoami
  • Registratie: December 2000
  • Laatst online: 16:05
4of9 schreef op dinsdag 07 december 2004 @ 11:40:
[...]


Ja zo wil ik het ook, alleen lijkt het me niet "netjes" om iedere keer handmatig te bepalen wanneer dat er een statuschange plaatsvind.
Alleen jouw class kan dat weten.
In het geval van de writestate van de xmlwriter class vind bij iedere stap een writestate verandering plaats.
Moest die XmlWriter nu een event hebben dat getriggered wordt als de WriteState veranderd, dan zou je daar wat mee kunnen aanvangen.

[quote]
Mijn vraag is nu, als ik de writeXML method toevoeg, hoe zorg ik er dan voor dat er zoiets als dit uitgevoerd word (als dat al kan)
Aangezien die XmlTextWriter dus geen event heeft dat je kan gebruiken, AFAIK niet.

https://fgheysels.github.io/


  • 4of9
  • Registratie: Maart 2000
  • Laatst online: 15:52
oke ik snap, dus als een method of property een event heeft dan kan ik het automatiseren ander moet ik het gewoon handmatig doen.

ik ben al weer een stuk wijzer :D

Aspirant Got Pappa Lid | De toekomst is niet meer wat het geweest is...


  • 4of9
  • Registratie: Maart 2000
  • Laatst online: 15:52
een klein vraagje nog.

In mijn form class maak ik een instantie aan van de DataBaseClass.

Nu werkt dat prima, ik maak deze aan samen met de Class members.

Maar wat is nu de goede plek om deze DataBaseClass aan te maken.
Mijn gedachte was namlijk in de constructor van de form class, alleen begint de compiler dan te roepen dat de instantie van de DataBaseClass nog niet bestaat.

ik gebruik deze namelijk in een method.
In de constructor worden ook eventhandlers toegevoegd die naar de DataBaseClass verwijzen.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
namespace iets
{
  Class FormClass
  {
     
     public FormClass()
     {
       // Hier?
      // DatBaseClass DB = new DataBaseClass();

      DB.StatusChanged += new getDataEventHandler(this.UpdateStatusBar);
     }

    private void fillDataSet(string sp)
    {
      hours = DB.getData(sp);
    }


     private void Button1_Click()
     { 
        fillDataSet(sp);
        //doe wat met dataset enzo

     }

    // waarom hier en niet in de constructor?
    DatBaseClass DB = new DataBaseClass();

  }
}



ondanks dat het werkt snap ik niet helemaal waarom het niet in de constructor kan?

Bedankt weer!

Aspirant Got Pappa Lid | De toekomst is niet meer wat het geweest is...


  • whoami
  • Registratie: December 2000
  • Laatst online: 16:05
Je kan je DataBaseClass wel initializeren in je constructor, maar, je moet ze wel declareren op je form level:

code:
1
2
3
4
5
6
7
8
9
10
class MyForm
{
     private DataBaseClass DB;

     public MyForm()
     {
          // Constructor
          DB = new DataBaseClass();
     }
}

https://fgheysels.github.io/


  • 4of9
  • Registratie: Maart 2000
  • Laatst online: 15:52
oke dank je.

Waarom moet dat in de contructor op die manier?

en wat is de meest nette manier om het te doen?
in de constructor of gewoon zoals ik het nu doe?

thx! ik leer vandaag een hoop meer dan uit zo'n boek lezen/overtikken....

Aspirant Got Pappa Lid | De toekomst is niet meer wat het geweest is...


  • whoami
  • Registratie: December 2000
  • Laatst online: 16:05
De plaats waar je je variable declareert, bepaalt de scope van die variable.

Als je een variable op form - niveau declareert, bestaat die waarde voor je hele form.
Declareer je een variable binnen een functie/method, dan bestaat die variable enkel binnen die method. (Een constructor is ook een method).
Aangezien je die DataBase class waarschijnlijk zo een beetje overal in je form nodig zult hebben, zal je hem dus op 'Form niveau' moeten declareren.
Je moet 'm dan natuurlijk ook nog initializeren, en dat kan je dan doen in je constructor, of direct bij de declaratie.

https://fgheysels.github.io/


  • 4of9
  • Registratie: Maart 2000
  • Laatst online: 15:52
oke thx!

Ik dacht dat de constructor een speciale method was waar niet hetzelfde opging als voor andere methods, vandaar deze verwarring!

Aspirant Got Pappa Lid | De toekomst is niet meer wat het geweest is...


  • riezebosch
  • Registratie: Oktober 2001
  • Laatst online: 13-04 14:28
Nu wil ik graag m'n logica beetje van m'n gui scheiden. Is het dan verstandig het openen en opslaan van bestanden een laag dieper te brengen? En moet ik dan ook op dezelfde manier de listview met gegevens vullen zoals hierboven aangegeven?

Canon EOS 400D + 18-55mm F3.5-5.6 + 50mm F1.8 II + 24-105 F4L + 430EX Speedlite + Crumpler Pretty Boy Back Pack


  • whoami
  • Registratie: December 2000
  • Laatst online: 16:05
riezebosch schreef op dinsdag 07 december 2004 @ 16:55:
Nu wil ik graag m'n logica beetje van m'n gui scheiden. Is het dan verstandig het openen en opslaan van bestanden een laag dieper te brengen? En moet ik dan ook op dezelfde manier de listview met gegevens vullen zoals hierboven aangegeven?
Ik zou m'n gegevens ophalen dmv een 'data access component', en die component die gegevens laten returnen. In je GUI kan je dan die component aanspreken, de gegevens verkrijgen en je ListView gaan inlezen.
Je mag het inlezen van de listview zeker niet over laten aan een component die 'dieper' zit, aangezien die componenten eigenlijk niets mogen afweten van de GUI, anders kan je die componenten nooit makkelijk gaan 'hergebruiken' in een andere GUI.

zo dus:
code:
1
2
3
4
5
6
7
8
9
10
11
12
private ButtonLoad_Click( object sender, EventArgs e )
{

    // dit is dus een method in je windows applicatie.

    // Roep je 'data access component aan', en verkrijg de gegevens.
    myCustomerCollection = customerDataAccessComponent.GetCustomers();
     
     // Laad de ListView in met gegevens die in de myCustomerCollection zitten.
     this.LoadCustomerListView (myCustomerCollection);

}


Wat het openen en sluiten en writen naar bestanden betreft: die kan je best in een andere component gaan plaatsen, mits je aan die component doorgeeft waar hij de bestanden moet plaatsen of kan vinden.
Zorg er ook voor dat die component steeds de bestanden sluit als ie ze niet meer nodig heeft (try/finally clause).

[ Voor 14% gewijzigd door whoami op 07-12-2004 17:00 ]

https://fgheysels.github.io/


  • Bint
  • Registratie: Juli 2002
  • Laatst online: 11:18
Sorry voor deze kick, maar ik heb een probleem met dit voorbeeld hier:

Ik heb dit:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Form1 : System.Windows.Forms.Form
    {
        private System.Windows.Forms.ListBox listBox1;
        private System.Windows.Forms.Button button1;
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;
        
        private Class1 bla;
        public delegate void MyOwnEventHandler(object sender, string msg);
<snip>
}

C#:
1
2
3
4
5
        private void button1_Click(object sender, System.EventArgs e)
        {
            bla = new Class1();
            bla.StatusChanged += new MyOwnEventHandler();
        }


in class.cs heb ik het volgende:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
using System;
using System.Threading ;

namespace WindowsApplication3
{
    /// <summary>
    /// Summary description for Class1.
    /// </summary>
    public class Class1
    {
        int i;
        public event MyOwnEventHandler StatusChanged;

        protected void InvokeOnStatusUpdated(string msg)
        {
            if (this.StatusChanged != null)
            {
                System.Windows .Control c = StatusChanged.Target as System.Windows.Control;

                if (c==null)
                {
                    StatusChanged (this, msg);
                }
                else
                {
                    c.Invoke(StatusChanged, new object []{msg});
                }
            }
        }

        public Class1()
        {
            Thread bla = new Thread(new ThreadStart(blaat));
        }

        public void blaat()
        {
            i++;
            InvokeOnStatusChanged("Bla");
        }

    }
}


als ik compileer krijg ik de volgende foutmelding:

Class1.cs(12): The type or namespace name 'MyOwnEventHandler' could not be found (are you missing a using directive or an assembly reference?)
Maar ik kom er dus niet uit! Ik heb al gegoogled, maar ik kom er echt niet uit:(

PS. Ik gebruik visual studio 2003 (geen 2005 dus, als dat al verschil uitmaakt)

Ik heb zoiets een tijdje geleden ook al gevraagd, maar was er door tijdgebrek niet meer aan toegekomen. Die threads nog wel doorgenomen, maar ik kom er echt niet uit :( :( :'(

Memories of yesterday, will grow, but never die


  • Bint
  • Registratie: Juli 2002
  • Laatst online: 11:18
Laat maar,
ben er eindelijk achter! Ben nu echt blij dat ik het eindelijk een keer doorheb!

Alleen nog een vraagje:

Is de code die hier dus was gegeven, de juiste manier om objecten op het form te veranderen//te updaten? Of is er ook nog een nettere manier hiervoor?

Memories of yesterday, will grow, but never die

Pagina: 1