Avatar billede keepy Seniormester
21. marts 2011 - 09:58 Der er 34 kommentarer og
1 løsning

Tråde textbox1

Hej

Jeg kan ikke opdater en textbox i en anden klasse.
JEg tror det har noget med at jeg ikke er i samme tråd, men hvordan skal det lige løses. ?? nedenstående kode kan jeg ikke få til at virke

Class Form 1
{
private void UpdateText(String logdata)//
        {
           
            textBox1.Text = logdata;
        }


}

Class Modem
{
public delegate void UpdateTextCallback(string text);

TextBox1.Invoke(new UpdateTextCallback(this.UpdateText),new object[]{"Text generated on non-UI thread."});
}
Avatar billede keepy Seniormester
21. marts 2011 - 10:10 #1
JEg vil gerne skrive til textbox1 fra Modem klassen
Avatar billede aaberg Nybegynder
21. marts 2011 - 10:18 #2
Prøv at ændre din UpdateText metode til dette:


private void UpdateText(String logdata)//
{
    this.Invoke(new MethodInvoker(delegate()
        {
            textBox1.Text = logdata;
        }));

}
Avatar billede aaberg Nybegynder
21. marts 2011 - 10:18 #3
Invoke metoden sætter en delegate til at køre i formens egen tråd.
Avatar billede keepy Seniormester
21. marts 2011 - 12:56 #4
ok super

Men hvordan skriver jeg til metoden fra modem klassen??

Jeg tror ikke det jeg har skrevet i Modem klassen er rigtigt?
Avatar billede aaberg Nybegynder
21. marts 2011 - 14:01 #5
For at kunne opdatere formen fra din Modem klasse, bliver du nød til at oprette en reference til formen i Modem klassen. Dette kan for eksempel være en property som bliver sat fra konstruktøren.

Class Modem
{
  public Form1 OwnerForm{get; private set;}

  public Modem(Form1 ownerForm)
  {
    this.OwnerForm = ownerForm;

    // nu kan du sætte labelen fra Modem klassen, hvis Label1 er sat til at være public.
    this.OwnerForm.Label1.Text = "test fra modem";
  }
}

Dette er dog meget dårligt design, da du gør din Modem klasse afhængig af denne form.

Et bedre design vil være at lade Modem klassen være uafhængig. Formen kan da bruge Modem klassen, og opdatere sit brugergrænsesnit alt efter dens state.

Hvis du forklare lidt mere om hvad du prøver at lave, så skal jeg prøve at hjælpe.
Avatar billede keepy Seniormester
21. marts 2011 - 14:40 #6
Jeg prøver at lave en "log" i en textbox1
I min modem klasse ønsker jeg at string variablen data, bliver printet i textbox1.

Jeg kunne godt tænke mig at jeg i min modem klasse kunne skrive

UpdateText(data);

Hvorpå min textbox1 vil vise indeholdet af data.

Håber det er til at forstå :o)
Avatar billede aaberg Nybegynder
21. marts 2011 - 22:55 #7
Undskyld jeg var lidt langsom om at svare, men jeg havde lidt travlt :)

Her er en god måde at gøre det på.

Her er en Modem klassen:
public class Modem
{
    private Timer testTimer;

    public Modem()
    {
        // Dette er testkode, for at simulere at der kommer nye logbeskeder en gang i sekundet.
        testTimer = new Timer(1000);
        testTimer.Elapsed += new ElapsedEventHandler(testTimer_Elapsed);
        testTimer.Start();
    }

    private string _logData;
    public string LogData
    {
        get { return _logData; }
        set
        {
            _logData = value;
            this.OnLogDataChanged();
        }
    }

    public event EventHandler LogDataChanged;

    protected void OnLogDataChanged()
    {
        if (this.LogDataChanged != null)
            this.LogDataChanged(this, EventArgs.Empty);
    }

