Laden...

Forenbeiträge von Fabian E. Ingesamt 258 Beiträge

22.12.2010 - 18:57 Uhr

Oh, okay...
Das ist schade... Aber eigentlich auch nicht so schlimm 😉

21.12.2010 - 23:55 Uhr

Wie deklariere ich im Programm selbst denn meine Betaversion korrekt?
Angenommen, ich habe die Version 1.3.0.2315 Beta 1 und möchte nun dass er mir die Version 1.3.0.4563 Beta 2 als Update findet...
Was muss ich dem Updater als Versionsstring übergeben? Bzw. wie verlgeicht der die Beta Versionen?
Gäbe da ja ein paar Möglichkeiten: *1.3.0.4563 Beta 1 *1.3.0.4563 (Beta 1) *1.3.0.4563 Beta1 *1.3.0.4563 (Beta1)

21.12.2010 - 14:43 Uhr

Damit könnte der Statistikserver dann sehen wie viele Benutzer es gibt.
Muss ich mir mal überlegen. Vor allem ob das Datenschutztechnisch in Ordnung geht.

Jo das wären auch meine größten Bedenken.
Aber wenn man die User nicht identifizieren kann, sondern nur weiß, dass da ein User ist, wäre das okay denke ich.

Vielleicht kann man auch nicht aufzeichnen wie oft jemand abfragt, sondern nur, DASS er abfragt. Wenn dieser User dann mehr als eine Woche/Monat/Jahr nicht mehr gesucht hat wird er gestrichen.

Mir gehts ja nicht darum zu wissen, wer wann wie oft abfragt, sondern darum, zu wissen, wie viele User mein Programm nutzen. Der Rest ist mir ja egal.

21.12.2010 - 14:28 Uhr

Ich hätte noch eine Anregung. Und zwar wäre es ganz schön, wenn der Statistikserver aufzeichnen könnte, wie viele individuelle Benutzer es gibt.
Dazu müsste das eigentliche Programm dem Updater nur z.B. eine vorher erzeugte und lokal gespeicherte GUID mitgeben, die dann zur Identifizierung genutzt wird.

Damit könnte der Statistikserver dann sehen wie viele Benutzer es gibt.

Ich habe auch gerade mal die Beta ausgepackt, die sieht ja richtig gut aus! =)
Allerdings vermisse ich noch die Einstellungen. Kommen die noch?
Werden wohl noch kommen, wenn der Link schon da ist 😉

Ansonsten könnte die Beta noch einen kleinen Dialog vertragen, mit dem man dir Fehler/Probleme melden kann...
Ohne den Umweg über das Forum und ohne, dass eine Unhandled Exception auftritt.

EDIT: Habe den Feedback-Dialog gerade gesehen, war aber auch ziemlich versteckt 😉

20.12.2010 - 23:19 Uhr

vlt kannst du eine volatile Variable setzen, die threadübergreifend aussagt, ob Daten noch verarbeitet werden können.

Als erstes im void RP6PortWrapper_DataAvailable(string obj) eine volatile bool setzen um zu signalisieren dass Du schon im DataAvailable drin bist.... dieses Flag nach dem Invoke wieder clearen.

Im TerminalForm_FormClosing den Event abhängen und dann das volatile-Flag abfragen. Falls es gesetzt ist machst du ein e.Cancel=true (damit der DataAvailalble noch verarbeitet werden kann) und dann ein BeginInvoke auf this.Close.

Ihr seid meine Helden! Genauso funktioniert es! =)
Zumindest ist der Fehler bis jetzt nicht mehr aufgetreten und sonst eigentlich mindestens jedes zweite Mal!
Vielen Dank! =)

20.12.2010 - 18:08 Uhr

Okay, das ist interessant...
Ergebnis ist genau das Selbe, der Fehler tritt manchmal auf...
Der Breakpoint wird aber niemals aktiviert.
Das bedeutet also der GUI-Thread disposed manchmal direkt nach der Abfrage auf IsDisposed.
Daher auch der Yeti-Effekt, ist halt eine Timing-Sache.

Nun die Preisfrage, was kann ich dagegen tun?
Ich hatte es schonmal mit einem lock probiert, das half aber auch nichts...
Daher war ich eigentlich auch wieder weg von der Timing Geschichte...

Im Moment habe ich ein leeres try catch Konstrukt drum rum.
Ist aber natürlich langsam und schön ist auch anders...

20.12.2010 - 14:27 Uhr

Also ich verstehe es wirklich nicht...

Wenn ich mir den Fehler mal von der IDE auffangen lasse und mir dann die Werte von IsDisposed und IsHandleCreated ansehe, dann passen die. Disposed -ja Handle - nein.
Daher dann natürlich auch der Fehler...
Das ignoriert mein Programm aber einfach gnadenlos...
Wie geht das?
Im Anhang mal ein Bild davon...
Link entfernt

20.12.2010 - 12:37 Uhr

Nein, leider keinerlei Veränderung 😦

20.12.2010 - 12:19 Uhr

Hallo zusammen,

ich habe eine Frage zum Threading in Fenster und zum Thread übergreifenden Zugriff auf meine Controls.

Bitte jetzt keine Links zu den bekannten Beiträgen posten, ich glaube das hier ist etwas komplizierter...

