Laden...
L
Lynix myCSharp.de - Member
Software-Entwickler Saarland Dabei seit 08.04.2004 667 Beiträge
Benutzerbeschreibung

Forenbeiträge von Lynix Ingesamt 667 Beiträge

16.10.2011 - 10:03 Uhr

Hallo zusammen.

Folgende Problemstellung: Eine Webseite (HTML) soll über ein C# Tool mit Daten gefüttert werden und es soll möglich sein Aktionen wie Buttonclicks etc. auszuführen. Hintergrund ist, dass das C# Tool eine Testautomatisierung der HTML-Seite ermöglichen soll.

Hätte hier jemand eine Idee, wie man von C# aus auf einzelne HTML-Controls (z.B. Textboxen oder Buttons) einer Website im Internet-Explorer zugreifen und diese manipulieren kann ?

Ich bin für jede Anregung dankbar, die mich irgendwie in die richtige Richtung treibt.

Danke...

26.08.2011 - 17:24 Uhr

Wenn ich Dein Problem richtig verstehe, soll bei Drücken von Entf der selektierte Eintrag in der Dropdown Liste gelöscht werden, nicht aber der aktuelle Text der Combobox.

In den KeyDownEventArgs gibt es einen Member Handled. Wenn Du diesen auf TRUE setzt, wir der Tastendruck nicht ausgeführt.

Daraus ergibt sich dann sowas (ungetesteter Pseudocode, hab gerade kein VS.NET zur Hand) :

if <gedrückte Taste> = "Entf"
eventArgs.Handled = true;

<code zum löschen des Eintrags aus der Dropdown Liste>

26.08.2011 - 17:12 Uhr

Dein "Days" Form kennt die startForm Instanz nicht, deshalb kann es auch darauf nicht zugreifen (Stichwort Scopes).

Am Einfachsten ist es, wenn Du beide Forms untereinander bekannt machst, z.B. so :

Program.cs


formStart startFenster = new formStart();
Days dayFenster = new Days();
startFenster.PartnerForm = dayFenster;
dayFenster.PartnerForm = startFenster;

Application.Run(startFenster);

In den beiden Forms muss dann natürlich noch jeweils das Property PartnerForm definiert werden


public Form PartnerForm {get; set;}

Dann kann man aus dem startFenster bzw. aus dem dayFenster mit


this.Hide();
PartnerForm.Show();

hin- und her switchen.

26.08.2011 - 17:01 Uhr

Sicher wissen tu ich es nicht, aber ich kann mir nicht vorstellen, dass es da eine Begrenzung gibt. Kann es vielleicht sein, dass Dein Dienst nicht die nötigen Rechte hat um die fehlenden Prozesse zu starten ? Wobei dann eigentlich aber eine Exception geworfen werden sollte...

26.08.2011 - 16:49 Uhr

Ist es nicht gerade so, dass alle Background-Threads automatisch beendet werden, wenn die Anwendung beendet wird ?

Wie kann dann dieser Thread nicht beendet werden ?

12.05.2011 - 16:27 Uhr

@Raphael

Ich arbeite auch seit Langem mit einem ähnlichen Ansatz. Ich nutze einen eigenen Serializer um Objekte in XML zu serialisieren und andersrum wieder zu deserialisieren (ObjectSerializer) und kann so "von außen betrachtet" direkt Objekte zwischen Client und Server hin und her schieben. Zur Kommunikation verwende ich ebenfalls die stinknormalen TcpListener / TcpClient Klassen, und es funktioniert bisher in allen mir untergekommenen Anwendungsfällen problemlos, was ich leider von Remoting, WCF etc. pp nicht behaupten kann.

Im Endeffekt musst Du herausfinden, was für Dich der beste Ansatz ist. Wenn Du hier so allgemein fragst, wirst Du von jedem eine andere Antwort erhalten...

12.05.2011 - 16:19 Uhr

Sorry, die Antwort hat etwas länger gedauert.

@Rainbird

gute Idee, danke - ich würde dann aber eher gleich ein .NET Control schreiben und das ins WinCC einbinden.

Davon unabhängig scheints aber mit dem o.g. Script zu funktionieren und da ich etwas Zeitdruck habe und das Gedöns einfach nur vom Tisch haben will, reicht mir das so fürs Erste.

09.05.2011 - 11:45 Uhr

Nachtrag:

Kann es sein, dass ich beim Anlegen des Sockets z.B. im CScript nur die Option "Socketstream" wählen muss, damit ich mit dem Networkstream arbeiten kann ?



int SendMsgToSocket(const char* server_ip, unsigned short server_port, const char* msg)
{

  #pragma code("wsock32.dll")

  unsigned long socket (long af, long type, long protocol);  
  unsigned long inet_addr (const char* cp);  
  unsigned short htons (unsigned short hostshort);  
  long connect (long s, const struct sockaddr* name, long namelen);  
  long send (long s, const char* buf, long len, long flags);  
  long closesocket(long s);

  #pragma code()

  #define INET 2  
  #define SOCK_STREAM 1

  long tosocket; 
  tosocket = socket(PF_INET,SOCK_STREAM,0);
  
  if(tosocket != -1)  
  {
     //arbeite mit socket...
  }
}

So oder so ähnlich müsste doch zumindest mal das Senden funktionieren.... Wenn ich nun die Funktion aufrufe und auf C# Seite ein TcpListener auf diesen Port läuft, sollte der meiner Meinung nach einen TcpClient akzeptieren und dessen Stream auslesen können, oder ?