    //testkode
    void testTimer_Elapsed(object sender, ElapsedEventArgs e)
    {
        this.LogData += string.Format("log entry, tid: {0}\r\n\", DateTime.Now.ToString());
    }
}

Det som har med timeren at gøre, er bare testkode for at simulere at der kommer nye logbeskeder en gang i sekundet. Den som sker er, at når LogData propertien bliver ændret, kastet LogDataChanged eventet. Dette event skal du lytte på i formen. Herunder er koden til min form:

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

    private Modem modem = new Modem();

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        this.modem.LogDataChanged += new EventHandler(modem_LogDataChanged);
    }

    void modem_LogDataChanged(object sender, EventArgs e)
    {
        if (this.InvokeRequired)
        {
            this.Invoke(new MethodInvoker(delegate()
                {
                    this.textBox1.Text = this.modem.LogData;
                }));
        }
        else
        {
            this.textBox1.Text = this.modem.LogData;
        }
    }
}
Avatar billede aaberg Nybegynder
21. marts 2011 - 22:55 #8
Bare spørg, hvis der er noget du ikke forstår :)
Avatar billede keepy Seniormester
22. marts 2011 - 07:16 #9
KAn jeg så bruge this.LogData += string.Format("log entry, tid: {0}\r\n", DateTime.Now.ToString());  som en "funktion" jeg kan indsætte forskellige steder i min kode??
Avatar billede keepy Seniormester
22. marts 2011 - 07:28 #10
JEg ville gerne hvis jeg kunne gøre sådan

data=sp.ReadLine();
UpdateText(data); //"log" skriver til textbox1
Avatar billede aaberg Nybegynder
22. marts 2011 - 08:33 #11
Du kan jo godt oprette en UpdateText(string data) metode i Modem klassen:

publiv void UpdateText(string data)
{
  this.LogData += data + Environment.NewLine;
}

Hvis du abonnere på eventet i formen, vil dette skrive til tekstboksen.
Avatar billede keepy Seniormester
22. marts 2011 - 09:07 #12
hehe så mistede du mig lige igen.

Hvis du abonnere på eventet i formen, vil dette skrive til tekstboksen.

hvad vil det betyde hvis jeg bruger din kode i Form1??
Avatar billede aaberg Nybegynder
22. marts 2011 - 09:14 #13
Ok, lidt bedre forklaring :)

Hvis du har gjort, som jeg gjorde i mit eksempel, på din form. Dvs først abonnerer du på eventet:

this.modem.LogDataChanged += new EventHandler(modem_LogDataChanged);

og så laver du en handler til eventet:
void modem_LogDataChanged(object sender, EventArgs e)
{
....
}

Hvis du har gjort dette. Så kan du tilføje følgende metode til Modem klassen fra mit tidligere eksempel:

publiv void UpdateText(string data)
{
  this.LogData += data + Environment.NewLine;
}

Så vil der blive skrevet til tekstboksen, hver gang du kalder UpdateText(data);
Avatar billede keepy Seniormester
22. marts 2011 - 09:28 #14
Jeg kan bare ikke få det til at virke

Modem klassen: - flere stedet har jeg skrevet UpdataText(data);

        private string _logData;
        public string LogData
        {
            get { return _logData; }
            set
        {
            _logData = value;
            this.OnLogDataChanged();
        }
    }

    public event EventHandler LogDataChanged;

    protected void OnLogDataChanged()
    {
        if (this.LogDataChanged != null)
            this.LogDataChanged(this, EventArgs.Empty);
    }
public void UpdateText(string data)
{
  this.LogData += data + Environment.NewLine;
}

Klassen Form1

        private MultiModemSetup modem = new MultiModemSetup();

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            this.modem.LogDataChanged += new EventHandler(modem_LogDataChanged);
        }

        void modem_LogDataChanged(object sender, EventArgs e)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new MethodInvoker(delegate()
                {
                    this.textBox1.Text = this.modem.LogData;
                }));
            }
            else
            {
                this.textBox1.Text = this.modem.LogData;
            }
        }
Avatar billede aaberg Nybegynder
22. marts 2011 - 09:53 #15
Nu prøvede jeg at copy paste koden ind, præcist som du har skrevet den. Og det virker helt fint hos mig.

