Laden...
T
Torgrimm
myCSharp.de - Member
6
Themen
24
Beiträge
Letzte Aktivität
vor 12 Jahren
Dabei seit
10.05.2007
Herkunft
Aschaffenburg
Erstellt vor 12 Jahren

Vielen Dank erstmal euch beiden

Der von dir, gfoidl, vorgestellte Beitrag klingt schonmal ziemlich vielversprechend. Den Ansatz werde ich mir über das Wochenende einmal näher ansehen. Beim bisherigen Lösungssuchen bin ich auch immer wieder an den Punkt gestoßen, an dem sich der Hund in den Schwanz beißt.

@ Neidhard
Zur Datenmenge:
Dies hängt ein wenig vom überwachten Objekt und der konkreten Konfiguration ab.
Bei höchster Abtastrate sind das ca.: 1,7 MB/s. (Hier wird auf 11 Kanälen gemessen)
Die längsten Messungen wären bei der Konfiguration ca. 2 GB groß.

Theoretisch sind jedoch auch Maschinen im Dauerbetrieb als Überwachungsobjekte interessant. Hier würde die tatsächliche Datenaufzeichnung allerdings nur nach Verletzung von Grenzwerten erfolgen. Das Szenario ist bisher nur als Erweiterung vorgesehen.

Bei den KeyValuePairs war ich in der Tat etwas undeutlich. Da ich nur zwei Zustände speichere, ist es mir eigentlich egal was am Ende ausgegeben wir. Im konkreten Beispiel habe ich das float gewählt, da auf diese Weise die Schnittstelle nach außen hin gleich der der Analogdaten ist.

Ich habe den Code diesbezüglich kommentiert.

Erstellt vor 12 Jahren

Hallo,

ich erstelle derzeit ein Datenformat für große Messdateien. Dabei stoßen verschiedene Anforderungen zusammen und mir ist derzeit nicht komplett klar, wie ich diese alle technisch am besten vereine.

  1. Die Messdateien bestehen sowohl aus Header, als auch aus binären Messdaten. Die Headerdaten sollen in einem XML Format abgelegt sein.
  2. Die Messdatei muss hinsichtlich ihrer Struktur auf n-Analoge (float) und m-Digitale Kanäle ausgelegt sein. (n reicht dabei in der Praxis von 2 bis ~64, m von 8 bis 64)
  3. Eine Datei sollte hinsichtlich ihrer Größe möglichst unbeschränkt sein.
  4. Die Dauer einer Messung ist erst nach ihrem Ende bekannt.
  5. Lesender Zugriff muss wahlfrei möglich sein.
  6. Das Format muss mit dem Streaming Pattern vereinbar sein. Speziell WCF und FileStreams müssen unterstützt werden.
  7. Ein Live-Stream muss möglich sein. Hierbei ist der wahlfreie Zugriff nicht zwingend erforderlich.
  8. Der Aufbau der Headerdaten muss durch die Anwendung definiert werden können.
  9. Wünschenswert wäre eine Möglichkeit eine Datei digital signieren zu können.
  10. Die Speicherung der (digitalen) Daten muss effizient erfolgen. (Hinsichtlich des Speicherverbrauchs)
  11. Das Format kann keine Aussage über die Form der gespeicherten Analogdaten machen.

Unter einem Livestream verstehe ich in diesem Kontext das On-the-Fly weiterleiten von Messdaten vom Messgerät en die entsprechenden Konsumenten.
Ein Konsument kann z.B. eine grafische Darstellung oder eine Evaluierungsroutine sein. Dabei ist es erforderlich, dass es für den Konsumenten weitestgehend transparent ist, ob er mit Livedaten oder Daten aus dem Dateisystem arbeitet.

Nun meine Fragen:
Kennt jemand eine Implementierung die ähnliches Leistet?
Ich habe bisher vor allem versucht im Bereich von Multimedia (Video/Audio Streaming) Anregungen zu finden. Jedoch sind die Beispiele dort in der Regel schon sehr spezifisch und auf einem hohen Abstraktionslevel.