Wie es in die andere Richtung aussehen müsste weiß ich allerdings noch nicht, zumal ich die Scripte nur durch Benutzerinteraktion (z.B. Buttonclick) ausführen kann. Zum Empfangen müsste ja permanent in einem Script "gehorcht" werden. Aber evtl. brauche ich das garnicht...

09.05.2011 - 11:13 Uhr

Hallo zusammen,

folgendes Szenario : Ich habe eine Anwendersoftware (WinCC) in der ich VBScript oder CScript benutzen kann und einen C# Server, der bestimmte Daten ermittelt und in einer SQL Datenbank abspeichert.

Aus dem CScript bzw. VBScript heraus will ich nun dem C# Server mitteilen, wann er mit der Datenermittlung anfangen bzw. aufhören soll. Außerdem müsste ich bei jedem Start/Stop Befehl eine Nummer mitgeben.

Da mir zusammengefrickelte Ansätze wie z.B. das Setzen einer 1 in der Datenbank, die dann vom Server erkannt und als Steuersignal genutzt wird nicht gefallen, würde ich diese Kommunikation gerne über einen TCP-Port lösen.

Daher die Frage bzw. mein Verständnisproblem :

  1. Auf .NET Seite habe ich einen TCPListener. Würde dieser einen Verbindungsversuch von Scriptseite als TcpClient Verbindung akzeptieren ?

  2. Kann ich dann den dranhängenden NetworkStream verwenden um z.B. eine Antwort zurückzuschicken ? Wenn ja, wie würde das auf Scriptseite ankommen und wie könnte ich dort den Stream auslesen ?

  3. Oder bietet sich vielleicht eine bessere Methode um die TCP Kommunikation zwischen VBScript / CScript und .NET zu realisieren ?

Danke...

08.02.2011 - 07:26 Uhr

Es müsste doch grundsätzlich auch gehen, wenn man erst Convert.ChangeType(value1, typeof(value1)) auf beide anwendet und dann gleich immer Equals benutzt, oder ? Zumindest bei primitiven Typen...

02.02.2011 - 21:05 Uhr

Daran lags - ich habe die Randoms außerhalb angelegt und bin nach ca. 27000 Runden bankrott gegangen...

Hast Du eine Erklärung dafür ?

Danke Dir !

02.02.2011 - 20:54 Uhr

Vorab : Bitte keine Kommentare zum Codestil, ich habe das gerade in ein paar Minuten zusammengetippt um den eigentlichen Algorithmus durchzuspielen.

Es geht dabei um das Martingale-System beim Roulette MartingaleSpiel.

Es ist mathematisch leicht beweisbar / nachvollziehbar, dass dieses System früher oder später zum Bankrott führt, ich wollte aber etwas rumprobieren, wie sich die Entwicklung des eigenen Kontostandes ändert, wenn man an der einen oder anderen Stelle dreht, daher meine unten stehende Umsetzung in Code...

Dieser Code stellt den Algorithmus ohne irgendwelche Änderungen dar, und müsste demnach unweigerlich zum Bankrott führen. Und jetzt zu meinem Problem : Er tut es nicht...

Kurz zur Erklärung, das label oben zeigt den aktuellen Kontostand, das label links die Anzahl der gespielten Runden, das label rechts die Höhe des aktuellen einsatzes und das label unten den höchsten je vorgekommenen Einsatz.

Wie man beim Ausführen des Codes sieht, steigt der höchste je vorgekommene Einsatz nie über 1024 (=10^2), was unterm Strich bedeutet, dass die Instanz der Random-Klasse "r2" es nie schafft, mehr als 10 mal hintereinander dieselbe "Farbe" zu erzeugen.

Wenn ich nicht alles zum Thema Wahrscheinlichkeitsrechnung verlernt habe, müsste der Fall, dass 11 mal hintereinander dieselbe Zahl kommt, aber bei 100.000 Versuchen ca. 4 Mal vorkommen. Es scheint daher so zu sein, dass die Random-Klasse hier in irgend einer Form so beschränkt wurde, dass keine Serien > 10 vorkommen können.

Oder sehe ich das falsch ? Danke für alle Antworten 😃


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 RSim
{
  public partial class Form1 : Form
  {
    private bool started;
    private double account;
    private double bet;
    private double maxbet;
    private int rounds;

    public Form1()
    {
      InitializeComponent();
      started = false;
    }

    private void Form1_MouseDoubleClick(object sender, MouseEventArgs e)
    {
      started = !started;
      if (started)
      {
        rounds = 0;

        //startkapital
        account = 1000;
        //starteinsatz
        bet = 1;
        //größter einsatz bisher
        maxbet = 1;

        //laufe so lange bis wir bankrott sind oder durch doppelklick abbrechen
        while (started && account >= 0)
        {
          //zufällig eine farbe auswählen, auf die wir setzen
          Random r1 = new Random((int)(DateTime.Now.Millisecond));
          int brs = r1.Next(0, 2);

          //roulette kugel zufallsgenerator erzeugen
          Random r2 = new Random((int)(Int32.MaxValue * DateTime.Now.Millisecond));
          int rrs = 0;

          while(true)
          {            
            //nächstes roulette ergebnis
            rrs = r2.Next(0, 2);
            rounds++; //gespielte runden hochzählen

            //roulettergebnis = wettvorhersage -> gewonnen !
            if (rrs == brs)
            {
              account = account + bet; //letzten einsatz zum kapital addieren
              bet = 1; //zurück zum starteinsatz

              //werte ausgeben
              lblAccount.Text = account.ToString();
              lblBet.Text = bet.ToString();
              lblRounds.Text = rounds.ToString();
              lblMaxbet.Text = maxbet.ToString();

              Application.DoEvents();
              break;
            }
            //roulettergebnis = wettvorhersage -> verloren !
            else
            {
              account = account - bet; //einsatz vom kapital abziehen
              bet = bet * 2; // einsatz für nächste runde verdoppeln

              //ggf. größten bisher getätigten einsatz aktualisieren
              if (bet > maxbet) 
                maxbet = bet;

              //werte ausgeben
              lblAccount.Text = account.ToString();
              lblBet.Text = bet.ToString();
              lblRounds.Text = rounds.ToString();
              lblMaxbet.Text = maxbet.ToString();
              Application.DoEvents();

              //ende bei bankrott
              if (account <= 0)
                break;              
            }
          }                    
        }
      }
    }
  }
}