Hvilken fejl får du?
Avatar billede keepy Seniormester
22. marts 2011 - 11:27 #16
Jeg får ingen fejl, men der sker bare intet i textbox1
Avatar billede keepy Seniormester
22. marts 2011 - 11:35 #17
Prøv lige igen tak :o)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Traade
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            modem.start();
        }
        private Modem modem = new Modem();

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            this.modem.LogDataChanged += new EventHandler(modem_LogDataChanged);
        }

        void modem_LogDataChanged(object sender, EventArgs e)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new MethodInvoker(delegate()
                {
                    this.textBox1.Text = this.modem.LogData;
                }));
            }
            else
            {
                this.textBox1.Text = this.modem.LogData;
            }
        }

    }
}



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;

namespace Traade
{
    class Modem
    {

    public Modem()
    {
       
    }

    private string _logData;
    public string LogData
    {
        get { return _logData; }
        set
        {
            _logData = value;
            this.OnLogDataChanged();
        }
    }

    public event EventHandler LogDataChanged;

    protected void OnLogDataChanged()
    {
        if (this.LogDataChanged != null)
            this.LogDataChanged(this, EventArgs.Empty);
    }

    public void UpdateText(string data)
    {
        this.LogData += data + Environment.NewLine;
    }
  public void start()
    {
        String data = "hej";
        UpdateText(data);
    }
    }


    }
Avatar billede aaberg Nybegynder
22. marts 2011 - 13:11 #18
Det er fordi du kalder modem.Start() før eventhandleren bliver tilføjet. Prøv at flytte model.Start ned i denne metode:

rotected override void OnLoad(EventArgs e)

derefter kan du bare slette Form1_load metoden. Brug OnLoad i stedet.

Nu ser OnLoad metoden altså sådan ud:
[code]protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);

    this.modem.LogDataChanged += new EventHandler(modem_LogDataChanged);
    modem.start();
}
[/code]
Avatar billede keepy Seniormester
22. marts 2011 - 14:28 #19
Ok

Jeg tror det der går galt er at jeg kun ønsker at skrive i textbox1 når jeg selv vil, ikke noget med at den skal køre og opdater heletiden.

UpdateText("hej");
.....
....
...
UpdateText("hej");
.....
....
...
UpdateText("hej");
Avatar billede aaberg Nybegynder
22. marts 2011 - 14:34 #20
Den forstod jeg ikke?

Det er vel det der sker nu! Når du kalder UpdateText, skriver du til tekstboksen!

Eller misforstod jeg lige hvad du mente?
Avatar billede keepy Seniormester
22. marts 2011 - 20:51 #21
Når jeg prøver det virker det kun når jeg loader programmet, så kommer data til at stå i textbox1.

Jeg vil gerne kunne skrive til textbox1 under kørsel af mit program.

Altså når programmet køre og der skal en handling så bliver det skrevet ud i textbox1.
Avatar billede aaberg Nybegynder
22. marts 2011 - 21:03 #22
Ja, og det gør den også nu. Er det en multiline tekstboks du skriver til? Hvis det er en single line tekstboks, vil du altid kun se den øverste linje. Sådan som den virker nu, lægger den en ny linje til, hver gang du kalder UpdateText.

Hvis du vil have den til at overskrive den gamle tekst, skal du ændre din UpdateText metode, sådan:

[code]public void UpdateText(string data)
{
    this.LogData = data;
}[/code]
Avatar billede keepy Seniormester
23. marts 2011 - 07:01 #23
Her ved mig virker det bare som om at det ikke kommer i samme tråd som form1
Avatar billede keepy Seniormester
23. marts 2011 - 07:15 #24
jeg har sendt dig en mail herinde.
Avatar billede keepy Seniormester
23. marts 2011 - 09:09 #25
hmm får du min mail?? den ligger i min indbakke virkerligt mærkeligt
Avatar billede aaberg Nybegynder
23. marts 2011 - 09:33 #26
Nu har jeg set på din kode. Jeg tror aldrig at UpdateText() metoden bliver kaldt. Du kalder den fra SendSMS metoden, men jeg kan ikke se at du kalder sendSMS() nogen steder fra i din form!