Mir bereitet derzeit das Live-Streaming Kopfzerbrechen. Im ersten Entwurf wird dieses Feature noch nicht unterstützt. Derzeit werden die Daten zum Zeitpunkt einer Messung im Speicher aufbereitet und bis zum Messungsende im Messungsobjekt gesammelt. Anschließend wird dieses Serialisiert. Um die Serialisierung möglichst einfach zu halten, wird diese über die DataContract und DataMember Attribute gesteuert. Dies hat nur den schwerwiegenden Nachteil, dass es bei längeren Messungen zu OutOfMemoryExceptions kommt. Auch ist ein Livesteam nicht möglich.
Nun möchte ich das Format, bzw. die Serialisierung so erweitern/ändern, dass diese Einschränkungen behoben werden. Welchen Ansatz sollte man hier verfolgen?

Eine Messung ist derzeit vereinfacht so aufgebaut:

	[DataContract]
	[KnownType(typeof(Channel))]
	[KnownType(typeof(BinaryChannel))]
	public class Measurement
	{
		[DataMember]
		public String Header1 { get; set; }
		[DataMember]
		public String Header2 { get; set; }
		[DataMember]
		public String Header3 { get; set; }
		[DataMember]
		public String Header4 { get; set; }
		[DataMember]
		public String Header5 { get; set; }

		[DataMember]
		public List<Channel> Channels { get; set; }
		public List<BinaryChannel> Channels { get; set; }
	}

	[Serializable]
	public class Channel
	{
		public String ChannelHeader1 { get; set; }
		public String ChannelHeader2 { get; set; }
		public String ChannelHeader3 { get; set; }
		public String ChannelHeader4 { get; set; }
		public String ChannelHeader5 { get; set; }

		float this[int index]
		{
			get
			{
				return Values[index];
			}
		}
		private List<Single> Values { get; set; }
	}

	[Serializable]
	public class BinaryChannel
	{
		public String BinaryChannelHeader1 { get; set; }
		public String BinaryChannelHeader2 { get; set; }
		public String BinaryChannelHeader3 { get; set; }
		public String BinaryChannelHeader4 { get; set; }
		public String BinaryChannelHeader5 { get; set; }

		float this[int index]
		{
			get
			{
				// calculate the actual value for the index and return it
				bool b = CalculateStateOfIndex(index);

				return b ? 1.0f : 0.0f; // Return 1 or 0, depending on the state
			}			
		}
		bool CalculateStateOfIndex(int Index) { ... }

		// This is only the internal storage of the Binary Values
		// Each entry in the list, represents a changed state on the binary channel
		// Key: The actual state, Value: Number of occurrences of the Key until the next state change
		private List<KeyValuePair<bool, int>> Values { get; set; }
	}

Extra:
Die Binären Daten werden derzeit unsauberer Weise Messheader mit abgespeichert. Gespeichert wird eine Liste von Paaren aus Zustand sowie Anzahl der Messwerte, dessen.
So wird aus der Binärfolge: 00001111111111111111111111111111111111111111111110000
0;4
1;45
0;4

Da sich die einzelnen Binärkanäle im laufe einer Messung nur selten ändern, kann auf diese Weise ein nicht unerheblicher Teil an Speicherplatz eingespart werden.
Zum live-streamen erscheint mir diese Vorgehensweise allerdings als eher ungeeignet, da die Länge mit jedem neuen Messwert aktualisiert werden müsste. Gibt es ein besseres Verfahren, als die 64 Bit für jeden Messwert neu zu senden?

Erstellt vor 15 Jahren

Kleine Anmerkung noch:
Wenn man die Assign Methode und den '=' Operator vom ConditionalAssignmentParser in den FctParser verschiebt funktioniert das ganze so wie es soll.

Ich bin damit allerdings noch nicht so richtig zufrieden und werde das Thema wieder verfolgen, sobald ich etwas mehr Zeit habe.

Erstellt vor 15 Jahren

EDIT: Vor etwas über einem Jahr dachte ich aber auch noch das man in C# Betriebssysteme in lowlevel entwickeln könnte 😄

Naja, prinzipiell ist das schon möglich und wird auch getan:
http://research.microsoft.com/en-us/projects/singularity/

Es ist nur die Frage wie LowLevel du gehen magst. Im Fall von Singularity sind (wenn mich mein Gedächtnis nicht trügt) ~98% des Codes in C# geschrieben. Der Rest sind aber auch wieder C und Assembler.

Erstellt vor 15 Jahren

Da schaut her:
http://www.microsoft.com/visualstudio/en-us/products/msdn/default.mspx#roadmap

Außerdem sind gerade die MSDN Lizenzinformationen erschienen, die könnten auch interessant sein:
http://download.microsoft.com/download/7/B/1/7B18407A-AC79-4949-A318-A6636D96F497/Visual%20Studio%202010%20Licensing%20-%20Feb-2010.pdf

Besonderen Lob verdient meiner Meinung nach, dass der TFS nun mit jeder MSDN Subscription verfügbar ist.

Erstellt vor 15 Jahren

Hallo,

ich habe mich mal daran gemacht und den offenen Punkt umgesetzt, mehrere Variablen verwenden zu können. Gelöst ist es wie von dir angeregt über ein Konstanten Dictionary. Im Prinzip funktioniert das auch genauso mit den Variablen selbst.

Außerdem ist es nun möglich Konstanten (oder apäter auch Variablen) in einer Formel mit dem '=' Operator zu setzen. Für meinen Anwendungsfall missbrauche ich den Parser ein wenig und arbeite mit Strings anstatt von Zahlen. Daher gibt es zwei neue Reservierte Zeichen, das '@' und das ".

Das '@' schließt eine Konstante ein, die auf ihren Wert aufgelöst werden soll (R-Value).
Das " schließt eine Konstante ein, deren Wert neu zugewiesen werden soll(L-Value) oder aber einen beliebigen String für eine Operation, zB. einen Vergleich (R-Value);

Beide Zeichen sind statisch in der Constant-Klasse belegbar. Die beiden Zeichen fügen sich in der Priorität noch vor den Klammern ein.

Soweit so schön. Dummerweise hat sich hier noch ein Bug eingeschlichen dem ich gerade etwas ratlos gegenüber stehe. Jedenfalls kann ich mir das beobachtete Verhalten nicht richtig erklären. Ihc habe dazu eine Beispielanwendung beigefügt, die den Fehler demonstriert.

Was ist eigentlich los?

Nun, die erste Instanz des Parsers funktioniert ganz tadellos.
Wird diese nun allerdings Zerstört und danach eine neue Instanz erzeugt, scheint die neue in einem bestimmten Kontext noch auf Constants der ersten Instanz zuzugreifen. Ich gehe davon aus, das in der Vererbung irgendwo der Bock steckt. Ich habe jedoch bereits mit allen möglichen Kombinationen von this, base und virtual rumgespielt - jedoch ohne positives Ergebnis.


    class Program
    {
    static void Main(string[] args)
        {
            Test();

            Debug.Print("\n\n\n\nZweiter Durchlauf:");
            Test();

        }

        private static void Test()
        {
            Dictionary<string, string> constantsIn = new Dictionary<string, string>();
            constantsIn.Add("a", "0");
            constantsIn.Add("b", "0");
            constantsIn.Add("c", "0");
            constantsIn.Add("d", "0");
            constantsIn.Add("e", "0");
            constantsIn.Add("f", "0");
            constantsIn.Add("g", "0");
            constantsIn.Add("h", "0");
            constantsIn.Add("i", "0");

            List<string> rules = new List<string>();
            rules.Add("\"a\" = \"1\"");
            rules.Add("\"b\" = \"2\"");
            rules.Add("\"c\" = \"3\"");
            rules.Add("\"d\" = \"4\"");
            rules.Add("\"e\" = \"5\"");
            rules.Add("\"f\" = \"6\"");
            rules.Add("\"g\" = \"7\"");
            rules.Add("\"h\" = \"8\"");
            rules.Add("\"i\" = \"9\"");

            ConditionalAssignmentParser<String, FctParser<Object>, Object> Parser = new ConditionalAssignmentParser<String, FctParser<Object>, Object>();

            // Hinzufügen der benötigten der VariDataObjecte als Konstanten in den Parser - LeftFile
            foreach (string s in constantsIn.Keys)
            {
                try
                {
                    Parser.AddConstant(s, constantsIn[s]);
                }
                catch (Exception ex)
                {
                    Debug.Print("Die Konstante " + s + " konnte dem Parser nicht hinzugefügt werden.", ex);
                }
            }

            foreach (string rule in rules)
            {
                try
                {
                    Parser.Parse(rule);
                }
                catch (Exception ex)
                {
                    Debug.Print("Fehler beim Ausführen einer Regel!", ex);
                }
            }

            // Die Geänderten Konstanten in die TransformFile übernehmen
            foreach (FctParser<String>.Constant result in Parser.Constants.Values)
            {
                Debug.Print(result.sConst + ": " + result.value);
            }
        }
    }

Die Methode Test() zweifach aufgerufen führt zu der folgenden Ausgabe:


Create FctParser: MathParser.ConditionalAssignmentParser`3 [System.String,MathParser.FctParser`1 [System.Object],System.Object] Hash: 45653674
Constants: System.Collections.Generic.Dictionary`2 [System.String,MathParser.FctParser`1+Constant [System.String]] Hash: 41149443
Create ConditionalParser: MathParser.ConditionalAssignmentParser`3 [System.String,MathParser.FctParser`1 [System.Object],System.Object] Hash: 45653674
Constants: System.Collections.Generic.Dictionary`2 [System.String,MathParser.FctParser`1+Constant [System.String]] Hash: 41149443
Create FctParser: MathParser.FctParser`1 [System.Object] Hash: 39785641
Constants: System.Collections.Generic.Dictionary`2 [System.String,MathParser.FctParser`1+Constant [System.Object]] Hash: 45523402
Create ConditionalAssignmentParser: MathParser.ConditionalAssignmentParser`3 [System.String,MathParser.FctParser`1 [System.Object],System.Object] Hash: 45653674
Constants: System.Collections.Generic.Dictionary`2 [System.String,MathParser.FctParser`1+Constant [System.String]] Hash: 41149443
[color]
Calculate Vorher a: 00 Constant Hash:41149443
Assign Vorher a: 000 Constant Hash:41149443
Assign sId Hash: -842352705 Constant Hash:41149443
Assign Nachher a: 111 Constant Hash:41149443
Calculate Nachher a: 11 Constant Hash:41149443
Calculate Hash in Calculate a: -842352705 Constant Hash:41149443
[/color]
Calculate Vorher b: 00 Constant Hash:41149443
Assign Vorher b: 000 Constant Hash:41149443
Assign sId Hash: -842352706 Constant Hash:41149443
Assign Nachher b: 222 Constant Hash:41149443
Calculate Nachher b: 22 Constant Hash:41149443
Calculate Hash in Calculate b: -842352706 Constant Hash:41149443
Calculate Vorher c: 00 Constant Hash:41149443
Assign Vorher c: 000 Constant Hash:41149443
Assign sId Hash: -842352707 Constant Hash:41149443
Assign Nachher c: 333 Constant Hash:41149443
Calculate Nachher c: 33 Constant Hash:41149443
Calculate Hash in Calculate c: -842352707 Constant Hash:41149443
Calculate Vorher d: 00 Constant Hash:41149443
Assign Vorher d: 000 Constant Hash:41149443
Assign sId Hash: -842352708 Constant Hash:41149443
Assign Nachher d: 444 Constant Hash:41149443
Calculate Nachher d: 44 Constant Hash:41149443
Calculate Hash in Calculate d: -842352708 Constant Hash:41149443
Calculate Vorher e: 00 Constant Hash:41149443
Assign Vorher e: 000 Constant Hash:41149443
Assign sId Hash: -842352709 Constant Hash:41149443
Assign Nachher e: 555 Constant Hash:41149443
Calculate Nachher e: 55 Constant Hash:41149443
Calculate Hash in Calculate e: -842352709 Constant Hash:41149443
Calculate Vorher f: 00 Constant Hash:41149443
Assign Vorher f: 000 Constant Hash:41149443
Assign sId Hash: -842352710 Constant Hash:41149443
Assign Nachher f: 666 Constant Hash:41149443
Calculate Nachher f: 66 Constant Hash:41149443
Calculate Hash in Calculate f: -842352710 Constant Hash:41149443
Calculate Vorher g: 00 Constant Hash:41149443
Assign Vorher g: 000 Constant Hash:41149443
Assign sId Hash: -842352711 Constant Hash:41149443
Assign Nachher g: 777 Constant Hash:41149443
Calculate Nachher g: 77 Constant Hash:41149443
Calculate Hash in Calculate g: -842352711 Constant Hash:41149443
Calculate Vorher h: 00 Constant Hash:41149443
Assign Vorher h: 000 Constant Hash:41149443
Assign sId Hash: -842352696 Constant Hash:41149443
Assign Nachher h: 888 Constant Hash:41149443
Calculate Nachher h: 88 Constant Hash:41149443
Calculate Hash in Calculate h: -842352696 Constant Hash:41149443
Calculate Vorher i: 00 Constant Hash:41149443
Assign Vorher i: 000 Constant Hash:41149443
Assign sId Hash: -842352697 Constant Hash:41149443
Assign Nachher i: 999 Constant Hash:41149443
Calculate Nachher i: 99 Constant Hash:41149443
Calculate Hash in Calculate i: -842352697 Constant Hash:41149443
T: 1
F: 0
true: 1
false: 0
a: 1
b: 2
c: 3
d: 4
e: 5
f: 6
g: 7
h: 8
i: 9




Zweiter Durchlauf:
Create FctParser: MathParser.ConditionalAssignmentParser`3 [System.String,MathParser.FctParser`1 [System.Object],System.Object] Hash: 35287174
Constants: System.Collections.Generic.Dictionary`2 [System.String,MathParser.FctParser`1+Constant [System.String]] Hash: 44419000
Create ConditionalParser: MathParser.ConditionalAssignmentParser`3 [System.String,MathParser.FctParser`1 [System.Object],System.Object] Hash: 35287174
Constants: System.Collections.Generic.Dictionary`2 [System.String,MathParser.FctParser`1+Constant [System.String]] Hash: 44419000
Create FctParser: MathParser.FctParser`1 [System.Object] Hash: 52697953
Constants: System.Collections.Generic.Dictionary`2 [System.String,MathParser.FctParser`1+Constant [System.Object]] Hash: 22597652
Create ConditionalAssignmentParser: MathParser.ConditionalAssignmentParser`3 [System.String,MathParser.FctParser`1 [System.Object],System.Object] Hash: 35287174
Constants: System.Collections.Generic.Dictionary`2 [System.String,MathParser.FctParser`1+Constant [System.String]] Hash: 44419000
[color]
Calculate Vorher a: 00 Constant Hash:44419000
Assign Vorher a: 111 Constant Hash:41149443
Assign sId Hash: -842352705 Constant Hash:41149443
Assign Nachher a: 111 Constant Hash:41149443
Calculate Nachher a: 00 Constant Hash:44419000
Calculate Hash in Calculate a: -842352705 Constant Hash:44419000
[/color]
Calculate Vorher b: 00 Constant Hash:44419000
Assign Vorher b: 222 Constant Hash:41149443
Assign sId Hash: -842352706 Constant Hash:41149443
Assign Nachher b: 222 Constant Hash:41149443
Calculate Nachher b: 00 Constant Hash:44419000
Calculate Hash in Calculate b: -842352706 Constant Hash:44419000
Calculate Vorher c: 00 Constant Hash:44419000
Assign Vorher c: 333 Constant Hash:41149443
Assign sId Hash: -842352707 Constant Hash:41149443
Assign Nachher c: 333 Constant Hash:41149443
Calculate Nachher c: 00 Constant Hash:44419000
Calculate Hash in Calculate c: -842352707 Constant Hash:44419000
Calculate Vorher d: 00 Constant Hash:44419000
Assign Vorher d: 444 Constant Hash:41149443
Assign sId Hash: -842352708 Constant Hash:41149443
Assign Nachher d: 444 Constant Hash:41149443
Calculate Nachher d: 00 Constant Hash:44419000
Calculate Hash in Calculate d: -842352708 Constant Hash:44419000
Calculate Vorher e: 00 Constant Hash:44419000
Assign Vorher e: 555 Constant Hash:41149443
Assign sId Hash: -842352709 Constant Hash:41149443
Assign Nachher e: 555 Constant Hash:41149443
Calculate Nachher e: 00 Constant Hash:44419000
Calculate Hash in Calculate e: -842352709 Constant Hash:44419000
Calculate Vorher f: 00 Constant Hash:44419000
Assign Vorher f: 666 Constant Hash:41149443
Assign sId Hash: -842352710 Constant Hash:41149443
Assign Nachher f: 666 Constant Hash:41149443
Calculate Nachher f: 00 Constant Hash:44419000
Calculate Hash in Calculate f: -842352710 Constant Hash:44419000
Calculate Vorher g: 00 Constant Hash:44419000
Assign Vorher g: 777 Constant Hash:41149443
Assign sId Hash: -842352711 Constant Hash:41149443
Assign Nachher g: 777 Constant Hash:41149443
Calculate Nachher g: 00 Constant Hash:44419000
Calculate Hash in Calculate g: -842352711 Constant Hash:44419000
Calculate Vorher h: 00 Constant Hash:44419000
Assign Vorher h: 888 Constant Hash:41149443
Assign sId Hash: -842352696 Constant Hash:41149443
Assign Nachher h: 888 Constant Hash:41149443
Calculate Nachher h: 00 Constant Hash:44419000
Calculate Hash in Calculate h: -842352696 Constant Hash:44419000
Calculate Vorher i: 00 Constant Hash:44419000
Assign Vorher i: 999 Constant Hash:41149443
Assign sId Hash: -842352697 Constant Hash:41149443
Assign Nachher i: 999 Constant Hash:41149443
Calculate Nachher i: 00 Constant Hash:44419000
Calculate Hash in Calculate i: -842352697 Constant Hash:44419000
T: 1
F: 0
true: 1
false: 0
a: 0
b: 0
c: 0
d: 0
e: 0
f: 0
g: 0
h: 0
i: 0
Der Thread 0x16cc hat mit Code 0 (0x0) geendet.
Der Thread 0xd0 hat mit Code 0 (0x0) geendet.
Das Programm "[5004] MathParserTest.vshost.exe: Verwaltet" wurde mit Code 0 (0x0) beendet.

Ich habe zwei equivalente Ausgaben rot Markiert, wie man beim zweiten im Assign Teil sieht, sind die Werte aus dem ersten Teil schon vorbelegt, haben aber außerhalb der Methode andere Werte. Im Debugger kann ich dies jedoch nicht nachvollziehen. Auch der HashValue von Constants ist in diesem Bereich der des Wertes vom ersten durchlauf.

Leert man das Constants Dictionary im Destruktor, erhält man beim Assign immer KeyNotFound.

Erstellt vor 15 Jahren

So, leider komme ich erste Heute dazu das hier weiter zu verfolgen.

Soweit ich das verstanden habe, dient bs.ResumeBinding() nach einem bs.EndEdit() dazu, auch danach noch weitere Änderungen zu akzeptieren, also die Bindung aufrecht zu erhalten.

Hintergrund des ganzen:
Das Formular (sfcTypeLine) hat verschiedene Eingabefelder die an veschiedene Eigenschaften einer gemeinsamen Datenquelle (Objekt) gebunden sind. Nach erfolgreicher Gültigkeitsprüfung lösen die Validated-Ereignisse der einzelnen Eingabefelder das Validated-Ereignis des Formulars aus in dem die Datenquelle über EndEdit() aktualisiert wird. Das ResumeBinding() dient dazu auch weitere Änderungen zu akzeptieren.

Ich kann in meinem Verständins der Funktionalität aber auch falsch liegen. Das Formular war meiner erster Versuch eienr etwas komplexeren Datenbindung.

Anfangs hatte ich auch noch den ToolTip im Validated Ereignis aktualisieren wollen, dadurch kam es zu den beschriebenen Fehlern beim anzeigen des ToolTips. Also zur Konkretisierung meiner ersten Beschreibung:
Der ToolTip wurde im Validated-Ereignis geändert, der Absturz kam aber erst beim Anzeigen des Tooltips (den gelben Rahmen hat es noch gezeichnet). Der Ereignishandler PopUp war in dieser ersten Version nichteinmal implementiert.

Erstellt vor 15 Jahren

MST ist meine Wenigkeit.
Leider ist es schon etwas her (Anfang November), dass das Thema aktuell war. Ich komme nur leider erst jetzt dazu, es auf zu arbeiten.

Und das da zusätzliche Validierungen ausgelöst werden, war auch meine Vermutung. Daher ja der Stack overflow. Allerdings gehe ich eher davon aus, dass die Validierung durch das SetToolTip ausgelöst wird, als durch das DataBinding. Schließlich ist das DataBinding beim funktionierenden Code noch an der selben Stelle.

Gerade, beim Stichpunkt Exception verschluckt, kommt mir aber noch ein Gedanke: wenn sich das Ereignis immer wieder selbst auslöst und es so zum einem StackOverflow kommt, an welcher Stelle muss dann die Exception dann abgefangen werden? An der Stelle, an der der Oberflächenthread erzeugt wird? Der Handler um das Application.Run(new MainForm()) sieht jedenfalls nichts.

Und in wie weit kann das Verhalten in diesem Punkt systemspezifisch sein? Auf diesem Rechner hier, tritt der Absturz weder im Debugger, noch im fertigen, unabhängig laufenden, Release auf. Auf anderen Rechnern habe ich es damals aber nicht im Debugger laufen lassen.

Erstellt vor 15 Jahren

Hallo

ich habe mal wieder eine Frage aus der Kategorie "warum".

Ich habe in einer Windows.Form eine Textbox, deren Inhalt beim Mouseover auch als ToolTip angezeigt werden soll.

Der erste Versuch sah so aus:


    public partial class sfcTypeLine : UserControl, IDisposable
    {
        private void sfcTypeLine_Validated(object sender, EventArgs e)
        {
            try
            {
                this.secureFileCopyTypeBindingSource.EndEdit();
                this.secureFileCopyTypeBindingSource.ResumeBinding();
                sfcTypeLineToolTip.SetToolTip(textBoxSearchPath, textBoxSearchPath.Text);
                sfcTypeLineToolTip.SetToolTip(textBoxTargetPath, textBoxTargetPath.Text);

            }
            catch (Exception ex)
            {
                Logging.LogException("", ex);
            }
        }
     }


Soweit so schön, es hat wunderbar funktioniert - dachte ich. Auf einigen anderen Rechnern jedoch, führte das Anzeigen des Tooltips zum sofortigen beenden des Programms. Auch der Eintrag in die Logdatei wurde nicht mehr geschrieben.
An meinem Entwicklungsrechner konnte ich das Verhalten beim besten Willen nicht nachvollziehen oder reproduzieren.

Danach habe ich ein wenig in den weiten des Netzes gestöbert und schließlich den Code derart geändert.


    public partial class sfcTypeLine : UserControl, IDisposable
    {
        private void sfcTypeLine_Validated(object sender, EventArgs e)
        {
            try
            {
                // MST 26.01.2010 Das ändern des ToolTips im Validated Ereignis 
                // führt auf manchen Systemen zu exceptionlosen Programmabstürzen.
                // Mögliche Ursache: Stack Overflow durch sich wiederholende Validated-Ereignisse?

                this.secureFileCopyTypeBindingSource.EndEdit();
                this.secureFileCopyTypeBindingSource.ResumeBinding();
            }
            catch (Exception ex)
            {
                Logging.LogException("", ex);
            }
        }

        private void sfcTypeLineToolTip_Popup(object sender, PopupEventArgs e)
        {
            try
            {
                ToolTip tt = (ToolTip)sender;
                tt.Popup -= new PopupEventHandler(sfcTypeLineToolTip_Popup);
                sfcTypeLineToolTip.SetToolTip(e.AssociatedControl, e.AssociatedControl.Text);
                tt.Popup += new PopupEventHandler(sfcTypeLineToolTip_Popup);
            }
            catch (Exception ex)
            {
                Logging.LogException("", ex);
            }
     }


Nun funktioniert es wunderbar. Kann mir jemand erklären, warumd das eine funktioniert, das andere nicht?

Erstellt vor 15 Jahren

Hallo Th69,

erstmal - ein wunderbares Tool hast du da erstellt. Auch die Erklärungen dazu sind schön verständlich und wecken wohlige Erinnerungen ans Studium. 👍