18.01.2011 - 17:15 Uhr

Ich meinte schon wie ich es sagte, dass nach geraumer Zeit nichts mehr ankommt (so c.a. 5 Sekunden funktioniert es). Das heißt, meine Receive BeginReceive wird nicht mehr ausgeführt, was ja soweit ich weis nur der Fall ist wenn nichts mehr kommt.

Ja, hab ich schon verstanden, aber ich meine es auch so wie ich es sagte : Wenn nach 5 Sekunden kein Eventhandler mehr gefeuert wird heißt das nicht zwangsläufig, dass nichts mehr ankommt, oder dass BeginReceive nicht mehr ausgeführt wird.

Wenn Dein Aufruf an byteArrayToImage() null zurückliefert (aus welchem Grund auch immer), passiert hinterher nichts mehr...

Deshalb nochmal die Frage, hast Du wirklich ausgeschlossen (Breakpoint, Log-Ausgabe), dass er ab einem Zeitpunkt X nicht mehr ins BeginReceive springt ?

17.01.2011 - 18:23 Uhr

Dumme Frage am Rande : Wie äußert sich denn das "nicht ankommen", bzw. wie stellst Du fest, dass nichts ankommt ?

Kann es sein, dass zwar irgendwas ankommt, das aber nur nicht korrekt in ein Bild zurück gebaut werden kann ?


if (ImageReceived != null && img != null)
          {
                 ImageReceivedEventArgs e = new ImageReceivedEventArgs();
                 e.Image = img;
                 ImageReceived(this, e);
          }

Wenn Du hier nur zählst, wie oft das Event gefeuert wird, sagt das noch nichts darüber aus, wie oft etwas beim Client ankommt. Der "Fehler" könnte dann genausogut im byteArrayToImage(imgBytes) Aufruf liegen.

23.12.2010 - 18:47 Uhr

Am Einfachsten ist es die Typinformationen in deinem Config-File zu speichern (ob dafür die app.config besonders toll geeignet ist, weiß ich nicht), also assembly info und typinfo und dann beim Initialisieren Deiner Software die benötigten Instanzen per Activator.CreateInstance() anzulegen.

Ich würde mir dementsprechend auch eine Factory, der Du die jeweiligen Typinfos rein gibst und von der Du die fertige Instanz zurück bekommst, bauen.

In meinem Projekt habe ich das auch noch so gelöst, dass ich mir ein "Konfigurationstool" geschrieben habe, über das ich mir meine Konfigurationsdatei zusammenklicken kann. An Stellen wo es Plugins ("Kindklassen" in Deinem Sinn) gibt, sucht das Konfigurationstool in allen Assemblies im Ausführungspfad nach Typen, die die jeweilige Schnittstelle / abstrakte Basisklasse implementieren und stellt diese dann zur Auswahl. Damit kann man das System später maximal einfach erweitern, indem man einfach neue Typen / Ableitungen in Form einer Plugin-Assembly ins Ausführungsverzeichnis dazukopiert und dann einfach einbinden kann. Das hat auch nachvollziehbare Vorteile, wenn man das "Framework" bzw. den "Kernel" selbst an Kunden oder andere Entwickler weiter gibt, die sich selbst Erweiterungsplugins dazu schreiben wollen.

23.12.2010 - 17:32 Uhr

Die Guids, die man sich im VS erstellen lassen kann sind rein zufällig soweit ich weiß, oder meinst Du etwas Anderes ? Dahin ging meine erste Idee - GUID erstellen, irgendwo im System "verstecken" und dann diese GUID als PC-ID verwenden. Allerdings bringt das für VMs / Images nichts, da die im System hinterlegte GUID mit kopiert wird...

23.12.2010 - 17:18 Uhr

Inwiefern musst du eindeutig identifizieren, innerhalb einer Gruppe(Netzwerk) oder einfach nur ob es sich nach dem Neustart deines Programs immer noch um den gleichen Rechner bzw. das gleiche System handelt?

Letzteres - es geht konkret darum, dass eine Kopie / Seriennummer der Software nur auf genau dem Rechner laufen darf, auf dem sie freigeschaltet wurde. D.h. ich muss die Seriennummer z.B. aus einer eindeutig identifizierbaren Komponenten des PCs bauen, der Kunde ruft an und gibt diese Seriennummer durch, und der passende "Freischaltcode" wird aus dieser Seriennummer erzeugt. Wird die SW nun auf einen anderen PC kopiert oder in Form einer VM vervielfältigt, soll sie erkennen, dass der Freischaltcode nicht zur für diesen Rechner ermittelten Seriennummer passt und den Dienst verweigern.

Die beste Lösung für sowas wäre wohl ein Dongle, wobei das aber den finanziellen Rahmen der Lizenzeinnahmen in meinem Fall wohl sprengen würde, weshalb ich nach einer SW-Lösung suche.

23.12.2010 - 17:11 Uhr

Danke Dir für die Antwort - aber bist Du sicher, dass man die Mac-Adresse der VM einstellen kann ? Ich kanns mir nur schwer vorstellen - wenn sie z.B. identisch zum Host-System wäre würde es doch ziemliche Probleme geben ?

Dein Vorschlag, eine ID aus Hardwarekomponenten zu bilden klingt auch interessant - gibt es dazu verfügbare Algorithmen ? Hätte man dabei aber nicht das selbe bzw. ein ähnliches Problem wie bei der Mac-Adresse ? Ich meine wenn man die bei einer VM faken kann, dann doch wohl auch Festplatten-, Graka- usw. IDs ?

23.12.2010 - 16:59 Uhr

Ein Beispiel aus meinem Projekt wäre, dass ich eine abstrakte Elternklasse mit einer Methode Start() habe und jedes Kind hat auch diese Startmethode, die aber bei jedem Kind anders ist. Also was macht es für einen Unterschied, ob ich nun in der Elternklasse eine abstracte Start() schreibe und dann bei jedem Kind überschreibe, oder ob ich einfach die Methode in der Elternklasse weglasse und jedes Kind seine eigene Start() hat, weil sie ja sowieso komplett anders ist.

Ein offensichtlicher Vorteil wäre, dass der konkrete Typ des Kindes dem Aufrufer zunächst nicht bekannt sein muss, da er mit dem Eltern-Typ arbeiten kann.

Stell die Vor, du hast 20 verschiedene Kinder und irgendwo eine Kontrollklasse, die mit den Kindern arbeiten muss. Hättest Du jetzt keine Elternklasse mit einer abstrakten Start()-Methode, müsstest Du in der Kontrollklasse jeweils für alle 20 Kinder eine eigene Behandlung zum Aufruf von Kind1.Start(), Kind2.Start() usw. bereitstellen.
Deine Eltern-Klasse mit der abstrakten Methode stellt dagegen einen allgemeingültigen Vertrag / Contract / Schnittstelle für alle abgeleiteten Typen bereit, so dass es deiner Kontrollklasse egal sein kann, ob sich dahinter nun konkret Kind1, Kind2 oder Kind20 verbirgt.

Google mal nach Contract-First Design, ich denke, da wirst Du genug finden, was Dir das Ganze deutlicher macht.

23.12.2010 - 16:47 Uhr

Hallo zusammen,