Ich habe folgende Situation: Mein erster Thread ist natürlich der GUI-Thread. Der Zweite ist ein Thread der seriellen Schnisstelle.
Und zwar scheint ein Thread im Hintergrund zu laufen, der das Event

SerialPort.DataReceived

schmeißt.

Nun muss ich aus diesem Thread-Kontext auf meine Controls zugreifen. (Das Event wird noch ein bisschen weiter gereicht, der Kontext ändert sich aber nicht)

Der Code sieht wie folgt aus:


        void RP6PortWrapper_DataAvailable(string obj) //Weitergeleitetes Event von SerialPort.DataReceived
        {
            if (!tbxDataReceived.IsDisposed && tbxDataReceived.IsHandleCreated)
            {
                if (tbxDataReceived.InvokeRequired)
                {
                    tbxDataReceived.Invoke(new Action(() => AppendNewText(obj))); //Hier kommt der Fehler
                }
                else
                {
                    AppendNewText(obj);
                }
            }
        }

        private void AppendNewText(string text)
        {
            if (tbxDataReceived.Text.Length > 5000)
            {
                string tmp = tbxDataReceived.Text.ToString();
                tbxDataReceived.Clear();
                tbxDataReceived.AppendText(tmp.Substring(2500));
            }
            tbxDataReceived.AppendText(text);
        }

Das klappt soweit auch schon ziemlich gut, keine Fehler oder sonstiges.
Die Probleme treten erst beim Schließen der Form auf.
Dann wird des Öfteren (allerdings nicht reproduzierbar) folgende Exception geworfen:

Fehlermeldung:
'Control.WaitForWaitHandle': Fehler: Invoke oder BeginInvoke kann für ein Steuerelement erst aufgerufen werden, wenn das Fensterhandle erstellt wurde.

InnerException:

StackTrace: bei System.Windows.Forms.Control.WaitForWaitHandle(WaitHandle waitHandle)
bei System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
bei System.Windows.Forms.Control.Invoke(Delegate method, Object[] args)
bei System.Windows.Forms.Control.Invoke(Delegate method)
bei RP6Remotrol.Forms.GeneralForms.TerminalForm.RP6PortWrapper_DataAvailable(String obj) in H:\RP6\RP6 Remotrol\C#\RP6Remotrol\Forms\GeneralForms\TerminalForm.cs:Zeile 29.
bei System.Action`1.Invoke(T obj)
bei RP6Remotrol.RP6Library.RP6PortWrapper.Port_DataReceived() in H:\RP6\RP6 Remotrol\C#\RP6Remotrol\RP6Library\RP6PortWrapper.cs:Zeile 166.
bei RP6Remotrol.RP6Library.RP6SerialPort.port_DataReceived(Object sender, SerialDataReceivedEventArgs e) in H:\RP6\RP6 Remotrol\C#\RP6Remotrol\RP6Library\RP6Port.cs:Zeile 32.
bei System.IO.Ports.SerialPort.CatchReceivedEvents(Object src, SerialDataReceivedEventArgs e)
bei System.IO.Ports.SerialStream.EventLoopRunner.CallReceiveEvents(Object state)
bei System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
bei System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
bei System.Threading.ThreadPoolWorkQueue.Dispatch()
bei System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()

Methode: Void WaitForWaitHandle(System.Threading.WaitHandle) (Das ist die Ausgabe meines Logs)

Wie man in meinem Code sieht, habe ich schon versucht, das Problem mit .IsHandleCreated zu umschiffen, leider ohne Erfolg...
Zusätzlich habe ich versucht das Event beim Schließen abzumelden:


        private void TerminalForm_FormClosing(object sender,  FormClosingEventArgs e)
        {
            RP6PortWrapper.DataAvailable -= RP6PortWrapper_DataAvailable;
        }

Auch das führt nicht zum gewünschten Ergebnis...
Ich bin jetzt etwas ratlos...

Das Event dürfte nach dem Dispose der Textbox nicht mehr aufgerufen werden,
und selbst wenn, dann dürfte das Invoke nicht mehr aufgerufen werden...
Trotzdem passiert all das...

Kann mir da irgendjemand helfen?

17.12.2010 - 22:41 Uhr

Nene, dein Designer findet das neue Beta-Update nicht...

17.12.2010 - 12:06 Uhr

Ich hätte noch eine kleine Anregung.
Ich kam auf die Idee, als ich mir Gedanken darüber machte, was passiert, wenn der Updater feststellt, dass ein Paket korrupt ist.

In diesem Fall gibt es zwei Möglichkeiten: entweder ist der Download des Pakets fehlerhaft oder jemand hat mutwillig das Paket verändert.
Im zweiten Fall ist natürlich größte Vorsicht geboten.

Nun würde mich interessieren, was in so einem Fall passiert. Wird der Entwickler irgendwie darüber benachrichtigt?

Meine Idee bestände nun darin, auf die Startseite eine kleine Übersicht einzubauen, in der man aktuelle Ereignisse präsentiert bekommt.
Dort könnte man z.B. auch die neusten Downloadzahlen anzeigen, sofern die Statistik aktiviert ist.

Das ganze könnte man auch schon als kleines PopUp-Fenster realisieren.
Unter anderem wäre dies dann auch ein geeigneter Platz um dem Entwickler mitzuteilen, dass eines seiner Updates kaputt ist.
(Natürlich müsste der Client das Paket öfters herunterladen, um festzustellen, dass es wirklich kaputt ist und nicht am Download lag.)

Kommst du so ein bisschen mit, worauf ich hinaus will? 😉 Klingt jetzt alles ein bisschen kompliziert glaube ich 😉

Achja, warum zeigt dein Updater die neue Betaversion nicht an wenn ich danach suche? Suche nach Beta ist natürlich aktiv.

27.11.2010 - 21:35 Uhr

Nähere Infos hast du per PM.

Noch eine Frage zu den Servicepacks:
Im Updater werden die Versionen vor einem Servicepack ausgegraut dargestellt.
Wenn man sucht werden die Updates davor aber noch angezeigt.
Runtergeladen werden sie aber ja nicht oder? Anzeige ist nur wegen dem Changelog?

27.11.2010 - 20:15 Uhr

Super, das klappt jetzt sehr gut!
Was ich allerdings auch noch gut fände, wenn du die Fenster Modal öffnen würdest.
Das reduziert nochmals die Chance, dass man ein Updatefenster einfach ausversehen gar nicht sieht.
Ist mir nämlich beim Testen ein paar Mal passiert...
Kannst du ja auch anpassbar machen über eine kleine Property.

Ansonsten bin ich grade wunschlos glücklich! Super Sache! =)

Achja, wie stehts eigentlich um diese neue überarbeitete Version?

23.11.2010 - 21:52 Uhr

Hey Fabian,

Gibt es eine Möglichkeit, die Update-Fenster, sowohl beim interaktiven, als auch beim asynchronen Vorgang auch als Fenster in der Taskleiste anzeigen zu lassen?
mmh ... das versteh ich irgendwie nicht, interaktiv ok, kann man optional machen (sofern du die ShowInTaskBar-Property meinst), aber was fürn Fenster willste denn beim asynchronen Vorgang in das Taskleiste haben, da gibts doch gar keines 👶

Naja, ich lasse z.B. beim Start meiner Awendung automatisch auf Updates prüfen.
Wenn etwas gefunden wurde rufe ich folgenden Code auf:

if (controller.showUpdateDialog() == DialogResult.OK && controller.downloadUpdatesDialog() == DialogResult.OK)
            {
                controller.applyUpdate();
            }

Und die zwei Dialoge die nun aufgehen sieht man leider nicht in der Taskbar.
Also können sie recht leicht "verloren gehen" wenn man mal daneben klickt.
Einfach immer optional machen? Ich glaube das wäre die sinnigste Lösung.

Wird updateFound des Controllers beim interaktiven Suchen nicht aufgerufen?
Nope, fand ich irgendwie nicht Sinnvoll, zumal du das Ergbnis (ob Updates verfügbar oder nicht) ja übers DialogResult herausbekommst. Die genauen Informationen stehen dann ja in der Eigenschaft currentUpdateResult.

Ich lasse dort aber mein Log mitlaufen, wäre zumindest also in meinem Fall sinnvoll.
Gibts ne Chance, dass du das schnell einbaust?
Sollte ja eigentlich kein Aufwand sein oder Probleme bereiten.

Ist es vielleicht möglich, dass du statt .NET 4 nur die Clientversion nimmst oder brauchst du das ganze Paket?
Ich brauch die System.Design.dll die es leider nicht im Clientpaket gibt.

Alles klar.

22.11.2010 - 23:41 Uhr

Ist es vielleicht möglich, dass du statt .NET 4 nur die Clientversion nimmst oder brauchst du das ganze Paket?

22.11.2010 - 21:49 Uhr

Ich hätte noch zwei Fragen:*Gibt es eine Möglichkeit, die Update-Fenster, sowohl beim interaktiven, als auch beim asynchronen Vorgang auch als Fenster in der Taskleiste anzeigen zu lassen? *Wird updateFound des Controllers beim interaktiven Suchen nicht aufgerufen?

Vielleicht habe ich auch einfach etwas übersehen, muss mich grade wieder in das Projekt einarbeiten...
Aber bis hierhin echt eine super gute Arbeit! =)
Mach weiter so! =)

18.07.2010 - 20:05 Uhr

Hallo,
ich stelle mir die Frage, ob es möglich ist, einen Serial-Port, der in einem anderen programm geöffnet ist, irgendwie zu entsperren und in meinem Programm zu öffnen.
Ich möchte also quasi das andere Programm ausschließen.
Der andere Prozess sollte dabei aber schon weiterlaufen.
Gibt es da irgendeine Möglichkeit?

12.07.2010 - 12:31 Uhr

Okay, dann werde ich das mit dem Baumodus ändern. Die Version jetzt ist halt etwas schwerer.

Lua werde ich mir dann auch mal ansehen, ich habe eh noch nie was mit Scripten gemacht! =) Kannst du vielleicht ein Beispiel nennen, was man damit so machen kann?
Wie gesagt, hab mich damit noch nie auseinandergesetzt.

12.07.2010 - 11:13 Uhr

Hm, dass die Dateien nicht mehr vorhanden sind kann sogar wirklich sein... Ich werds auf jeden fall testen!

Mein aktuelles Projekt hat eine etwas größere Ordnerstruktur. (ca 12 Ordner)
Diese Ordner sind natürlich auch verschachtelt. Wenn ich jetzt eine Datei in
den letzten Ordner kopieren will muss ich erst zig Verzeichnisse im Updater
erstellen. Beim nächsten Update das selbe Spiel.
Deswegen solltest du die Verzeichnisse speichern.

Jetzt verständlich? Wenn nicht poste ich noch einen Screenshot.

12.07.2010 - 10:53 Uhr

Zum Internet: der Updater kann es eigentlich nicht sein, der wird nichtmal erstellt. Vielleicht der Logger, muss ich msl sehen. Das ganze passiert beim ersten Start mitten im Spiel?

Zum Bauen der Türme: das ist sogar so gedacht! Nur stimmen die Wartezeiten für die Creeps halt noch nicht. Wenn das alles ein nettes Balancing erfahren hat klappt das auch! =)

Zum Thema Scripte muss ich mir mal überlegen, ob der Aufwand den Nutzen wert ist. Aber danke für den Vorschlag. Klappt Lua gut mit .Net?

Balancing ist eigentlich fast noch gar nicht vorhanden. Aber das kommt schon noch, keine Angst 😉

@Blacal: ich melde mich später mal bei dir, Hilfe kann ich immer gebrauchen! =)

11.07.2010 - 22:39 Uhr

Hallo,

ich möchte euch mein aktuelles Projekt vorstellen.
Dabei handelt es sich um einen Towerdefence-Klon.
Ich hatte allerdings ein paar Anforderungen, die ich so noch nicht gefunden habe:*Die Gegner haben keinen festen Weg, sondern suchen sich autonom einen durch das Level. So kann man mit den Türmen einen Hindernis-Parkour bauen. *Hohe Flexibilität: Jeder Turm besteht aus einer Dll und einer Xml-Datei. Dabei ist es dem Spiel ersteinmal egal welche Türme vorhanden sind.
Es sucht nach passenden Dateien und fügt diese dem Spiel dynamisch hinzu.
Löscht man einen oder mehrere Türme, so tauchen sie auch nicht im Spiel auf.

*Somit lassen sich sehr leicht neue Türme entwickeln, ohne die gesamte Struktur des Spiels zu kennen.
Einfach den Code eines vorhandenen Turms anschauen und schon kann man eigene entwickeln.

*Mit dem Turmeditor kann man ganz gezielt fast alle Werte eines Turmes verändern.
Einzig und allein die Verhaltensweise eines Turmes muss programmiert werden, der Rest ist mit dem Editor möglich.

*Der Leveleditor kann neue Level erzeugen und die dazugehörige Gegnercharakteristik einbinden. *Auch für die Level gilt, dass das Spiel die Levels nicht kennen muss. Sie werden dynamisch ins Spiel geladen. *Natürlich ist auch ein leistungsstarker Logger vorhanden, der die Fehlersuche stark erleichtert und auch direkt eventuelle Fehler an mich senden kann.
Weiterhin können auch anonyme Perfomance-Daten versendet werden.

*Das Spiel besitzt auch einen automatischen Updater, der das Spiel immer auf der neusten Version hält.

Das Spiel ist noch weit davon entfernt fertig zu sein, da vorallem noch das Balancing der bis jetzt 9 Türme fehlt.

Ich stelle das Projekt hier vor, da ich eigentlich ein paar Leute suche, die Lust haben, hier mitzumachen und dabei vielleicht auch das ein oder andere zu lernen. =)

Als Aufgaben gibt es vieles zu nennen:*Entwicklung am Spiel selbst (Optimierungen, GUI, neue Features) *Entwicklung neuer Türme (hier sind auchIdeen gefragt) *Balancing der Türme (Schaden, Reichweite, etc müssen aufeinander abgestimmt werden) *Balancing der Levels (Die Stärke der Gegner muss eingestellt werden) *Erstellung neuer, kreativer Level (Die "Form" an sich) *Erstellung weiterer Grafiken für Türme, Level, Gegner, ... *Weiterentwicklung der Editoren (Auch hier ist noch etwas Arbeit, hauptsächlich GUI)

Das Spiel liegt auf Sourceforge und ist dementsprechend OpenSource.

Im Anhang findet ihr eine lauffähige Version des Spiels mit allen Türmen und zwei Levels.
Allerdings sind auch die Level noch nicht ausbalanciert was die Gegner betrifft.

Ansonsten bin ich über jeden Helfer froh und wünsche euch viel Spaß beim Testen.

Natürlich solltet ihr XNA 3.1 installiert haben damit das ganze läuft 😉

PathDefence 0.5.0.0

11.07.2010 - 18:56 Uhr

Ich habe noch einen Bug gefunden.
Wenn ich ein Update erstelle und danach bearbeite,
dann zeigt er mir nicht mehr an, welche Dateien wohin
kopiert werden sollen. (s. Screenshot)

Außerdem wäre es noch schön, wenn der Focus beim
Erstellen eines neuen Verzeichnisses direkt auf der TextBox läge. =)

10.07.2010 - 22:59 Uhr

Ich hätte noch eine Idee:
Ich habe mir gerade ein kleines Programm geschrieben, welches die Unterschiede zweier Versionen heraussucht.
Also die Dateien miteinander vergleicht und dann ausgibt welche Dateien hinzugefügt, gelöscht oder modifiziert wurden.
Es wäre hilfreich, wenn der Updater-Ersteller eine Art API hätte, mit der man soetwas machen kann.
Also liest dein Programm eine Textdatei ein, in der nach gewissen Regeln die Dateien drin stehen.
Außerdem wäre es schön, wenn man beim hinzufügen von Dateien zum Update 1. mehrere hinzugefügte Dateien gleichzeitig löschen könnte und [ENTF] die Dateien auch löschen würde.

Eine weitere Idee: Die Möglichkeit zu jedem Projekt eine Verzeichnisstruktur anlegen zu können. Dann muss man nicht jedes Mal beim Update die ganze Ordner hinzufügen.

Im Anhang noch eine mögliche Ausgabe, die der Updater behandeln könnte.

10.07.2010 - 17:42 Uhr

Die Pause kann sich schon so über 5-10 Sekunden erstrecken.
Meistens aber so 3-4. War auch nur ein Vorschlag 😉
Ich schließe halt auch noch mein Programm vor dem installieren, deswegen ist dann erstmal gar nichts zu sehen.
Noch etwas:
Wenn ich eine Beta veröfefntliche, dann wäre es schön, wenn in dem Dialog "neues Update verfügbar" auch neben der Versionsnummer ein "Beta" stehen würde. =)

10.07.2010 - 17:24 Uhr

Hallo,
ich habe gerade deine Bibliothek ausprobiert und bin geradezu begeistert =)
Das klappt ja lles super! =)
Arbeitest du noch an dem Projekt? Ich hätte nämlich auf die Schnelle noch eine Verbesserung.
Nachdem die Updates heruntergeladen wurden entsteht eine relativ lange Pause bevor sie installiert werden.
Vielleicht könntest du dort noch ein kleines Fenster einbauen, dass zeigt, dass der Update-Vorgang noch läuft.

Ansonsten echt eine super Sache. =)

10.06.2010 - 18:17 Uhr

So, mit TextBox.AppendText klappt das ganze zumindest etwas flackerfreier, aber auch nicht perfekt.
Suspend und ResumeLayout verstehe ich entweder nicht, oder es klappt nicht.
Hier der Code:

private void SetText(string text)
        {
            if(tbxDataReceived.InvokeRequired)
            {
                try
                {
                    tbxDataReceived.Invoke(new Action<string>(SetText), text);
                }
                catch (InvalidOperationException){} //Hier Fehler beim Schließen
            }
            else
            {
                tbxDataReceived.SuspendLayout();
                try
                {
                    tbxDataReceived.AppendText(text);
                }
                catch (ObjectDisposedException) { } //Hier Fehler beim Schließen
                //tbxDataReceived.ResumeLayout();
            }
        }

Ich habe das Resume mal auskommentiert und eigentlich müsste doch dann gar keine Layoutänderung mehr stattfinden oder?
Das ist aber nicht der Fall. Ich kann da alles fröhlich ein- und auskommentieren, ohne das sich irgendwas ändert.
Die Box scrollt weiterhin bei jedem Hinzufügen nach ganz unten.
Was lässt sich dagegen tun?

08.06.2010 - 21:37 Uhr

Also ich habe eine einfache Textbox mit Multiline, einer vertikalen Scrollbar und sonst eigentlich nichts an ihr geändert.
Jetzt möchte ich in einem Event von einem Timer Daten hinzufügen.
Und zwar so ähnlich:

tbxData.Text += text;

Das ganze kann auch etwas öfter aurgerufen werden. Wenn ich das jetzt allerdings so mache flackert hat die ganze Textbox. Doubblebufferd der Form bringt nichts.
Weiterhin scrollt die Textbox beim Anfügen automatisch nach ganz oben.
Ein setzen der SelectionStart-property und anschließendes .ScrollToCaret bringt zwar den gewünschten Effekt des Autoscrollen allerdings flackert nun die Scrollleiste immer von nach unten.

08.06.2010 - 17:32 Uhr

ich habe doch gar nichts als unpassend empfunden!=)
Wenn ich euch keine Infos gebe kann ich ja auch nicht erwarten,
gute Infos zurück zu bekommen.
Problem ist nur, dass ich nicht zu Hause bin, dachte das wäre vielleicht ein bekannteres Problem oder so.
Code kommt später.

08.06.2010 - 16:44 Uhr

Na das klingt doch toll! =)
Mag mir auch noch jemand sagen wie?
Meine Textbox scroollt immer und flackert.
Was muss ich tun?

08.06.2010 - 11:19 Uhr

hallo,
folgendes Problem: ich bracue eine Textbox-Komponente, die eine Reihe von bestimmten Berhalten aufweisen muss.

Wenn Text HINZUGEFÜGT wird, solül dieser natürlich am Ende hinzugefügt werden,
und zwar ohne Flimmern und auch ohne,dass die Textbox direkt nach unten scrollt.
Ich will den Text manipulieren können,ohne dass die aktuelle Scroll-Position verloren geht.
Weiterhin brauche ich dann Methoden um gezielt scrollen zu können.
Dazu gehört eigentlich nur das Scrollen zum Anfang und zum Ende.

Geht das vielleicht schon mit der normalen Box?

06.06.2010 - 19:48 Uhr

Die von BaseForm abgeleiteten Forms müssen ab und zu sowieso die MainForm kennen, deswegen ist das nicht schlimm 😉
Aber das mit dem Type.ToString stimmt wohl, da kann ich auch direkt den Type nehmen.
Danke.=)

06.06.2010 - 16:47 Uhr

Naja, ich habe halt eine Form erstellt, die ist leer und ist die BaseForm:


    public class BaseForm : Form
    {
        protected MainForm FormParent;

        public virtual void Initialize(MainForm parent)
        {
            FormParent = parent;
        }

        private void InitializeComponent()
        {
            SuspendLayout();
            // 
            // BaseForm
            // 
            ClientSize = new Size(284, 262);
            Name = "BaseForm";
            StartPosition = FormStartPosition.CenterParent;
            FormClosed += BaseForm_FormClosed;
            ResumeLayout(false);
        }

        public virtual void ResetFeatureData()
        {
        }

        protected virtual void BaseForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            FormParent.Forms.Remove(GetType().ToString());
        }

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            if (keyData == Keys.Space)
            {
                RP6Controler.Stop();
                return true;
            }
            return base.ProcessCmdKey(ref msg, keyData);
        }
    }

Ich frage mich im Übrigen auch gerade, warum meine Form keine Designer-Datei hat...
Gut, dann ist klar, warum das event nicht aufgerufen wird.
Es wird nie zugewiesen.

Gut, damit hat sich das Problem dann auch schon gelöst...
Ich rufe einfach InitializeComponent selbst auf.

Danke trotzdem =)

06.06.2010 - 16:07 Uhr

Naja ich habe in der BaseForm ja das die Methode ja auch dem Event zugewiesen.
Da sollte man och eigentlich erwarten, dass als erstes die Events der BaseForm abgearbeitet werden und dann danach eventuelle Events der neuen Form.
Das ganze hin und her mit Dictionary ist wirklich etwas umständlich, das gebe ich zu, aber es funktioniert eigentlich ziemlich perfekt.
Es dient eigentlich dazu, dass 1. Keine Form doppelt geöffnet wird,
2. dass wenn die Form schon offen ist, ich sie in den Vordergrund bringen kann und
3. dass ich einen einzigen Befehl habe um "schön" alle meine Forms öffnen zu können.

OpenForm<SteeringForm>(true);

Das bekomme ich sonst nicht so schön hin denke ich.

Aber ich meine es muss doch möglich sein, dass auch die definierten Events einer Mutterform(Klasse) abgearbeitet werden, oder?

06.06.2010 - 14:49 Uhr

Hallo,

folgendes Szenario:
Ich habe eine BaseForm. Von dieser Baseform werden sehr viele neue Forms abgeleitet.
Eine jede dieser neuen Forms kann über diesen Code hier geöffnet werden:


public T OpenForm<T>(bool open) where T : BaseForm, new()
        {
            if (!Forms.ContainsKey(typeof(T).ToString()))
            {
                var form = new T();
                Forms.Add(form.GetType().ToString(), form);
                form.Initialize(this);
                if (open)
                    form.Show();
                return form;
            }
            else
            {
                BaseForm form = Forms[typeof(T).ToString()];
                form.BringToFront();
                return (T)form;
            }
        }

Daher auch die Notwendigkeit einer solchen BaseForm, ich möchte ja schließlich spezifische Methoden wie z.B. das Initialize() aufrufen.

Die Zeile Forms.Add(form.GetType().ToString(), form); hat den Zweck, die erstellte Form in einem Dictionary zu speichern, um später darauf Zugriff zu haben.
Allerdings muss die Referenz auf diese Form auch wieder aus dem Dictionary entfernt werden, wenn die Form geschlossen wird.

Dazu habe ich in der BaseForm das Event FormClosed genommen und entferne dort über eine Referenz auf die MainForm den Eintrag aus dem Dictionary.

Das sieht so aus:


protected virtual void BaseForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            FormParent.Forms.Remove(GetType().ToString());
        }

Das klappt aber leider nicht. Dieses Event wird nicht aufgerufen, wenn eine der abgeleiteten Forms geschlossen wird.
Ich erreiche dieses Ziel erst, wenn ich in jeder der neuen Forms folgendes einfüge:

protected override void BaseForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            base.BaseForm_FormClosed(sender,e);
        }

und dann noch das FormClosed-Event auf diese Methode lege.
Alles also sehr umständlich.

Meine Frage wäre nun, wie man das Verhalten der Form so beeinflussen kann, dass das Event in der BaseForm schon aufgerufen wird und ich nicht erst in jeder Form alles einfügen muss.

05.02.2010 - 15:22 Uhr

Okay, die Schleife da läuft jetzt maximal 100 Mal durch. Trotzdem würde es mich interessieren warum beim Schreiben eine TimeoutExeption auftritt...
Wann genau passiert das denn? MSDN ist da nicht so wirklich präzise.

Fabi

05.02.2010 - 00:24 Uhr

Naja, das Event macht nicht viel:

void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            if (DataReceived != null)
                DataReceived(Port.ReadExisting());
            timeOutWatch.Reset();
            timeOutWatch.Start();
        }

Die timeOutwatch ist eine Stopwatch, die ich verwende um festzustellen ob mein kleiner Roboter noch sendet.

Das Event oben kapselt eben nur das eigentliche Event des Ports, da man da nicht mehrere Empfänger sinnvoll registrieren kann...

Dann erkläre ich nocheinmal den Ablauf:

  1. Mein Roboter sendet alle ca. 400ms einen Frame von Daten. Also ein Startsignal ein paar Daten (Sensorwerte) und dann ein Endsignal.
  2. Mein Programm schickt dem Roboter einen Befehl. Der besteht nur aus ein paar Zahlen, Trennzeichen und Start/stop-Signalen. Z.B. :"#1:125:125:1*"
    Wenn der Roboter den Befehl komplett erhalten hat (keine Übertragungsfehler) sendet er ein "OK" zurück.
  3. Wenn mein Programm nun was schicken will tut es das solange, bis das Programm im empfangenen Text (die daten von den Sensoren + evtl. das OK) ein OK findet.
    Allerdings dauert die Übertragung, Verarbeitung und das Senden des OKs auf dem Roboter nunmal etwas Zeit. Nicht viel, aber immerhin gehts nicht direkt. Deswegen warte ich nach dem Senden eines Befehls ein wenig, sodass oft der Befehl danach schon verarbeitet wurde und der PC auch schon das OK empfangen hat. Ein weiteres Senden wird überflüssig.

Ich habe also jetzt festgestellt, dass das schreiben in den Port mit einer TimeoutException fehlschlägt. Deswegen reagiert der Worker nicht mehr und ich lande in der Endlosschleife.
Es stellt sich trotzdem noch die Frage, warum die Exception auftritt.

04.02.2010 - 18:40 Uhr

Das Sleep sorfgt dafür, dass die Schleife nicht allzu oft aufgerufen wird bevor sie wegen empfangenen OK abgebrochen wird.
Eigentlich reduziert es nur den Datenverkehr und kann auch prinzipiell weggelassen werden.

DataReceived(String) ist ein von mir definiertes Event, welches dazu dient, den empfangenen Text mehreren Abnehmern zur Vefügung zu stellen.
Das eigentliche Event des Portes hat in den Parametern den Text ja leider nicht dabei.

ReceivedText ist eine statische string Variable der Klasse :

private static volatile string ReceivedText;
04.02.2010 - 13:21 Uhr

Zum besseren Verständnis dann doch hier mal der Code:
Eine Klasse die den Port überwacht kapselt folgendes Event:


void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            if (DataReceived != null)
                DataReceived(Port.ReadExisting());
            timeOutWatch.Reset();
            timeOutWatch.Start();
        }

Damit wird der empfangene Text wirklich über ein Event verfügbar gemacht.
Dann habe ich zwei Klassen, die den Text verarbeiten, die eine ist rein passiv und liest nur die Daten mit um damit ein paar Sensorwerte und so anzeigen zu können.
Die andere allerdings ist der Controller für den Roboter. Sie sendet ihm Befehle. Leider gibt es ab und zu Übetragungsfehler aufgrund der Funkverbindung mit dem Roboter und deswegen bekommt der Roboter den Befehl nicht zwangsläufig.
Also Sendet er einen Befehl ("OK") wenn er einen gültigen Befehl erhalten hat.
Der Controller sendet nun solange den gewünschten Befehl, bis er ein "OK" vom Roboter bekommt.
Das sieht so aus:


void asyncWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            bool cancel = false;
            ResetReceivedText();
            do
            {
                SendCommand(e.Argument.ToString());
                string tmp = ReceivedText.Trim();
                Thread.Sleep(200);
                foreach (var s in tmp.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries))
                {
                    if (s == "OK")
                    {
                        cancel = true;
                        break;
                    }
                }
            } while (!asyncWorker.CancellationPending && !cancel);
        }

ResetReceivedText löscht einfach den Inhalt von ReceivedText. Eigentlich funktioniert das ganze ja auch genau so wie ich mir das vorgestellt habe...
Nur dieser eine blöde Fehler tritt immer wieder auf.
Zum Thema TimeOut/Deadlock: Wann genau tritt denn der Timeout auf? Und wenn sich mein Worker festfährt, warum friert das meinen GUI-Thread ein?

Ich habe noch eine Idee, ich habe folgenden Code um einen Befehl zu senden:


public void EnqueueCommand(string command)
        {
            lastCommand = command;
            while (asyncWorker.IsBusy)
            {
                asyncWorker.CancelAsync();
            }
            asyncWorker.RunWorkerAsync(lastCommand);
        }

Da könnte theoretisch ein Deadlock entstehen... Dazu müsste dann allerdings der worker überhaupt nicht mehr reagieren... Wie kann das sein?

Achja SendCommand ist ganz einfach:


private void SendCommand(string cmd)
        {
            if (Port.IsOpen)
            {
                Port.WriteString(cmd);
            }
        }

Fabi

EDIT: Also das Prgramm verfängt sich in der Schleife bei EnqueueCommand... Nun weiß ich aber trotzdem noch nicht warum der Backgroundworker nicht mehr reagiert. Er hat schließlich eine Abbruchbedinung wenn jemand das Senden beenden möchte...

04.02.2010 - 11:21 Uhr

Ja, das Programm bleibt nur hängen. Das komische ist nur, das in meinem Code meiner Meinung nach nichts drin ist, was zu zu einer Endlosschleife mutieren könnte...
Es gibt wie gesagt nur diesen einen Backgroundworker, keine Ahnung ob das damit auch möglich ist...
Was ich mir etwas problematisch vorstelle ist die Tatsache, dass ich vom Backgroundworker und vom GUI-Thread aus auf die selbe Variable zugreife.
Von beiden lesend und schreibend. Kann das dazu führen, dass sich das Programm ohne jegliche Fehler aufhängt?

Konkret ist es so, dass ich im GUI-Thread die am SerialPort empfangenen Daten in eine static Variable schreibe und im Worker-Thread wieder auslese und auch die Variable komplett leere.

Könnte das das Problem sein?

Fabi

03.02.2010 - 18:35 Uhr

Hallo,
ich habe ein Problem mit einem meiner Programme. Es dient zur Kommunikation über einen SerialPort mit einem dort angeschlossenen Roboter.
Leider stürzt das Programm sporadisch einfach ab bzw reagiert nicht mehr. Allerdings kommt dabei vom Debugger keine Fehlermeldung und sonst passiert auch einfach nichts... 😦
Das Programm benutzt auch noch einen Backgroundworker um die empfangenen Daten zu analysieren...

Gibt es irgendeine Möglichkeit dahinter zu kommen was da schief geht?

Fabi

29.11.2009 - 09:32 Uhr

Hallo,

ich bin gerade dabei eine kleine Suchfunktion zu schreiben.
Dazu würde ich gerne implementieren, dass die Suche auch ein wenig fehlertolerant ist. Dazu habe ich einen Suchstring, der auch aus mehreren Wörtern, die durch Leerzeichen getrennt sind, bestehen kann und ein Array das alle Wörter des Textes genau einmal enthält.
Wenn nun ein Wort aus dem Array mit einem der Wörter aus dem Suchstring (fast) übereinstimmt würde ich gerne etwas Code ausführen.
Hat dazu jemand eine Idee oder ein Stichwort oder so?

Liebe Grüße,
Fabi

22.11.2009 - 16:04 Uhr

Achso, danke, dann ist das jetzt natürlich einfach =)

Fabi

22.11.2009 - 15:59 Uhr

Er soll ja gar keine 30 Zeichen zurückgehen... Er soll mir nur von 0 an über die nächsten 30 Zeichen die Position des letzten Space geben, oder hab ich da was falsch verstanden? Das mit den 30 Zeichen zurück mache ich doch selbst...

Fabi

22.11.2009 - 15:53 Uhr

Ja, zum Verständnis hier mal mein Code dazu:


//contextStart beinhaltet den bisherigen Startpunkt zum Auslesen
//text ist einfach der gesamte Text, etwa 1800 Zeichen lang
int startSearchPosition = contextStart - 30 < 0 ? 0 : contextStart - 30;
//Das hier wäre dann der endgültige Punkt, mit einem kompletten Punkt am Anfang
int nextStartSpace = text.LastIndexOf(" ", startSearchPosition, 30);

Nun bekomme ich hier aber die Fehlermeldung, dass der Parameter Count entweder nicht positiv oder außerhalb des Textes sei. startSearchPosition ist allerdings 0, deshalb kann ich das absolut nicht nachvollziehen....

Fabi

22.11.2009 - 15:44 Uhr

Genau 😉
Konkret geht es darum zu einem Suchergebnis den Kontext anzuzeigen. Dazu will ich halt um den Treffer herum noch etwas Text auslesen.

Fabi

22.11.2009 - 15:36 Uhr

Hallo,

ich habe einen String mit normalen Text gefüllt, eine Position in diesem String, welche auch mitten in einem Wort sein kann, und möchte nun das erste Leerzeichen vor der gegebenen Position finden.
Also z.B.:
String:

Dies ist ein kleiner Teststring.

So, meine Position ist nun z.B. 17. Wie bekomme ich nun den String

kleiner Teststring

raus?
Ich habe schon ein bisschen mit LastIndexOf versucht, aber das hat nicht so wirklich funktioniert...

Vielen Dank,
Fabi

15.11.2009 - 17:22 Uhr

Aber du hast Windows 7?
Schonmal ein Treiberupdate probiert?

Fabi

15.11.2009 - 17:18 Uhr

Versuch mal noch den Parent des Shapes zu setzen.

fabi

15.11.2009 - 16:29 Uhr

Im Anhang siehst du es, bei einem Klick auf den Stop-Button hätte sich das Symbol mit der grünen Ecke in eines mit einer blauen Ecke verwandelt, bzw. tut es, es wird nur nicht angezeigt.

Fabi

15.11.2009 - 16:06 Uhr

Okay, ich glaub den Aufwand ist es nicht wert.
Prinzipiell klappt das mit dem kurz Einblenden zwar, aber dann müsste ich noch eine gewisse Zeit warten bis alles gezeichnet ist und darf die Form nicht direkt wieder minimieren. Außerdem geht dabei das Preview-Fenster zu, was natürlich absolut nicht zu gebrauchen ist.
Es geht also nicht. 😉

Fabi