Laden...

Forenbeiträge von Gremgiz Ingesamt 106 Beiträge

19.04.2010 - 05:44 Uhr

Dann werde ich das wohl auch so machen müssen. Ich hatte gedacht, das geht etwas schneller (einfacher). Ich will damit nicht sagen, dass es kompliziert ist, ich hatte nur gehofft, dass ich ein event übersehen hätte...

Gruß
gremgiz

15.04.2010 - 06:06 Uhr

Warum es sich nicht ändrt, habe ich gefunden. Das geht nun. Jedoch bin ich der Meinung, dass dies Overkill ist ist, zumal dort auch händisch Text eingetragen wird. Im Ereignis für TextChanged werden auch andere Dinge gemacht. Die flimmert damit schon leicht. Wenn nun bei jedem eingegebenen Buchstaben die Zuweisung des Fonts auch noch gemacht wird, flimmert es mehr. Weiterhin verliere ich die bereits erstellten Formatierungen (z.B. Textfarbe). Wenn ich das auch noch im TextChanged Event abfange, kann man nicht mehr flüssig arbeiten. Es gibt doch eigentlich für alle Satndardsachen Events - nur für Copy&Paste nicht - das kann ich nicht glauben

Gruß
gremgiz

14.04.2010 - 11:59 Uhr

Hallo,

ich habe in einer Form diverse RTF Boxen, die teilweise via Copy&Paste befüllt werden. Dabei ist zu beaobachten, dass logischwerweise auch der Font des Originaltextes verwendet wird. Wie kann ich es erreichen, dass nach dem Einfügen der Text im richtigen - von mir definierten - Font dargestellt wird? Event TextChange hilft nicht - greift wahrscheinlich zu spät. Einen Eventhandler für Paste habe ich nur in WPF gefunden, was aber nicht verwendet wird.

Kennt jemand einen Trick?

Danke
gremgiz

09.04.2010 - 10:48 Uhr

Hallo kleineseichhörnchen,

wenn das mal so einfach wäre. Ich habe schon viele graue Haare darüber bekommen. Interop ist prinzipiell möglich, aber nur für das direkte Senden. Wenn die E-Mail noch im Client bearbeitet werden soll, müssen einige Properties gesetzt werden. Das geht nicht über C# (die sind schreibgeschützt) wohl aber über VB. Ich vermute das hier der Mischmasch aus COM/OLE in C# hier massiv reinfunkt. Reines COm ist leider nicht möglich und reines OLE auch nicht. Irgendwas geht da nicht. Auf Wunsch kann ich dir einige Threads nennen, die sich damit beschäftigen und auch Beispielcode

09.04.2010 - 06:15 Uhr

Hallo,

ich glaube, ich habe den Fehler gefunden. Es sind weder die User Objekte, noch die GDI Objekte die überlaufen. Ich schrieb ja bereits, dass der Crash auch passiert, wenn die Objekte deutlich unterhalb der Schwelle von 10000 liegen. Vielmehr war es eine DLL, die zu langsam zu sein scheint. Wird eine Anfrage abgeschlossen, werden 2 E-Mails generiert und an Lotus Notes gesendet. Hierbei scheint er sich zu verschlucken. Der erste Test ohne E-Mail-Generierung verlief positiv. Dann habe ich nach jeder E-Mail eine Pause von 2s eingefügt und es lief immer noch. Damit würde ich sagen, ist dieses Problem gelöst.

Ich habe mir den ganzen Fehlercode noch mal angesehen. Der Crash passiert an Adresse 0x2. Das ist ein geschützter Speicher und Windows scheint hat eigentlich richtig gehandelt, da an dieser Stelle kein Fenster gespeichert werden darf, kam die Meldung 😦.

BTW: Die DLL ist in VB geschrieben, da es C# scheinbar unmöglich ist, sauber mit Lotus Notes zu kommunizieren. Kenn jemand von Euch einen Weg, wie das geht. Es geht dabei nicht um das reine Senden – das ist kein Problem. Vielmehr soll die E-Mail in Lotus Notes angezeigt werden, dort ggf. weiterbearbeitet werden und dann gesendet werden.

Danke für Eure Hilfe
Gruß
gremgiz

08.04.2010 - 16:56 Uhr

Der Witz an dieser Access Vioations ist, dass diese laut MS nur in unmanaged Code auftreten kann, der gar nicht verwendet wird...

08.04.2010 - 16:55 Uhr

Nun gut…
Dazu ein wenig Hintergrund. Es handelt sich um eine Applikation für Kundenanfragen. Beim Öffnen der Applikation wird ein erster Tab erzeugt, der die Anzahl aller fälligen Aktionen anzeigt. Ein Klick auf eine dieser Zahlen (Button) öffnet eine Tabelle in einem neuen Tab mit einer groben Übersicht aller Anfragen, die es zu bearbeiten gilt. Ein Doppelklick auf eine Zeile öffnet die Anfrage wiederum in einem neuen Tab. Hier kann nun damit so einiges gemacht werden.

Wie kann ich den Fehler erzwingen: Öffnen einer Anfrage, ändern von Werten und abspeichern. Danach wird die nächste Anfrage geöffnet usw. Die einzelnen Anfragen werden nach dem Speichern nicht zwangsläufig geschlossen, sondern können offen bleiben.

Es ist auch schon vorgekommen (gerade eben), dass nur eine Anfrage geöffnet war und gespeichert wurde. Dabei blieb es dann hängen. Es waren zu diesem Zeitpunkt 200 GDI Objekte und 300 User Objekte geöffnet (3 Tabs). Der Absturz kommt aber nicht zwangsläufig beim Speichern, sondern manchmal auch wenn ich eine neue Anfrage öffne oder eine geöffnete bearbeite.

Folgende Fragen stellen sich:
Wie kann ich es am elegantesten erreichen, den Inhalt eines Tabs zu entladen, wenn dieser nicht in der aktive ist, ohne den Tab selber komplett zu zerstören und wie bekomme ich die Daten wieder rein? Das Ganze soll nach Möglichkeit nicht unendlich lange dauern.

Beim Laden eines Tabs für eine Anfrage passiert folgendes:

  • es wird eine Instanz der Benutzeroberfläche für den Tab erzeugt
  • es wird eine Instanz der Steuerdatei erzeugt, die den Tab managed (Trennung von Code und Design)
    Das bedeutet, dass ich jedes Mal eine Instanz erzeuge. Vielleicht liegt ja auch hier der Hase im Pfeffer. Das dürfte alles andere als sauber objektorientiert sein. Vielmehr sollte es doch so sein, dass eine Instanz erzeugt wird und diese dann im Leerzustand (sprich ohne Daten) vererbt wird, oder? Wenn diese dann geerbt wurde, können (sofern vorhanden) Daten hinzugefügt werden. Daher ne dumme Frage: Ist der Ansatz der Gedanken richtig und wenn ja, wie macht man das am Besten?
08.04.2010 - 15:05 Uhr

Hallo,

für alle die es interessiert, wie man den GDI Stack erhöht: To change this limit, set the following registry value

Ich teile aber die Meinung, dass dies den crash nur hinauszögert. Einige weitere Untersuchungen mit dem taskmanager haben ergeben, dass ich die GDI Objekte wieder freigebe, so wie ich es auch eigentlich gedacht hatte. Wird eine Form geladen erhöhen sich die GDI Objekte entsprechend ud wenn die Form wieder geschlossen wird, verringern sie sich wieder. Was ich erstaunlich finde, ist, dass er den Speicher nicht freigibt, oder nur partiell.

Wie ich den Fehler erzwingen kann, kann ich euch zwar mitteilen, das wird Euch aber nichts nutzen, da dies Applikationsabhängig sein dürfte

gruß

08.04.2010 - 13:48 Uhr

ps: es gibt noch einen trick oder besser gesagt einen hack, wie man den gdi stack erhöhen kann. auf codeproject findest du eine anleitung.

Hast du zufällig die URL parat?

08.04.2010 - 13:31 Uhr

@kleines_eichhoernchen: Nein, reine Single Thread Anwendung und SDI. Die einzige Stelle, an der ich mal einen Inoke verwende ist ein Fortschrittsbalken

08.04.2010 - 13:22 Uhr

Hallo,

@dN!3L: Wann immer es geht, gebe ich die Objekte wieder frei. Um bei Deinem Beispiel des Fonts zu bleiben: In der gesamten Anwendung gibt es nur einen Font, der direkt in den Steuerelementen festgelegt ist. Für Ausnahmen, wo ich ihn mal aufrufen muss, ist er nur einmal im Code verankert und referenziert dann auf die neuen Objekte

Die GDI Objekte kommen alle aus dem Designer. Selbstgezeichnet wird nix. Wann und wie oft, hängt vom Anwender ab. Der entscheidet wann er welchen View benötigt. Die Views selbst können umfangreich sein. Ich glaube der Spitzenreiter liegt bei 80 Controls – und nein, diese Flut kann nicht eingedämmt werden

08.04.2010 - 13:17 Uhr

Hallo

Alternativ hätte ich noch folgendendes von Windgb

Fehlermeldung:
(135c.14dc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000a8f ebx=c7f60005 ecx=0000011e edx=00000000 esi=0c814328 edi=c7f60000
eip=7713205b esp=002e950c ebp=002e9540 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206
ntdll!RtlpLowFragHeapFree+0xc5:
7713205b 8930 mov dword ptr [eax],esi ds:0023:00000a8f=????????
0:000> !pe
Exception object: 106ca304
Exception type: System.AccessViolationException
Message: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
InnerException: <none>
StackTrace (generated):
SP IP Function
002EE2C0 6B27EC80 System_Windows_Forms_ni!System.Windows.Forms.UnsafeNativeMethods.DestroyWindow (System.Runtime.InteropServices.HandleRef)+0x10

Gruß

08.04.2010 - 12:54 Uhr

Hallo,

wie versprochen, der Auszug aus WinDbg.

Fehlermeldung:
Exception type: System.OutOfMemoryException
Message: Error creating window handle.
InnerException: System.NullReferenceException, use !PrintException 0b4897d4 to see more
StackTrace (generated):
SP IP Function
002E9EE8 6B2A703B System_Windows_Forms_ni!System.Windows.Forms.NativeWindow.CreateHandle (System.Windows.Forms.CreateParams)+0x28b
002EDFB0 6B2A6CB5 System_Windows_Forms_ni!System.Windows.Forms.Control.CreateHandle()+0x125

0:000> !PrintException 0b4897d4
Exception object: 0b4897d4
Exception type: System.NullReferenceException
Message: Object reference not set to an instance of an object.
InnerException: <none>
StackTrace (generated):
SP IP Function
002EABC8 07828DB9 CSC_Solutions!CSC_Solutions.Program.Application_ThreadException (System.Object, System.Threading.ThreadExceptionEventArgs)+0xb9

Es hat also etwas mit dem Speicher zu tun. Hat jemand dazu Ideen?

Gruß
gremgiz

08.04.2010 - 11:12 Uhr

Hallo zusammen,

@ Jack30lena:mit WinDbg werde ich mal versuchen was rauszubekommen. Das Ergebnis wird dann gepostet.

@talla: Es werden schon einige GDI Objekte erzeugt. Ich würde dann aber erwarten, dass der Absturz an nahezu immer der gleichen Stelle auftritt. Nur manchmal starte ich das Programm, wähle die Funktion und schon ist es weg. Dann Neustart des Programms und es läuft. Es wurde aber keine Prozesse neu erstellt oder beendet. Ich weiß, dass Windows immer selber viel macht, aber so viel ist es auch wieder nicht. Die User Objekte bewegen sich im Rahmen von max. 4000 – also deutlich unterhalb der magischen Grenze von 10000. Die GDI Objekte sind bei ca. 500 im Maximum.

@Th69: Es sind sehr viele Controls vorhanden, die in Tabs angeordnet sind. Es gibt prinzipiell 2 Tab Controls. Ein Haupttab, der das gesamte Objekt beinhaltet und untergeordnete Tabs, die Details beinhalten. Das Laden der Tabs erfolgt dynamisch – sprich erst, wenn diese benötigt werden, werden Sie auch geladen. Das Entladen erfolgt jedoch immer erst mit Schließen des Haupttabs. Dann wird alles aus dem Speicher entfernt. Die Anzahl der Haupttabs habe ich schon begrenzt. Hilft aber nicht viel.

Gruß
gremgiz

08.04.2010 - 10:42 Uhr

Hallo,

Ein Programm hat ein seltsames Verhalten. So lange es im Visual Studio Debugger ausfgeührt wird, kann ich ohne Probleme damit arbeiten. Sobald aber die Anwendung verteilt wird, kommen sehr merkwürdige Abstürze. Diese passieren immer an anderen Stellen, fast niemals an der Gleichen und das sehr sporadisch. Ich habe zwar mittlerweile einen Weg gefunden, um den Fehler zu erzwingen, bekomme aber in den wenigsten Fällen eine Fehlermeldung. Wenn mal eine kommt, besagt die folgendes:

Fehlermeldung:
Fault Module name: ntdll.dll
Version: 6.1.7600.16385
Exception code: c0000005
Exception Offset: 0005205b

Gestern hatte ich noch das Glück, dass ich zumnindes mal einen Ansatz einer Fehlermeldung bekam: > Fehlermeldung:

Ein Fensterhandle konnte nicht erstellt werden sehr hilfreich, wenn man bedenkt, dass die gleiche Methode eine Minute vorher noch genau das getan hat.

Mehr leider nicht. Google hat nichts brauchbares geliefert. Der Fehler tritt unter Vista, XP und W7 auf.

Hat vielleicht irgendwer eine Idee, wo ich anfangen kann zu suchen? Ich habe schon versucht eine globale Routine zu erzeugen, die unbehandelte Exceptions abfängt, aber selbst die greift nicht mehr.

Es wird kein Multithreading verwendet, daher kann es also nicht kommen. Speicher und CPU Auslastung sind auch im Grünen Bereich.

Wenn ich versuche, nach dem Absturz das Programm zu debuggen, bekomme ich wiederum einen Fehler:> Fehlermeldung:

Unhandled Exception at 0x7713205b
Zugriffsverletzung beim Schreiben an Position 0x2

Der Assemblercode an der Stelle lautet: mov dword ptr [eax],esi

Vielen Dank im Voraus
Gremgiz

15.02.2010 - 16:04 Uhr

Hallo zusammen,

Aus einer Anwendung heraus soll für statistische Zwecke eine Excel-Tabelle (Excel 2003) beschrieben werden. Dabei haben einige Felder (Zellen) mehr als 255 Zeichen. Mittlerweile weiß ich, dass es dort wohl eine Begrenzung gibt; soblad die überschritten wird, gibt es eine Exception. Wie kann diese Grenze aufgehoben oder umgangen werden? Die Anzahl der Zeichen variiert, ebenfalls die Anzahl der Zeilen.

Nachtrag:
Ein wenig Spielerei brachte folgendes zu Tage:
Wird Excel über ein object[,] beschrieben kommt dieser Fehler.
Schreibe ich die Daten direkt in die Zelle (per worksheet.Cells[x,y]) kommt der Fehler nicht.

Ich würde aber gerne über object[,] gehen, da dieses performanter ist

Danke und gruß
gremgiz

26.10.2009 - 10:45 Uhr

Hallo,

ich habe über das Problem noch mal ein wenig nachgegrübelt.

Hierzu mal meine Gedanken. Dazu würde ich mich über Kommentare freuen:

  1. Ansatz: Form global bekanntmachen
    Man nehmen eine Klasse die das Globales heißt und die Form halten wird:
public class Globales
{
   public static Form Form1 {get; set;}
}

Dann beim Start des Programms das ganze setzen:

Globales.Form1 = new Form;

Beim Aufruf der Form das ganze wieder rausholen und das halt jedesmal:

Form Form2 = Globales.Form1;

Was ich dabei beobachtet habe ist, dass immer nur ein Tab damit befüllt wird. Alle älteren Tabs werden glöscht oder besser leer angezeigt. Keine Ahnung warum

  1. Ansatz: IClonable
    Der generelle Ansatz ist wie oben, nur dass die Klasse um IClonable erweitert wird und dann immer nur ein Clone erstellt wird. Dabei knallt es allerdings mit einer InvalidCastException - wobei ich hier nicht weiß warum?

Kann mir hier noch mal jemand gute Tipps geben?

Danke
gremgiz

20.10.2009 - 06:38 Uhr

Hallo Herbivore,

das war auch meine Vermutung - ist es aber nicht. Da werde ich wohl weiter suchen müssen. Vorerst habe ich mir mit einer Variable geholfen. Nicht schön aber funktionell.

BTW: Dieses Verhalten habe ich auch schon bei anderen Events beobachtet, die ich erst im Code definiere

Gruß
gremgiz

19.10.2009 - 09:28 Uhr

Hi,

Das ganze läuft jetzt erstmal. Jdoch wird jedes KeyDownEvent nun 2x durchlaufen? Woher kann das denn jetzt kommen?

Gruß
gremgiz

19.10.2009 - 09:06 Uhr

Hi,

ich habs glaube gefunden. Meine Suche innerhalb des Forums war wohl falsch. Für alle die es interssiert:

Gelöst - PreviewKeyDown für alle Steuerelemente!

19.10.2009 - 08:26 Uhr

Hallo Herbivore,

leider leitet das KeyPrevent nicht durch. Mit dem rekursiv habe ich das auch schon probiert - komme aber nicht an die Kontrols, sondern nur an die übergeordneten Container, in die die Controls eingebettet sind?

So richtig fündig geworden inm Forum bin ich nicht.

Was ich probiert habe, um das ganze rekuriv zu bekommen:

foreach (Control Help_Control in UserControl)
{
   Help_Control.KeyDown += new KeyEventHandler(Hotkeys);
}

Das hat mir ertsmal nen Fehler rausgeworfen: Es gibt keine öffentliche GetEnumerator Definition.

Also habe die Controls erst mal eingesammelt mit:

Control.ControlCollection UCControl = UC.Controls;

Wenn ich das ganze jetzt starte, kommt zwar kein Fehler, aber auch kein Event. Die Schleife durchläuft genau zwei Controls, nämlich die Container, die die eigentlichen Controls beinhalten.

Habe ich eine falschen Denkansatz oder mache ich grundsätzlich was falsch?

Man könnte jetzt natürlich ganz pragmatisch alle Controls per Hand hinschreiben und auf die gleiche Funktion verweisen lasse, aber das kann es ja wohl niht sein oder?

Gruß
gremgiz

16.10.2009 - 21:13 Uhr

Nanu, keiner hat eine Idee? Nach den Zugriffszahlen zu urteilen, bin ich aber nicht allin mit dem Problem.

Ich habe ein wenig gespielt. Wie beeits erwähnt kann ich von der Hauptform ohne Probleme auf das 1. Usercontrol zugreifen. Nur auf die eine Ebene tiefer nicht mehr.

Die einzelnen Controls innerhalb des 2. Usercontrols lassen sich ebenfalls per KeyDown Event problemlos ansprechen. Nur das will ich nicht, da nicht flexibel genug. Um dieses Evnt auswerten zu können, muss das COntol den Fokus haben, da es ja an diess gebunden ist. Daher will ich auf das gesamte 2. Usercontrol Hotkeys definien, die auch die Steuerung einzelner Buttons übernehmen.

Was ich auf keinen Fall will sind globale/systemweite Hotkeys. Die Hotkeys sind nur für die App gültig.

Wie kann ich ein /mehrere Hotkeys auf ein Usercontrol erstellen, das wiederum Teil eines Usercontrols ist?

Evtl. über eine Child/Parent Eigenschaft?

Gruß
gremgiz

14.10.2009 - 09:21 Uhr

Hallo zusammen,

Ich habe ien Problem mit Hotkeys. Dies wurde in vielen Threads ja bereits beleuchtet, aber ich komme nicht so recht weiter.

Beschreibung:
Wenn das Programm über eine Form gestartet wird, definiere ich dort die Hotkeys, die für ein in der Form dargestellten UserControl gelten. Dies funktioniert auch. Nun lade ich innerhalb diesees UserControls ein weiteres UserControl. In diesem UserControl gibt es z.B. eine RTF Box. In der Hauptform habe ich für ENTER einen Hotkey definiert. Wenn ich aber nun in der RTF Box Enter drücke, wird als erstes der Hotkey vom übergeordneten UserControl ausgewertet - was natürlich hier unerwünscht ist. Eigentlich ist das logisch, da die Hauptform nur das 1. UserControl aufruft und auch nur dieses kennt. Daher kann ich hier nicht abfangen, von welchem UserControl der Aufruf erfolgt. Wie kann man das umgehen? Idealerweise würde ich ganz gerne im 1. UserControl die Hotkeys für dieses UserControl und alle untergeordenten UserControls definieren. Geht das? Ein UserControl kennt ja nicht KeyPrevent

Danke
gremgiz

12.10.2009 - 11:00 Uhr

Hallo Herbivore,

Vielen Dank für die Tipps. Habe es mal umgesetzt und es funktioniert ganz gut.

Gruß
Gremgiz

09.10.2009 - 13:30 Uhr

Hallo,

@Herbivore: ob meine Lösung jetzt optimal ist, wage ich zu bezweifeln. Das ist so ziemlich meine erste Arbeit mit Threads. Hast du Vorschläge, wie man das optimieren kann? Das ganze an sich geht schneller - oder fühlt sich zumindest so an - was ja auch ein nicht zu unterschätzender Aspekt der Benutzerpsychologie ist. Genau gemessen habe ich die Zeit nicht, jedoch mal mit "mitzählen" ist die Zeit halbiert worden. Nachdem das GUI aufgebaut ist, ist es noch ca. 0,5 -1 s blockiert - bis halt alle Threads fertig sind.

@JunkyXL: Das mache ich auch so. Alle initial benötigten Controls werden geladen - der Rest später. Es bleiben aber immer noch genügend über 😃

Gruß
gremgiz

09.10.2009 - 10:39 Uhr

Hallo zusammen,

erst mal herzlichen Dank für die vielen Tipps und Anregungen. Ich glaube ich habe die Lösung gefunden - zumindest funktioniert es gut.

Die Ladezeiten des GUIs kann ich schlecht beeinflussen, aber ich kann das GUI im Hintergrund laden und dann holen. Grundlage für diese Überlegung und schlußendliche Umsetzung ist Controls von Thread aktualisieren lassen (Invoke-/TreeView-Beispiel). Für dieses sehr gut gelungene Tutorial herzlichen Dank an alle, die daran mitgewirkt haben

Was wird nun im Einzelnen gemacht:
Bevor ich die Schritte im Detail erläutere, die Struktur des Programms: Beim Start des Programms wird der Benutzer verifiziert. Wenn dies erfolgreich verlaufen ist, wird die Hauptmaske geladen, in der das "Problem"-GUI als Tab dargestellt werden soll. Mit Aufruf dieses Haupt-GUIs wird das „Problem“-GUI bereits das erstemal geladen. Dieses "Problem"-GUI kann vom Anwender beliebig oft aufgerufen werden. Dies erfolgt über einen Button.

  1. Delegaten im Haupt-GUI erstellen
public partial class Main_GUI
{
   delegate void Del_LoadGUI();
}
  1. Wenn der Benutzer auf den Button klickt, der das "Problem"-GUI anzeigen soll, neuen Thread erzeugen
private void Button_Click(object sender, EventArgs e)
{
   Thread t = new Thread(new ThreadStart(Thr_ShowGUI));
   t.Start();
}
  1. Das bereits vorgeladene „Problem“-GUI darstellen
protected void Thr_ShowGUI() 
{
   //Den Tab anzeigen, muss separat erfolgen wegen Tread-Sicherheit
    PageView();

    //Im Hintergrund einen neuen Tab erzeugen
    BeginInvoke(new Del_LoadGUI(Thr_LoadGUI));
}
  1. Erzeugen des eigentlichen Tabs mit dem “Problem”-GUI
    Dabei benötigen wir noch ein paar klassenweite Variablen, für das spätere Management (darauf wird hier aber nicht eingegangen). Nachdem der Tab erzeugt wurde, wird dieser unsichtbar gemacht, so dass er noch nicht angezeigt wird.
protected void Thr_LoadGUI() 
{
   //Ableitungen erstellen
    New_GUI Next_GUI = new New_GUI();  //Das GUI an sich
    Page_Ticket = new TabControl.Page(); //Tab für das GUI

    //Tabzähler erhöhen
    TabCount++;

    //Namen des Tabs festlegen für spätere Verwaltung
    Page_GUI.Name = "Tab" + TabCount.ToString();

    //Angezeigten Text des Tabs einstellen
    Page_GUI.Text = "Neuer Tab";

    //Tab befüllen und hinzufügen
    Page_GUI.Controls.Add(Next_GUI);
    Tab_Main.Pages.Add(Page_GUI);

    //Tab unsichtbar machen
    Page_GUI.Visible = false;
}

Definition der klassenweiten Variablen (machen das Leben leichter auch wenn nicht sauber objektorientiert)

public partial class Main_GUI
{
   //Den Teil haben wir schon eingefügt
   delegate void Del_LoadGUI();

   //Klassenvariablen
   TabControl.Page Page_GUI = null;
   Int TabCount = 0;

}
  1. Den Tab sichtbar machen und dabei auf Thread-Sicherheit achten
private void PageView()
{
   if (Page_GUI.InvokeRequired)
   {
      Page_GUI.Invoke(new MethodInvoker(PageView));
      return;
   }
   Page_GUI.Visible = true;
   TabControl.SelectedPage = Page_GUI;
   TabControl.Update();
}

Wichtig hierbei ist das Update(); das dafür sorgt, dass das GUI direkt neu gezeichnet wird und zur Verfügung steht, bevor das neue/nächste GUI geladen wird.

  1. Vorladen des ersten GUIs
    Wie ja bereits anfänglich erwähnt, wird das erste „Problem“-GUI direkt beim Aufrufen der Hauptform geladen. Das passiert über das Load-Event der Form
private void Main_GUI_Load(object sender, EventArgs e)
{
   Invoke(new Del_LoadGUI(Thr_LoadGUI));
}

Interessant hierbei ist der Synchrone Aufruf des Threads im Gegensatz zu dem sonstigen Asynchronen Aufruf. So kann man erreichen, dass die Hauptform auch sofort einsatzfähig ist und nicht erst noch hängt, weil der Thread im Hintergrund noch läuft. Klar braucht auch diese Ausführung Zeit, die man aber mittels eines Splashscreens gut abfangen kann – und es ist nur einmal beim Start des Programms.

Anmerkungen:
Da ich nicht mit den WindowsForms arbeite, sondern mit einem anderen Control Set, bin ich mir nicht sicher, ob ich in den Codebeispielen alles korrekt auf WinForms rückgeschrieben habe. Bei Bedarf kann man dies ja ändern 😃

Gruß
Gremgiz

09.10.2009 - 06:48 Uhr

Aus gewissen Überlegungen heraus, sind Code und GUI komplett getrennt. Das heißt, das eigentliche GUI hat weder Konstruktoren noch Events. Diese werden alle in der zugehörigen Code Klasse definiert. DIe interne Stopuhr von C# gibt mir Zeiten von 1,5 -2,5 Sekunden aus, um die Form per NEW zu erstellen und eine weitere Sekunde, um diese in ein übergeordnetes Control einzubetten.

Ich tippe mal, dass ein Backgroundworker vielleicht die Lösung ist. Damit werde ich mal rumprobieren. Wenn es weitere Hinweise gibt, wäre ich dankbar

Danke
Gremgiz

08.10.2009 - 21:29 Uhr

Der Tipp mit dem Link hilft leider nicht weiter. Meine Form ist ja fertig. Für einzelne Steuerelemente ist das Ok. Bei komplexen Sachen nicht mehr

08.10.2009 - 16:28 Uhr

Hallo Norman-Timo,

vielen Dank für die Antwort. Den Link werde ich mir anschauen. Das mit dem Vorhalten klappt leider nicht, da ich immer neue Instanzen benötige, da der benutzer in diese Form immer Daten eingibt und nicht immer alle Tabs vorher schließt

Gruß
Gremgiz

08.10.2009 - 14:27 Uhr

Hallo,

Ich habe eine ziemlich komplexe Form gebastelt, die an verschiedenen Stellen im programm immer wieder aufgerufen werden muss (tabbed browsing). Wenn ich die jedesmal mit form Form = new form() lade, dauert mir das zu lange. Daher ist meine Idee, das ganze bereits beim Start des Programmes zu laden und in den Speicher zu schreiben, so dass ich dann jeweils eine Kopie davon bekommen kann. Ist das möglich und wenn ja, wie sehen die Lösungsansätze dazu aus?

20.05.2009 - 11:33 Uhr

Hallo,

eine bestimmte Form muss einfach mehrfach anzeigbar sein. Es geht darum, dass dort Daten zu einem Vorgang erfasst werden. leider können die User das nicht immer erst zu Ende machen, sondern holen sich auch die Daten zu einem anderen Fall, der die gleiche Form verwendet. Das sollte schlicht beides angezeigt werden

20.05.2009 - 07:48 Uhr

Hallo zusammen,

ich habe mittlerweile ein paar Umbauten vorgenommen und so die Ladezeiten verkürzen können. Sie liegen momentan in einem akzeptablen Rahmen, sind aber noch nicht optimal.

Ich habe daher die Idee, diese Form (wird am meisten benötigt) bereits im Splashscreen komplett zu laden und in den Cache zu werfen. Dann kann ich die ja aus dem Cache holen bzw. immer eine entsprechende Ableitung erstellen. Daraus ergeben sich für mich aber ein paar Fragen:

  • Macht das überhaupt Sinn? Bringt das überhaupt Zeitvorteile?
  • Wie muss ich mit Cache arbeiten? habe das noch nie gemacht und bin auch nicht so recht fündig geworden

Gruß
gremgiz

15.05.2009 - 07:52 Uhr

Hi,

ohne den Code zu kennen (und die Stelle) wo es knallt, kann ich nur Vermutungen anstellen. Wenn du ein externes Framework verwendest und diese Funktionen in einer DLL liegen, diese DLL aber nicht mit installiert wird, kann es dazu kommen. Ist aber nur ne Vermutung. Versuch doch mal das Verhalten bei dir auf einem frischen Rechner nachzustellen, dann siehst du wo es knallt. Wenn kein Rechner da ist, nimm VirtualBox o-ä.

Gruß
gremgiz

12.05.2009 - 07:13 Uhr

Hallo,

bin leider erst jetzt dazu gekommen weiter zu machen. Habe mal mit dem profiler neue Tests gemacht. Bedingt durch die Konfiguration (lasse alle Variable mittracken) habe ich die zeiten zwar nach oben schießen lassen, konnte dadurch aber besser sehen wo die Zeit liegen bleibt. Es ist in der Tat so, dass InitializeComponent(); der einzelnen Unterformulare die zeit frisst. So haben die Adressdaten eben mal 10s benötigt. Die anderen Unterformulare sind auch nicht viel weniger - und immer im InitializeComponent();. Die liegen alle bei 7-10s. Die Datenbankzugriffe die benötigt werden, um Listwerte in die Kontrols einzutragen liegen dagegen im ms-Bereich - also zu vernachlässigen.

Wenn ich mir nun die InitializeComponent(); Funktion näher ansehe, sind die größten Zeitfresser das Laden der Bildressourcen (Icons im PNG Format mit 16x16 Pixel und 256 Farben. Die Bilder sind als Ressource im Programm eingebunden. Er genehmigt sich dabei mehr als 1s.

Was vielleicht noch interessant ist: Ich verwende das KryptonToolKit. Das braucht natürlich auch noch Zeit (ca 1-2s)

Gruß
Gremgiz

08.05.2009 - 16:31 Uhr

@Jaensen: Die Adressen haben ein eigenes UserControl, was nur 3x aufgerufen wird. Innerhalb des Controls habe ich einen TableLayoutAdapter mit den entsprechenden Textboxen. Eigentlich doch richtig?

08.05.2009 - 16:29 Uhr

Versuch endete in einer noch langsameren Zeit. hatte versucht das COntrol so umzaubauen, dass weniger Platzhalte wie tablelayout etc da sind - ist aber noch langsamer.

08.05.2009 - 16:02 Uhr

Bin gerade am umbauen.

Ignoriert habe ich dich nicht. Zeit liegt bei ca. 0.5 Sekunden

08.05.2009 - 12:23 Uhr

Müssen beide UserControls direkt sichtbar sein?

Ja, das übergeordnete Control enthält die wichtigsten Daten aus den untergeordenten Controls

Vielleicht brauchst du ein CustomControl ?

Wäre durchaus denkbar - Muss ich mich aber erst mit befassen

Weißt du wieviele Instanzen der Formulare brauchst (Wieviele gleichzeitig sichtbar sein können)? ggf. kansnt du eine Instanz vorhalten?

Das Übergordnete Formular kann beliebig oft aufgerufen werden und wird es in der Praxis vermutlich auch, da die lieben Anwender immer hin und herspringen müssen, was in der Natur dieser Anwendung liegt

Was passiert während der initialisierung?

Eigentlich nichts weiter als Standard, oder was meinst du hier genau?

Fügst du die Controls dynamisch hinzu oder legst du sie schon im Designer drauf?

Beides ist möglich. Rumpf ist immer im Designer aber einige Controls kommen erst zur Laufzeit und andere werden geändert.

Kann es sein dass die controls zu spät geladen werden ?

Glaube ich nicht. Ich bin eher traurig darüber, dass ich sie zu früh laden muss, um die Kommunikation hinzubekommen. Werden direkt mit dem hauptformular geladen

Feuern unnötige Events?

Nein zu dem Zeitpunkt sind keine Events am werkeln

08.05.2009 - 11:22 Uhr

Nein, ich lade lediglich die Forms mit den Controls. Einige Felder werden mit Listwerten vorbelegt, die aus der DB kommen, aber das geht fix und SpeedTrace gibt da noch nicht mal ne Zeit für aus

08.05.2009 - 10:59 Uhr

In diesem Beitrag erwähnst du aber, dass man das mit GUIs nicht machen sollte ....

Die Anzahl der Controls lassen sich nicht reduzieren. Es handelt sich um eine ziemlich komplexe DB Anwendung. Allein der Adressbereich muss 3x ausgeführt sein, was schon 19 Controls pro Adressbereich sind

08.05.2009 - 10:54 Uhr

Leider hilft hier ein Splash gar nichts, da dieser ja nur am Anfang angezeigt wird. Diese Funktion kann innerhalb des Programms jedoch beliebig oft aufgerufen werden - was halt jedesmal seine Zeit dauert

gruß

PS: Ach so die Anzahl der Controls. Nicht hauen: ca. 70

08.05.2009 - 10:43 Uhr

Ok - Asche über mein Haupt....

Habe den SpeedTracer genommen (BTW: Das ist ein kommerzielles Produkt mit 10 Tagen Trial. Gibt es ein gutes Freeware Tool?) und mal Zeiten ermittelt. Dabei habe ich mich auf das problematische UserControl beschränkt.

Es gibt im Prinzip 2 längere Aktionen. Das UserControl selber braucht ca 1,5 Sekunden um sich zu initialisieren. Ein Unterformular, das sofort geladen werden muss braucht in etwa die gleiche Zeit. Macht also 3 Skunden für diese beiden Formulare. Der Rest ist fast vernachlässigbar.

Eine genauere Analyse erbrachte, dass das Initialisieren/Zeichnen der Steuerelemete die Zeit frisst. Nur werde ich da nicht rankommen bzw. großartig optimieren können oder?

Gruß
Gremgiz

08.05.2009 - 10:14 Uhr

Hallo,

kannst du das bitte etwas näher eläutern? Ich kenne diese Funktion nicht

Gruß
gremgiz

08.05.2009 - 10:02 Uhr

Hallo zusammen,

Ich habe ein Problem mit den Ladezeiten von Formularen. Aber der Reihe nach. Eine Applikation öffnet ein Fenster und bietet ein Menü an, mittels welchen die Funktionen aufgerufen werden. Diese Funktionen öffnen sich innerhalb eines Tabs als UserControl.

Eines dieser UserControls ist sehr umfangreich und öffnet weitere UserControls in einer separaten TAB Ansicht - da nicht alle benötigten Daten auf den Schirm passen. Da die Tabs untereinander durchaus kommunizieren, müssen die entsprechenden Ableitungen beim Start des übergordneten UserControls bereits erstellt werden. Das Zeichnen der untergeordneten UserControls erfolgt erst beim erstmaligen Aufruf, um zeit zu sparen. Jedoch benötigt das übergeordnete UserControl schon 5-6 Sekunden um sich zu öffnen. Gibt es Tricks dieses zu beschleuinigen?

Ich habe hier schon ein wenig gesucht und meine Idee mit seperaten Threads wieder fallen gelassen, da jeder davon abrät GUIs in seperaten Threads zu laden.

Vielen Dank
gremgiz

04.05.2009 - 13:44 Uhr

Hallo,

danke für den Tipp - funktioniert. Mal wieder den Wald vor lauter Bäumen nicht gesehen

Gruß
Gramgiz

04.05.2009 - 13:15 Uhr

Hallo,

ich habe ein TableLayoutPanel, dass zur Laufzeit erweitert werden kann. Wenn der Anwender nun eine falsche Eingabe macht, oder Daten verworfen werden sollen, möchte ich erreichen, dass die gesamte Zeile gelöscht wird. Wie kann ich das erreichen? Es reicht aus die letzte Zeile zu löschen, aber ich bekomme es nicht hin. Hat jemand einen heißen Tipp?

Ich habe bereits probiert, einfach den RowCount um 1 zu verringern und danach ein Update() - geht aber nicht

Danke
Gremgiz

11.03.2009 - 11:55 Uhr

Hallo,

scheinbar beißen sich da mehrere Leute die Zähne dran aus. Ich möchte mich erst einmal bei allen bedanken, die sich darüber den Kopf zerbrochen haben. Ich für meinen Teil habe es jetzt so gelöst, dass ich in VB eine DLL geschrieben habe, die ich über C# einbinde. Manchmal ist VB doch die bessere Alternative J

Falls noch Ideen bestehen, bitte posten.

Gruß
Gremgiz

09.03.2009 - 13:23 Uhr

Das es nicht der elegante Weg ist, steht außer Frage. Nur bringt mich das nicht weiter

Gruß
gremgiz

06.03.2009 - 07:18 Uhr

Hallo,

ja das habe ich mir angeschaut, geht aber in die falsche Richtung. Der Threat verwendet DominoObjecte (COM), was hier nicht geht. Ich muss über OLE zugreifen udn das geht leider nur auf diesem Wege.

@JayCore: Das hat mich auch ein paar graue Haare gekostet, dass so hinzubekommen. Aber irgendwo im Thread habe ich eine URL gepostet die das Grundgerüst sehr gut erklärt.

Gruß
gremgiz

05.03.2009 - 15:54 Uhr

Hi,

Ich habe ein wenig gespielt und herausgefunden, dass:

Type NotesSessionType = Type.GetTypeFromProgID("Notes.NotesSession");
object NotesSession = Activator.CreateInstance(NotesSessionType);

bool obj = (bool)NotesSessionType.InvokeMember("ConvertMIME", BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance | BindingFlags.GetProperty, null, NotesSession, null);

Wunderbar funktioniert. Nur wenn ich danach aufrufe:

NotesSessionType.InvokeMember("ConvertMIME", BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty, null, NotesSession, new object[] {false});

Knallt es mit „TargetInvocationException“. HRESULT: 0x8000FFFF (E_UNEXPECTED). Kann mir irgendjemand sagen was ich da falsch mache?