angenommen ich habe einen PC und ziehe ein Image davon, z.B. mit Acronis - gibt es dann eine softwareseitige (nach Möglichkeit C#-seitige) Möglichkeit zu erkennen, ob der PC oder das Image verwendet wird ? Also ich will die Software auf dem PC starten und angezeigt bekommen Rechner X wird verwendet. Dann die Software in der VM mit dem Image starten und angezeigt bekommen Rechner Y wird verwendet...

Generell brauche ich also eine Möglichkeit, Rechner eindeutig zu identifizieren. Grundsätzlich müsste das doch über die Mac-Adresse gehen, oder ? Die müsste ja auch bei einer VM anders sein als beim PC von dem das VM-Image abstammt ?

Wie könnte ich die Mac-Adresse mit C# auslesen ? Ich könnte natürlich über Ausführung von ipconfig /all und anschließendes Auslesen des Ausgabestreams die Macadresse ablesen, aber gibt es vielleicht eine "eingebaute" / "elegantere" Möglichkeit ? Oder gibt es bessere Möglichkeiten als die Mac-Adresse ?

Danke ...

Nachtrag : Außerdem würde mich interessieren kann, ob man generell irgendwie abfragen kann, ob es sich bei dem aktuellen System um eine VM oder einen echten PC handelt.

05.12.2010 - 12:16 Uhr

Das stimmt sicher, aber in dem Thread geht es um die richtige Verwendung von GDI oder um allgemeine Hinweise, wann man Invalidate verwenden soll/darf und wann nicht - nichts davon trifft auf mein Problem zu. Weder mache ich irgendwas mit GDI und Invalidate rufe ich in der gesamten Anwendung nirgendwo auf.

05.12.2010 - 12:10 Uhr

Herbivore hat eigentlich alles zum System.Windows.Forms.Timer gesagt. Wenn ich deine Aufgabenstellung richtig verstehe könnte allerdings auch System.Threading.Timer was für Dich sein.

05.12.2010 - 12:06 Uhr

Das bezog sich nicht speziell auf "Zyan", sondern eher auf solch unflexible Konstrukte wie Remoting allgemein. Das jetzt (nochmal) zu vertiefen wäre aber Offtopic...

05.12.2010 - 11:59 Uhr

Ich habe den Thread beim Suchen auch gefunden, aber das meiste davon hat ja nichts mit meinem Fall zu tun. Bei mir geht es um das Hinzufügen / Entfernen von Controls. Dein Artikel sagt zu diesem Punkt auch Suspend-/ResumeLayout verwenden - habe ich wie gesagt, getan - allerdings ohne Effekt. Das Flackern tritt mit Suspend-/ResumeLayout genauso auf wie ohne...

Da ich auch nichts Spezielles tue, wie irgendwas im OnPaint zeichnen oder dergleichen, sondern nur stinknormale Labels auf ein Usercontrol hinzufügen/entfernen will, hilft mir der Rest des Threads nicht wirklich weiter.

Ich könnte mir höchstens noch vorstellen, dass es irgendwie damit zusammenhängt, dass mein Usercontrol ein Hintergrundbild hat, und es da irgendwo Probleme gibt, wenn Controls in ein Control mit Hintergrundbild gepackt werden. Ich werd einfach mal das Hintergrundbild testweise rausnehmen und schauen, ob es sich dann anders verhält...

03.12.2010 - 17:45 Uhr

Das Problem liegt darin, dass ReadLine() blockiert, bis eine Zeile gelesen wurde. Daher läuft Deine Schleife nicht weiter, so lange der erste Client nichts sendet.

Du hast die Lösung ja schon gefunden, wollte es nur zur Erklärung noch dazu schreiben.

@Rainbird

Vielleicht will er seine Nerven etwas schonen 😃

03.12.2010 - 17:41 Uhr

Ich weiß ja, dass mittlerweile jeder hier weiß, dass ich von WCF nicht so richtig überzeugt bin und Remoting für eine Katastrophe halte, deswegen schreibe ich dazu auch nichts mehr... nur der Vollständigkeit halber sei erwähnt, dass es auch mit den TcpClient/TcpListener Klassen bzw. gleich mit Sockets geht.

03.12.2010 - 17:37 Uhr

Hallo inflames2k,

aufgrund Deiner Beschreibung tippe ich darauf, dass Du beim Senden der Daten das Flush() vergessen hast. Ist aber schwer zu sagen, ohne den entsprechenden Code zu sehen.

03.12.2010 - 17:31 Uhr

Erstmal danke für die Antwort !

Die Idee mit Controls.Add() ans Ende setzen hatte ich auch schon, aber dann stimmt die Location nicht mit der überein, die ich vorher gesetzt habe. Wenn ich bspw. Location=(100,100) setze und dann Controls.Add() aufrufe, landet das Label irgendwo aber nicht bei 100,100

Der Zugriff per Name passiert ja nur einmal am Anfang, vor der Schleife, und zu diesem Zeitpunkt wird auch noch nichts am GUI verändert. Ich sehe nicht, wie das zu dem Problem führen könnte / sollte.

03.12.2010 - 17:07 Uhr

Hallo zusammen,

seit einiger Zeit nervt mich ein Usercontrol in meiner Anwendung. Dem Usercontrol werden je nach Benutzeraktion Labels zur Laufzeit hinzugefügt bzw. Labels daraus entfernt.

Beim Hinzufügen/Entfernen fängt das Usercontrol an zu flackern, als ob gleich der Monitor explodieren müsste. Ich dachte eigentlich immer, dass genau dafür SuspendLayout / ResumeLayout gut wäre, allerdings sehe ich bei mir keinen Unterschied egal ob ich es auskommentiere oder drin lasse.

Hier mal der betreffende Codeausschnitt aus dem Usercontrol :


private void DisplayBatchInfo(BatchStatus batchInfo, List<VariableInput> variableInputs, int groupID, bool update)
    {
      this.SuspendLayout();
      if (batchInfo != null)
      {
        //Display batch info
        string lblName = "lblBatch" + groupID.ToString() + "_";
        Controls[lblName + "PNr"].Text = batchInfo.ProductNo;
        Controls[lblName + "Proc"].Text = batchInfo.Process;
        Controls[lblName + "ANr"].Text = batchInfo.BatchNo;
        Controls[lblName + "Desc"].Text = batchInfo.ProductName;
        Controls[lblName + "Lot"].Text = batchInfo.LotNumber;
        Controls[lblName + "Date"].Text = batchInfo.Date;
        Controls[lblName + "Operator"].Text = batchInfo.Operator;
        Controls[lblName + "Status"].Text = batchInfo.GetStatusString();

        Font viFont = Controls[lblName + "Operator"].Font;
        Size hSize = Controls[lblName + "OperatorH"].Size;
        Size vSize = Controls[lblName + "Operator"].Size;
        Point hStart = Controls[lblName + "OperatorH"].Location;
        Point vStart = Controls[lblName + "Operator"].Location;
        BorderStyle viBorderStyle = ((Label)(Controls[lblName + "Operator"])).BorderStyle;

        int viDetailsCounter = 1;
        foreach (VariableInput i in variableInputs)
        {
          if (i.ShowInDetails && !update)
          {
            Label header = new Label();
            Controls.Add(header);
            header.Visible = true;
            header.TextAlign = ContentAlignment.MiddleLeft;
            header.BorderStyle = viBorderStyle;
            header.Name = "VIH" + groupID.ToString() + "_" + viDetailsCounter.ToString();
            header.Text = i.VarName;
            header.Font = viFont;
            header.Size = hSize;
            header.Location = new Point(hStart.X, hStart.Y + viDetailsCounter * 23);            
            mCustomLabels[groupID].Add(header);

            Label value = new Label();
            Controls.Add(value);
            value.Visible = true;
            value.TextAlign = ContentAlignment.MiddleLeft;
            value.BorderStyle = viBorderStyle;
            value.Name = "VIV" + groupID.ToString() + "_" + viDetailsCounter.ToString();
            value.Text = i.VarValue;
            value.Font = viFont;
            value.Size = vSize;
            value.Location = new Point(vStart.X, vStart.Y + viDetailsCounter * 23);            
            mCustomLabels[groupID].Add(value);

            viDetailsCounter++;
          }          
        }
      }
      else
      {
        //Display batch info
        string lblName = "lblBatch" + groupID.ToString() + "_";
        Controls[lblName + "PNr"].Text = "frei";
        Controls[lblName + "Proc"].Text = "frei";
        Controls[lblName + "ANr"].Text = "frei";
        Controls[lblName + "Desc"].Text = "";
        Controls[lblName + "Lot"].Text = "";
        Controls[lblName + "Date"].Text = "";
        Controls[lblName + "Operator"].Text = "";
        Controls[lblName + "Status"].Text = "frei";
        //batchInfo.Status = eBatchStatus.Empty;        
      }
      this.ResumeLayout();
    }

Ich hoffe auf Ideen Eurerseits...
Danke

24.11.2010 - 10:07 Uhr

Hallo zusammen,

da von meiner Anwendung aus andere Anwendungen, die auf anderen PCs innerhalb des LANs laufen bedient werden müssen, suche ich so etwas wie ein .NET Usercontrol welches mir den Desktop eines anderen Rechners anzeigt. Also quasi ein VNC-Viewer, der als Control in eine .NET Anwendung eingebettet werden kann.

Momentan öffnet sich der VNC Viewer extern wenn der Benutzer die Steuerung anfordert, was ich relativ unschön finde.

Gibt es sowas ? Kann mich jemand in die richtige Richtung schubsen ?

Danke...

31.10.2010 - 14:49 Uhr

Hallo Felsen,

suche mal bei Google nach der "MySQL.Data.dll" bzw. nach "MySQL Connector .NET"
In dem Paket sind die gewohnten ADO.NET Klassen auf MySQL Basis nachgebaut, so dass Du im Connection-Objekt nur Deine Online-DB als Quelle angeben musst. Eignet sich sehr gut, um zwischen Lokal und Internet umzuschalten, da nur der Connectionstring geswitcht werden muss.

Habe es selbst in einem Hobbyprojekt im Einsatz und es funktioniert problemlos.

31.10.2010 - 14:44 Uhr

Liegt das Problem beim Deserialisieren auf Empfänger-Seite ? Wenn, wie Du schreibst, der BinaryFormatter die Objekte nicht serialisieren kann, liegt es ziemlich sicher nicht am Netzwerk-Code.

Falls es wie ich vermute beim Deserialisieren hakt, bist Du sicher, dass alle versendeten Objekte auf Sender- und Empfängerseite bekannt sind ? Tritt der Fehler immer bei denselben Objekttypen auf ?

08.09.2010 - 08:28 Uhr

WCF finde ich zumindest angenehmer zu nutzen, wobei ich dazu sagen muss, dass ich es noch nie in einem Projekt gebraucht habe, da sich meine Netzwerk-Klassen mittlerweile in mehreren Großprojekten, sowohl was die Performance als auch die Flexibilität angeht, bewährt haben und ich keinen Grund sehe, jetzt WCF auszuprobieren.
Zumindest muss man bei WCF keine 20 kryptischen Konfigurationsstrukturen befüllen - teilweise mit untypisierten Listen, in denen bestimmte Objekte in der richtigen Reihenfolge drin stecken müssen - um überhaupt eine Connection hinzubekommen. Auch callbacks / events scheinen mit WCF mit deutlich weniger Daumenschrauben nutzbar zu sein als bei Remoting. Insofern zumindest was die Usability angeht ein Schritt in die richtige Richtung.

03.09.2010 - 01:40 Uhr

Auf so eine Idee würde ich nur dann kommen, wenn mir alle bestehenden Datenbanksysteme vorschreiben würden, dass ich einen string Wert nur in einer Tabelle speichern darf, wenn ich vorher 5 integers und 3 datetimes speichere, anschließend 2 bool Werte auslese und danach eine Tabelle löschen muss.

Wenn es dann noch weiterhin die Einschränkung gibt, dass der String an der 5. Stelle immer zwingend ein "X" haben muss, dann würde ich die Idee wohl in die Tat umsetzen. Ähnlich verhält es sich mit Remoting...

28.08.2010 - 23:36 Uhr

Ich habe nämlich noch keine Möglichkeit gefunden, wie mein Programm das mitbekommt, das die Hostanwendung geschlossen wurde... Da ist noch der Haken...

Es gibt da meines Wissens nach außer über das Abfangen von SocketExceptions, was sehr zeitintensiv und ungenau ist keine praktikable Möglichkeit "mit Bordmitteln".

Ich habe das Problem immer so gelöst, dass ich die Gegenseite (in Deinem Fall die Hostanwendung), in regelmäßigen Abständen eine spezielle Nachricht an den Empfänger (dein Client) schicken lasse. Der Empfänger weiß dann, dass die Gegenseite tot ist, wenn x Sekunden lang keine entsprechende Nachricht mehr angekommen ist. In dem Fall könntest Du also Deine Polling-Loop wieder starten.

28.08.2010 - 23:25 Uhr

@MarsStein

Der Sinn meines Codes war ja auch, dass er abbrechen soll, sobald entweder keine Daten mehr im Stream sind, oder (mit dem Zusatzhinweis) wenn am Ende ein </html> Tag gelesen wurde.

@azzic

Das darf doch nicht sein ich mach die aufrufe sequentiell und les danach aus, nicht mit mehreren Threads oda sonstigem wodurch ichs mir erklären könnt...

Das Problem kann grundsätzlich auch daher kommen, dass die Gegenseite unsynchronisiert in den Stream rein schreibt. Dann hast Du wenig bis garkeine Chancen, wenn keine Trennzeichen o.Ä. definiert wurden.

26.08.2010 - 08:57 Uhr

Wenn Du mit Threads arbeitest solltest Du statt while(true) immer so etwas wie while(!mShutdown) benutzen, wobei mShutdown eine bool-Variable ist, die Du auf false setzt, wenn die Anwendung beendet wird, also z.B. im FormClosing Event.

Das sollte schonmal das Problem lösen, dass Deine Anwendung im Taskmanager als Prozess weiter läuft.

Dein Server bekommt ein Problem wenn der Client geschlossen wird, da Du im Server in der Methode "doChat" permanent auf die Verbindungsobjekte zugreifst. Die Zugriffe werfen eine SocketException, wenn die Verbindung nicht mehr vorhanden ist. Das musst Du also mit einem geeigneten Catch abfangen.

Einen einmal geschlossenen TcpClient kannst Du nicht wieder öffnen. Du musst stattdessen eine neue TcpClient Instanz anlegen und über diese nochmal verbinden. Dabei solltest Du verschiedene Ports benutzen, da die Ports einer geschlossenen Verbindung von Windows noch eine Zeit lang blockiert sein können.

26.08.2010 - 08:45 Uhr

Wie wäre es mit while(stream.DataAvailable) ?

26.08.2010 - 08:42 Uhr

Ich hab mich ja schon vor langer Zeit von diesem Remoting-Murks verabschiedet also bin ich da sicherlich kein "Experte" in dem Bereich (Gott sei dank...) - aber gab es bei Remoting nicht auch einen Modus, bei dem die Verbindung dauerhaft offen bleibt ?

Stichwort Lifetimeservice oder so was ?

26.08.2010 - 08:32 Uhr

Ich denke mal so müsste es funktionieren, vorausgesetzt meine Annahme ist richtig und die Variable s ist in Deinem Code ein NetworkStream:



private System.IO.StreamReader reader = new StreamReader(s);

private string readstream()
{
        string output="";        
        while(s.DataAvailable)
            output += sr.ReadLine();

        return output;
}


Evtl. musst Du da noch das Ende der html-Seite detektieren, denn wenn während die erste Seite gelesen wird, eine weitere in den Stream rein kommt, wird er diese einfach mit an "output" anhängen. Also vielleicht als zusätzliche Abbruchbedingung so etwas in der Art machen :


private string readstream()
{
        string output= "";       
        string currentLine = ""; 
        while(s.DataAvailable)
        {
            currentLine = sr.ReadLine();
            output += currentLine;

            if(currentLine.Contains(@"<\html>"))
              break;
        }

        return output;
}

Code ist ungetestet.

23.08.2010 - 20:01 Uhr

Danke,

ich hab mal die ersten paar Einträge studiert, aber so wirklich überzeugt haben mich die Ansätze auch nicht, da ich nur Aktionen in meiner Anwendung abfangen will.

Ich habs jetzt erstmal so gemacht, dass ich am Anfang rekursiv von allen Controls des Hauptforms und dann wieder von allen Controls der Controls usw. das MouseMove abonniere. Geht ja zum Glück recht einfach :


private void SubscribeMouseMoveRecursive(Control ctrl)
{
   ctrl.MouseMove += new MouseEventHandler(HandleMouseMove);
   foreach(Control child in ctrl.Controls)
     SubscribeMouseMoveRecursive(child);
}

Damit erwische ich auch alle vorkommenden Usercontrols und die darin verbauten Controls. Kommt mir zwar irgendwie unelegant vor, funktioniert aber.

23.08.2010 - 18:56 Uhr

Hallo zusammen,

da die Forensuche nach "MausEvents" nichts zu Tage gefördert hat, was mir weiterhelfen würde, mache ich mal einen eigenen Thread auf.

Folgendes Problem :

In meiner Anwendung gibt es einen Login/Logout Mechanismus, der auf dem ActiveDirectory aufsetzt. Jetzt soll ein automatischer Logout nach 30 Minuten Inaktivität des Benutzers stattfinden.

Die Anwendung ist so aufgebaut, dass es ein Hauptformular gibt, welches verschiedene Ansichten (realisiert als Usercontrols) anzeigt.

Da es bereits einen permanent laufenden Timer im Hintergrund gibt, wollte ich das Problem nun so lösen, dass ich das MouseMove Event des Hauptformulars abonniere und im Handler nur eine LastActivity-Membervariable vom Typ Datetime aktualisiere. Im dauernd laufenden Timer wollte ich nun schauen ob

(DateTime.Now - mLastActivity).TotalMinutes > 30 ist und falls ja, die Logout-Funktion aufrufen.

Leider funktioniert das nicht, denn das MouseMove Event wird niemals ausgelöst.

Ich denke das Problem liegt daran, dass das gesamte MainForm von den Usercontrols verdeckt wird, und deswegen das Event nicht getriggert wird.

Ich würde jetzt nur ungern von jedem Usercontrol das MouseMove Event abfangen und dann die Info jeweils komplett bis zum Hauptform weiterreichen.

Daher die Frage : Gibt es eine einfache Möglichkeit, das MouseMove-Event über die ganze Anwendung hinweg abzufangen ?

Danke

06.08.2010 - 12:57 Uhr

Würde ich auch so machen, wobei ich nicht weiß ob WCF den "Type" Typ serialisieren kann. Falls nicht kannst Du auch den Type.FullName als string mitschicken und auf der Gegenseite per Reflection wieder anlegen.

16.07.2010 - 10:14 Uhr

Wird aber vermutlich wieder krachen, wenn es über das Internet gehen soll.

07.07.2010 - 19:05 Uhr

Ist der FTP Server denn so konfiguriert, dass er ausreichend Idle Time erlaubt, bevor er die Verbindung trennt ? Ich hatte früher bei meinem ehemaligen Arbeitgeber immer das Problem, dass FTP-Uploads die ich über Nacht für die Amerikaner angestoßen habe, irgendwann fehlgeschlagen sind, da der FTP nach einer gewissen Zeit ein Kommando haben wollte und wenn keins kam, er die Verbindung unterbrach.

07.07.2010 - 08:40 Uhr

Tu Dir keinen Zwang an, manche Erfahrungen muss man eben erst selbst machen 😉 Viel Erfolg !

05.07.2010 - 21:01 Uhr

Hallo inflames2k,

ich würde von Remoting klar abraten, da dieser Namespace sehr komplex und verwirrend aufgebaut ist, und Du da wahnsinnig wirst, wenn Du vorher noch nicht damit gearbeitet hast.

Also bevor Du Dich in Remoting einarbeitest, entwickle Dir lieber eine eigene Netzwerbibliothek basierend auf den Networkstreams der TCP-Klassen, die Du dann weiter verwenden kannst. Der Aufwand ist vergleichbar, mit etwas Vorkenntnis zum Thema Sockets sogar deutlich geringer.

Der Vorteil ist zudem, dass Du diese Bibliothek genau auf Deine Anforderungen anpassen kannst und nicht früher oder später an irgendwelchen sinnlosen Einschränkungen bei Remoting hängen bleibst.

Wenn Du Dich in Microsoft-Foren rumtummelst, wirst Du auch ab und an an Microsoft-Mitarbeiter geraten, die mittlerweile selbst von Remoting abraten. Ich weiß allerdings nicht, wie dazu die offizielle Haltung von Microsoft ist, sondern kann nur sagen : Es ist grauselig....

Was WCF angeht, bin ich mir noch nicht ganz schlüssig. Sieht zum Einen auch recht (unnötig) überfrachtet aus, ermöglicht aber zumindest mit sehr wenigen, einfachen Schritten, grundlegende Netzwerkanwendungen zu erstellen.

Soweit meine Meinung, Du wirst hier sicher auch andere erhalten. Falls Du Interesse hast kann ich Dir auch per PM noch den Aufbau meiner Netzwerkbibliothek erläutern.

23.06.2010 - 01:25 Uhr

Richtig, und der simpelste "Header" wäre so was :



public enum ePackageType
{
  NetworkCommand_X,
  NetworkCommand_Y,
  ImageContainer,
  //u.s.w.
}

public class DataPackage
{
  private Dictionary<string, object> mParameters;

  public int SenderID {get; set;}
  public ePackageType PackageType {get; set;}

  public DataPackage()
  {
  }

  public DataPackage(ePackageType packageType, int senderID)
  {
     mParameters = new Dictionary<string, object>();
     SenderID = senderID;
     PackageType = packageType;
  }

  public object this[string parameterName]
  {
     get { mParameters.ContainsKey(parameterName) ? mParameters[parameterName] : null; }
     set { mParameters[parameterName] = value; }
  }
}

DataPackage anlegen, mit Parametern befüllen, dann bspw. mit dem hier serialisieren : ObjectSerializer und mit StreamWriter.WriteLine() in den NetworkStream schreiben. Auf der Gegenseite dann deserialiseren und das Ergebnis-Objekt in ein DataPackage zurück "unboxen".

18.06.2010 - 18:46 Uhr

Hey Majestic,

ich arbeite auch gerade an einem Leitstand für eine SPS-Produktionslinie, bin allerdings Informatiker und hab mich daher am Anfang eher mit der OPC/SPS-Seite schwer getan, weil das komplett neu für mich war.

Jedenfalls zu Deinem Problem : Serialisierung ist das für Dich wichtige Stichwort. Den Serializer, den ich mir gebaut habe um ein ganz ähnliches Problem wie das von Dir geschilderte zu lösen, habe ich hier bei Codeproject reingestellt :

ObjectSerializer

Hab ihn mittlerweile auch noch stark optimiert, bin aber noch nicht dazu gekommen ihn auf Codeproject zu aktualisieren. Kannst es Dir ja mal anschauen, vielleicht passt er ja für das was Du brauchst. Mit der Serialisierung von Generics kommt er jedenfalls problemlos klar.

18.06.2010 - 18:38 Uhr

Um die unschöne Behandlung einer Exception als Disconnect zu umgehen, mache ich das immer andersrum. In Deinem Fall würde ich den Server in regelmäßigen Abständen ein Ping an alle Clients broadcasten lassen. Wenn der Ping auf Clientseite nicht innerhalb eines bestimmten Zeitraums ankommt, weiß der Client, dass der Server weg ist und kann die Verbindung sauber aufräumen.

Der Weg funktioniert natürlich auch andersrum, also wenn der Server mitkriegen soll, wann ein Client beendet wurde. In dem Fall müsste der Client eben Pings an den Server schicken, bleibt ein Ping aus, weiß der Server dass der Client weg ist.