Prøv at sætte et breakpoint inde i UpdateText metoden, for at se om den breaker.

Hvis du er i tvivl om, hvordan man sætter breakpoints og bruger dem, så prøv at læse denne korte artikkel:
http://msdn.microsoft.com/en-us/library/ms173083%28v=vs.80%29.aspx (Se på "Debugging" afsnittet).
Avatar billede keepy Seniormester
23. marts 2011 - 10:10 #27
Det du kan se er kun en lille del af den samlede kode, men den kommer igennem SendSMS, for jeg modtager både SMS og jeg får skrevet til min log txt fil.
Avatar billede aaberg Nybegynder
23. marts 2011 - 10:20 #28
Hmm, mærkeligt.

Blokerer du tråden? Dette kan ske hvis koden suser rundt i en while løkke eller lignende? Et symptom på dette, vil være at formen går i "svarer ikke" mode. Hvis dette sker, vil formen ikke blive opdateret.

Men, jeg skal prøve at se lidt mere på det senere i dag. Lige nu har jeg lidt travlt :)
Avatar billede keepy Seniormester
23. marts 2011 - 10:26 #29
Ja jeg kunne jo have prøvet at steppe igennem programmet sorry havde jeg ikke lige tænkt på.

Når UpdateText() bliver kaldt, hopper den i methoden, og derefter i LogData(), og OnLogDataChanged(), så køre den
if(this.LogDataChanged !=null), og her hopper den over handlingen i if sætningen og køre videre i mit program.
Avatar billede aaberg Nybegynder
23. marts 2011 - 10:53 #30
Som jeg forstår dig, så er kalder den ikke eventet? Altså at (this.LogDataChanged != null) bliver false?

Hvis dette sker, er det fordi at denne linje ikke har været kaldt:
this.modem.LogDataChanged += new EventHandler(modem_LogDataChanged);

eventuelt at du kalder this.modem = new MultiModemSetup() efter at du abonere på eventet.
Avatar billede keepy Seniormester
23. marts 2011 - 12:06 #31
nej det virker heller ikke, den kommer stadig ud som false
Avatar billede keepy Seniormester
23. marts 2011 - 13:44 #32
Vil det fra MultiModemSetup klassen komme i samme tråd som Form1??
Avatar billede aaberg Nybegynder
23. marts 2011 - 22:12 #33
Med mindre du gør noget aktivt for at køre noget kode i en anden tråd, vil det køre i samme tråd som det der kalder koden. Hvis du er i tvivl om du har flere tråde, så har du højest sandsynligt bare en. Med mindre selvfølgelig, at du bruger et eller andet tredjeparts værktøj som opretter nye tråde.


hvis den springer over denne linje: if(this.LogDataChanged !=null), så er det fordi der ikke er tilføjet en event-handler. Det kan kun skyldes 2 ting. Enten har du ikke tilføjet event-handleren, ellers har du oprettet event-handleren på forkert instans af Modem klassen. Event-handlers er aktive, uanset om de bliver kaldt fra andre tråde, så det har ikke noget med det at gøre.

Prøv at brug lidt mere tid til at steppe igennem koden. Kontroller at du tilføjer eventhandleren før du kalder UpdateText, og dobbeltjek at det er rigtig instans du tilføjer eventhandleren på.

Det er denne linje der tilføjer en event-handler.
this.modem.LogDataChanged += new EventHandler(modem_LogDataChanged);

Og den tilføjer eventhandleren til this.modem instansen, og ikke andre eventuelt oprettede instanser af klassen.
Avatar billede keepy Seniormester
25. marts 2011 - 21:01 #34
Hej

Jeg fandt ud af det. Jeg oprettede 2 instancer af multimodem klassen og det var efter eventhandleren.

Men 1000 tak for hjælpen, det har været meget lærerigt.
Avatar billede aaberg Nybegynder
25. marts 2011 - 22:35 #35
Jeg lægger et svar :)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester