Der Aufruf "XMLCreateEvent" kann zum beispiel genau das bewirken, intern in der DLL selbst. So kannst dir z.B. diesen Aufruf spaaren, wenn der Aufruf allerdings noch etwas anderes bezweckt, tjoar dann wie JAck30lena schrieb musst entweder das in der DLL selbst behoben werden, oder du musst dir was einfallen lassen.
Das Problem das es Flockert liegt beim MouseMove Ereigniss, nutze besser ein Click oder MouseDown Ereigniss.
Das Graphics grafic; grafic = this.CreateGraphics() ist gefährlich ohne Dispose zu benutzen mal davon abgesehen das es nicht mal benutzt. Schmeiß es am besten erstmal raus und wenn du jemals Graphics benutzt, schreib einfach nen using drum herum. also:
using(Graphics grafic = this.CreateGraphics() )
{
.... //usw
}
Das toolTip.Hide(this); brauchst du dann auch nicht mehr, da beim toolTip bereits einen Intervall mit angeben kannst 🙂
[Edit] JAck30lena war schneller ,-)
Hrm, würde mal behaupten der Benutzer hat keine Lese-, Ausführenrechte oder evtl. brauchts auch Schreibrechte auf dem entsprechenden Netzwerkpfad.
Hrm, evtl. hilft dir diese Seite weiter 🙂
Denke hast nur etwas vergessen, wie den description Parameter für die Awnendungsbeschreibung oder sowas.
Hrm, das anhand von Win API's über **SetParent ** und **SetWindowPos **oder **MoveWindow ** zu realisieren wäre eine Möglichkeit. Das dumme ist nur, ich habe keinen Plan vom Compact Framework und weis daher nicht wie es da überhaupt mit Windows API aussieht 😮)
Siehe hierzu pinvoke.net, falls die Win API kein Problem darstellt.
Hrm, hatte gehofft das einfahc nur das OSK (Parent) mitbekommt das der Button A (Child) gedrückt wird.. schlussendlich passiert das ja auch. Also gilt es herauszufinden was genau passiert.
Also ne überlegung wäre noch mal das OSK (Parent) zu beobachten wenn Button A gedrückt wird. Du sagtest ja das WM_LBUTTONDOWN ins OSk (Parent) reingeht, also schau dir da mal lParam und wParam an. Mit den Windows Taschenrechenr auf Wissenschaftlich gestellt wandelst den int Wert von wParam und LParam mal in nen HexWert um und suchst dann diesen via Spy++ oder halt deinen Programm. Wenn der Button A = den Hexwert übereinstimmt so weist dass dass Handle davon mitgegeben wird. Wenn das nicht der Fall ist und das Handle nirgendwo auftaucht ist es evtl. der ASCII in Wert. Kann ja sein das die Typen die umschalttaste nicht beobachten wollten und bei gedrückter Umschalttaste die Buttons auf dem OSK statt kleingeschrieben also "a" plötzlich großgeschrieben werden also "A". Dann schicken die einfach den fertigen Buchstaben an das OSK das dann wiederum die Nachrichten an das entsprechende Control mit den Focus schickt.
Wenn das der Fall ist brauchst ja nur wieder WM_LBUTTONDOWN schicken und als lParam oder WParam je nachdem das handle von Button A oder / und nur den integer Wert des Buchstaben (also auf ASCII bezogen).
Sonst gehen mir langsam die Ideen aus 😮)
Hrm, also so ganz verstehe ich es nicht ganz - du stellst ja einfach im Designer Localizable = true und erhällst in deinen *.resx Dateien die auf dem Controls hinterlegten <Control>.Text Eigenschaften.
Da steht dann nur: Name, Value und Comment. Die .resx Dateien werden natürlich beim Ableiten vom der jeweiligen Klasse übernommen welche die Ableitung beinhaltet (ist ja auch gut so). Aber was ich nicht verstehe was du mit zweiter Sprache meinst?
Die .Resx Dateien werden ja in der Regel übersetzt und bei der Installationsroutine dann durch die Ausgwählte Sprache eben je nachdem eingebunden? Evtl. habe ich das auch falsch verstanden...
Also ist ne weile her bei mir, hatte das nur mal in Verbindung mit einen SQL 200 Server um Nachrichten von der SQL Datenbank auf dem Server zu erzeugen, gebraucht. Evtl. habe ich das Projekt sogar noch zu Hause
Private Queue geht nur die Local verbindung, sprich wenn eine private Queue erzeugst auf einem Rechner, kann nur dieser Rechner diese Nachricht verarbeiten. Das macht grade bei einer Datenbank Sinn - früher gabs ja keine TransactionNotification wie sie der SQL Server 2005 anbietet. Daher konnte man anhand des MSMSQ Dienstes Add's Delete's oder Update's auf der Datenbankseite mitbekommen für die jeweiligen Tabellen und schichtete diese Nachrichten wieder auf C# Code um.
Für deine Zwecke reichen public Queues..
Habe vorrhin auch den Fehler nicht gesehen, muss dann natürlich public$ heissen und nicht private$ 🙂
Gibt nen guten MS Artikel dazu:Link.
Hrm, würde mal auf den ersten Blick das Format vermuten:
Denke hällst in der queue nur nen string, daher folgendes Format:
... new XmlMessageFormatter(new Type[] {typeof(string})
und dann eben noch das hier, hinterlegst die NAchricht ja auf dem Server und nicht auf deinen Client - Evtl. habe ich das auch verkehrt herum verstanden?
Formatname:DIRECT=TCP:<ServerIP>\\Private$\\myQueue
Das hier sind die Formate:
FormatName:Public= 5A5F7535-AE9A-41d4-935C-845C2AFF7112
FormatName:DIRECT=SPX: NetworkNumber; HostNumber\QueueName
FormatName:DIRECT=TCP: IPAddress\QueueName
FormatName:DIRECT=OS: MachineName\QueueName
Danke an alle für Eure Hilfe.
Ich habe das Problem jetzt so gelöst, dass ich die Spaltenbreite zur Laufzeit mittels Graphics MeasureString festlege. Die automatische Spaltenbreite gefällt mir insofern nicht, dass bei sehr kurzen Texten die Spalte schmal wird und eine weitere ungewünschte Spalte erscheint.
Beim nächsten Mal fange ich lieber gleich mit DataGridView an.
Gruß, Christel
Meiner Meinung nach wäre das hier sicherlich der komfortabelste Weg 😉
listView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
😜
/ps Hattest schon recht jaensen 🙂
Soo wieder da 😉
Versuchs mal so rum:
PostMessage(new HandleRef(null, osk), WM_LBUTTONDOWN, _letterA, IntPtr.Zero )
Nen einfaches Beispiel:
Du hast ein Form auf das machst du ne TextBox, jetzt willst du die Nachrichten die in der TextBox eingegeben werden aber auf dem Form verarbeiten. Dazu <Form>KeyPreview = true. Stellen das heisst die Nachrichten von der Textbox erscheint nun in der Form in der Methode OnKeyDown. Angenommen du hättest statt einer Textbox viele hunderte. So erscheinen alle Nachrichten von Tastatureingaben in der OnKeyDown Methode des Form's.
Genauso kann man auch andere Nachrichten weiterleiten 😉
Das Form ist das "Parent" der TextBox und die TextBox vom Form das Child. Die Begriffe werden egal ob C# oder C++ oder C immer verwendet. Und egal ob das Ding was du siehst ne TextBox oder ne Form ist unter Windows ist alles ein Window, das heisst eine Form ist in seinem Kern fast das selbe wie eine TextBox beides ist schlussendlich ein Control hat ein Handle einen Rahmen usw...
Was ich damit meine ist nur, das die Nachricht statt das sie auf dem Child also den Button verarbeitet wird, seine Nachricht an das Parent also das Control auf dem sich der Button befindet weiterleitet und dort in wirklichkeit die Nachricht dann schlussendlich verarbeitet wird.
Kleines Beispiel, ich möchte in Notepad Speichern, da habe ich nun viele Möglichkeiten. Ich kann an die Notepad Main Form (Control auf dem sich alles befinder) die Tastatureingabe "Str+S" senden. Ich kann aber auch das Menücontrol suchen mir das Handle dazu rausgreifen und die Nachricht BM_CLICK an das Menücontrol senden usw.
Daher, dein Problem ist erstmal herauszufinden, wo wird die Nachricht verarbeitet. Im normalfall Programmieren die meisten irhe Anwendungen wie folgt. Mein Button XY wird gedrückt, löse ein Event aus und verarbeite die Nachricht. Da hätte Dragons Ansatz schon gereicht und alles wäre gut.
Du wirst also mit dem Spy++ ode rhalt deinen Tool erstmal herausfinden müssen. Kommt die Nachricht WM_LBUTTONUP auf meinen Control "Button A" an. Darauf hast mir bisher keien Antwort gegeben 😉 Ergo, gehe ich davon aus hast es noch nicht versucht.
Wenn keine Nachricht ankommt läuft mit PostMessage schonmal was falsch und wir können uns mal ansehen ob wie oben mal geschrieben evtl. das falsche Handle einfach holst. was ganz schnell mal passieren kann. Oder die Nachricht kommt an und wird halt nicht verarbeitet evtl. ist WM_LBUTTONUP nichtmal die richtige. Vermute sogar das WM_LBUTTONDOWN eher stimmt. Wer nimmt schon ButtonUp als Event? Also wie du siehst, es gibt zu viele Variablen, da musst dich einfach knallhart durchwühlen.
Sprich, schau dir die Nachrichten an, versuch auf gut Glück mal WM_LBUTTONUP oder WM_LBUTTONDOWN an den Button zu senden. Wenn das nicht klappt sende einfach mal WM_LBUTTONUP oder WM_WM_LBUTTONDOWN oder WM_CLICK an das Parent Control von "Button A" und als lParam eben das Handle von "Button A" und schau was passiert. Einfach etwas rumprobieren 🙂
Aber wie gesagt das erste was schaust, gibt dir PostMessage schonmal den boolischen Wert = true zurück 🙂
Hrm, bisher habe ich das nur mal unter C++ verwendet...
[DllImport("kernel32.dll", SetLastError=true)]
static extern bool HeapFree(IntPtr hHeap, uint dwFlags, IntPtr lpMem);
[DllImport("kernel32.dll")]
static extern uint GetProcessHeaps(uint NumberOfHeaps, out IntPtr ProcessHeaps);
Na ja... aber das ist alles zu lange her obs dir wirklich hilft?
Hrm, WM_LBUTTONUP hat auch nichts gebracht?
Ansonsten macht mich das Parentnotify etwas nervös... evtl. wird die Nachricht im Parent also das Control auf dem sich der Button befindet ausgelöst erst verarbeitet.
Und das könnte so ablaufen Hwnd = Parent (das Parent Control von Button A) Msg = WM_LBUTTONUP und lParam halt = Handle von z.b Button A.
Hier hilft nur ausprobieren, wenn deine Nachrichten ankommen ists schonmal gut, dann gildet es nur herauszufinden wo die Nachrichten verarbeitet werden und wo sie schlusssendlich verarbeitet werden.
Hrm, du kannst beim Füllen anhand der ListView Font und mit Graphics MeasureString die größe berechnen und herausfinden ob der Text der grade zur laufzeit eingefügt werden soll größer als die With des Clientbereichs ist. Wenn ja kannst du ja <ListView>.Scrollable = true schalten. Falls nicht dann ist der Wert auf false. Das wäre der einfachste Weg.
Man kann es aber auch noch komplexer machen wenn der Lösungsweg nicht in ordnung wäre 😮)
Hrm, schreib bitte rein was ein µC senden ist .o)
Sprichst du ein externes Gerät an und wenn ja über Seriellen-Port bzw. welche Schnittstelle oder über eine API ?
Hrm, hatte grade geschrieben bevor das Edit kam 😉
Schicke mal die Nachricht WM_LBUTTONUP via PostMessage ab. Das wäre dieses hier:
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true)]
private static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
private readonly uint WM_LBUTTONUP = 0x202;
private void button1_Click(object sender, EventArgs e)
{
PostMessage(new HandleRef(null, this.unhook.Handle), WM_LBUTTONUP, IntPtr.Zero, IntPtr.Zero);
}
Scheint halt so das die statt auf nen Klick eben auf Linke Maustaste loslassen reagieren (Left Mouse Up).
Na ja, wenn das erste was du machst ist erstmal wie gesagt zu schauen ob deine PostMessage reinkommt und schließt damit aus das da der Fehler auftritt.
Einfach dein Programm starten dann das OSK , dannach satrtest den Spy++ oder halt das WinId (kenne das nicht). Dannach suchst du den Button auf den du den Klick simulierst und loggest die Nachrichten mit. Schau erstmal das die Log leer ist dannach drückst du auf deiner Anwendung den Knopf der das PostMessage auslöst. Hoffe hast zwei Monitore so kannst auf dne zweiten die lognachrichten laufen lassen ohne das versehentlich mit der Maus oder durchs switchen mit den Fenstern ne andere Nachricht auslöst. Es sollte wenn alles geklappt hat nun bei dem OSK für dne entsprechenden button nur die Nachricht WM_CLICK oder halt BM_CLICK erscheinen.
Wenn das geschieht weist du das die Nachricht ankam, aber nichts wurde verarbeitet. Das wäre schlecht 😉
Wenn keine der beiden Nachrichten eingeht schau mal ob wirklich das Handle stimmt das du mit FindWindowEx bekommst nicht das auf dem Button irgend nen Label oder Image Control drauf ist an das du versehentlich die Nachricht sendest anstatt deines Buttons den nur dieses verarbeitet die Nachricht.
Wenn die Nachricht eingegangen sein sollte und diese nichts bewirkt ists doof. Den dann musst du die richtige Nachricht finden.
Dazu wieder das log anschmeißen, draufklicken und log beenden. Nachrichten wie PAINT NCPAINT GetText oder irgendwelche Erases kannst knicken, wichtig sind komische Nachrichten die z.B. nicht mit WM_ anfangen. Kann ja sein das auf nen validate reagiert wird oder irgend ne komische Focus Geschichte, da wirst dich durchwühlen müssen.
Hrm, PostMessage ist schon ein bissel was anderes als SendMessage 🙂
Siehe dazu folgenden Artikel.
Trotzdem, sollte eigentlich gehen.. hast mit dem Spy ++ mal geschaut ob deine Nachricht reinkommt? Nachher reagiert das Ding nichtmal auf nen Klick (Keine Ahnung warum es nicht sollte).
Sollten folgende Nachrichten auftauchen und sonst nichts:
BM_CLICK
Wenn nichts auftaucht schauen wir weiter und wenn eine Auftaucht machst es ganz einfach. Lass wieder dne Spy ++ laufen logge wieder mit und rücke mal auf einen der Buchstaben und schau dir die Nachrichten an die Auffällig sind.
Hallo Andreas.May,
OSK == On Screen Keyboard, das von Windows 😉.
Leider passiert auch deinem Vorschlag nichts 😦.
Ich hab es mit dem Handle der "gesamten" Bildschirmtastatur versucht, sowie mit dem handle vom buchstaben "A".
Sorry , hab total gepennt .. ging ums Tasten "drücken" simulieren... war irgendwie bei Tastatureingaben... 😉
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true)]
private static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
private readonly uint WM_CLICK = 0x00F5;
private void button1_Click(object sender, EventArgs e)
{
PostMessage(new HandleRef(null, <OSKHandle des entsprechenden Buttons>), WM_CLICK, IntPtr.Zero, IntPtr.Zero);
}
Der einfachste Weg wäre in der SQL Anweisung im SELECT Statement anhand von T-SQL, die entsprechenden Leerzeichen zu entfernen.
Siehe hierzu RTRIM (Zeichenfolge) und LTRIM (Zeichenfolge).
Hierzu auch nen guter Link für T-SQL.
Hall Kalleberlin,
mit folgenden sollte es gehen:
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true)]
private static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
private readonly uint WM_KEYDOWN = 0x100;
private void button1_Click(object sender, EventArgs e)
{
PostMessage(new HandleRef(null, this.Handle), WM_KEYDOWN, new IntPtr((int) Keys.F1), IntPtr.Zero);
}
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.KeyData == Keys.F1)
{
MessageBox.Show(string.Format("Taste: {0} wurde erfolgreich gedrückt", ((Keys)e.KeyData).ToString()));
}
base.OnKeyDown(e);
}
this.Handle war nur zum ausprobieren, das ist natürlich das Handle vom OSK, was auch immer OSK bedeutet 😉
Hrm, habe nun etwas rumporbiert aber den Fehler nicht wirklich reproduzierne können, ausser wenn man mehrfach den hook auf einer Instanz startet und aufruft, dann kommt es natürlich zu fehlern. Aber ein einmaliger Aufruf auf einer Instanz mit anschließenden unhook und wieder den hook starten verursachte keine Probleme bei mir...
Evtl. fällt mir später noch etwas dazu ein, derzeit komme ich irgendwie nicht drauf was das sein könnte.
Hrm, wie immer gibt es viele Lösungen dafür 😉
Leider kommt eine Lösung wirklich stark auf jede kleine einzeleit an die du haben möchtest. Du kannst eine intelligente ProgressbarMessage Box gestalten die sich auf einen ApplicationThread setzt und dessen Lebenszyklus bei hoher Prozessauslagerung einfach einklinkt erstellen. Und diese ausnahmsweise als eigenen GUI Thread laufen lassen, hierzu brauchst du aber Kentnisse in bereich der Windows API's.
Du kannst eine ganz normale Form nehmen, diese via ShowDialog aufrufen und dieser einfach nen int Value übergeben um die Progressbar zu füllen. Und damit "absichtlich" die Hauptanwendung blockiert diese innerhalb des verarbeitenden Threads aufrufen.
Du kannst einen eigenen GUI Thread gestallten inenrhalb deines Dialogs dessen wiederum Daten übergeben die der Dialog dann selbst abarbeitet ohne irgend einen einfluss auf deinen Main GUI Thread zu nehmen.
Also ist eher die Frage was du willst. Das leichteste wäre der zweite Lösungsansatz.
public void StarteVerarbeitung()
{
System.Threading.Thread th = new System.Threading.Thread(new System.Threading.ThreadStart(MyThread);
th.SetApartmentState(System.Threading.ApartmentState.STA);
th.Start();
}
private void MyThread(EventArgs e)
{
using (myPrgressbarDialog frm = new myPrgressbarDialog().ShowDialog())
{
for(int i = 0, i < 1000; i++)
{
frm.Value = i;
}
}
}
[Edit]
Die erste und der dritte Lösunsgansatz sind keine herkömmlichen Progressbars sondern ähnlich wie bei Winamp nur Popups die eine verarbeitung signalisieren ohne die Hauptanwendung zu kennen oder sie zu beeinflussen. Diese sind nur zur visualisierung gedacht, daher "seperate" GUI Threads - ansonsten finder davon lassen.
Hrm, normal sollte es gehen...
1.) Arbeitest den etwas für Windows CE aus?
2.) Stößst du irgendwo den GC.Collect manuell an?
3.) Schließt du die instanz von deiner MouseHook Klasse oder nutzt halt die Methode <MouseHook>UnHook() ? Den nur auf den Garbage Collector zu warten bringt nichts, das würde Fehelr verursachen, daher enwteder beim schließen der Instanz den GC.Collect manuell anstoßen oder <MouseHook>UnHook() aufrufen.
4.) Du startet dein testprogramm und der Fehler kommt direkt ?
Probiere es grade irgendwie nachzuvollziehen 🙂
Also, leider gibt es dafür viele Lösungen 😉
Lösungsansatz:
Du könntest einen Dienst schreiben der via WMI ausließt wenn ein USB Stick reingepöpselt wurde, dann durchsuchst du den USB Stick nach einer Datei die den Namen deiner .exe trägt und der Dienst beendet dann sollte dein aktuelles Programm gestartet sein, dieses. Im Anschluss ersetzt dein Dienst die gefundene .exe Datei von deinen USB Stick mit der von der aktuellen auf dem Rechner.
Lösungsansatz:
Du kannst das auch ohen Dienst machen indem deine .Exe einfach auf das WMI Ereigniss wartet und nen externes Programm update.exe einfach startet und dieses dann die Aufgabe des durchsuchens und beenden deines Programms übernimmt und die Dateien ersetzt.
3 Lösungsansatz:
Ideal wäre es natürlich wenn dir unter Codeproject mal ModuleLoader / Plugins ansiehst und deine Anwendung via Pluginverfahren implementierst. Das ganze hat den Sinn das nur eine absolut dumme .exe Anwendung hast die nur eine Klasse und ein Interface besitzt, die Klasse ist dein ModuleLoader. Diese Klasse ladet nur Assemblys wie Plugins herein die über eine gemeinsamme Schnittstelle reingeladen werden, daher die Schnittstelle. Die Schnittstelle bietet ein Versionsmanagment. Soo die einzige große Funktion die sich dann eben in der ModuleLoader Klasse befindet ist daher das WMI Event für den USB Stick wie der Suche und der überprüfung der Versionen. Sollte das WMI Event anspringen untersuchst du den Stick nach einer DLL welche die gemeinsamme Shcnittstelle implementiert. Wenn eine gefunden wurde schaust du nach der Version wenn diese höher als die aktuelle ist. Entladest du das aktuelle Hauptmodul und kopierst das neue Modul in deinen Anwendungsordner und ladest sie von dort wieder rein. Das ganze ist wirklich schnell sogar nachträglich implementiert also maximal 1 Tag und wäre sauberer zumal nen Versionsmanagment sicherer ist als nur Dateien zu verschieben, ohne nach den Sinn dahinter zu überprüfen. Davon abgesehen, du kannst das verfahren auch nutzen um dein Programm zu erweitern und andere Möglichkeiten implementieren zur aktualisierung wie z.B. übers Internet usw. Natürlich kann man damit auch viel mehr anfangen und DesignPatterns einbauen, denke aber bei eine kleineren Anwendung ist das nicht unbedingt nötig.
Sorry hab lange nicht mehr hier reingeschaut 🙁
Also, herbivore hat die richtige Spur angegeben dennoch fürchte ich ist der Fehler nicht leicht zu finden, daher schreibe ich mal die Lösung rein 🙂
Hatte ja einen destructor angegeben
~CMouseHook()
{
this.UnHook();
}
Leider fehlt in der UnHook() Methode das auch der pointer auf das zwischenliegende Modul wieder freigegeben wird sobald die instanz der Klasse geschlossen wird.
Also folgendes bereinigt das ganze, hab den Quellcode oben bei mir auch daraufhin angepasst. (siehe daher m_hInstance und DLLImport FreeLibrary).
[DllImport("kernel32.dll", SetLastError=true)]
private static extern bool FreeLibrary(IntPtr hModule);
public void UnHook()
{
FreeLibrary(m_hInstance);
UnhookWindowsHookEx(m_hHook);
}
Ansonsten hast sind noch zwei kleinere Fehler drinnen. Bei deiner Methode HookProc fehlt die Abfrage auf Code ≥ 0. Denn sonst gibts beim CallNextHookEx Fehler, grade wenn der GC drüberläuft den dann sollen keine Nachrichten mehr verarbeitet werden. Das passiert daher weil das Ding nicht synchron "aufgeräumt" wird. Dann denk dran das Events immer darauf prüfen solltest ob diese überhaupt gebunden sind, also einfach ein if (this.MouseMove != null) bevor das Event invokst.
Nach dem ganzen lief dein Quellcode bei mir ohne Probleme durch, falls es weiterhin Probleme geben sollte, gib einfach bescheid.
Soo nen kleines Feedback die Skinlib ist kurz vor der Fertigstellung.
Das ganze funktioniert wie folgt, man zieht eine Komponente Namens SkinExtender auf den Designer und jedes Control auf der Form bekommt im PorpertyGrid nun die Einträge Skin. Dort gibt es dann die folgenden Möglichkeiten:
UseWindowsTheme:
ja / nein - bei ja wird windows themes benutzt sofern UseDefault auf ja ist.
UseDefault:
ja nein - bei nein wird der Skin reingeladen.
Skin:
Ladet vordefinierten Skin via eindeutigen Namen. Hier bin ich grade bnoch dran das ganze auf ne assembly loader umzustellen für nen späteres skinning tool mit den man dann die einzelnen Controls bearbeiten kann. Damit verbunden wird noch ein globales skinning. So das man eine form welche das SkinComponent besitzt auf alle das selbe Skin vererbt defaultmäßig. Damit braucht man nicht jedes control einzelnd anklicken und den "Skinnamen" wählen bzw. eingeben.
BorderAppearance:
Wenn UseDefault auf nein gestellt wird, so kann man hier der Skinn manuell verändert werden via normalen images. Ebenso kann man hier einfluss auf das DragAndDrop Ereigniss nehmen (ja man kann damit Buttons auf ner Form herumschieben). Die Mauscursor für das Strechen (also auch nen Button z.b. größer zerren) an den jeweiligen Kanten.
CaptionButton:
Wird noch bearbeitet momentan kann man damit sogar Buttons auf nen Button malen 😉 Überlege mir da noch eine Logik die das defaultmäßig erstmal nur bei ner Form veranlässt aber durch umschalten eines kleines schalterchens auch für andere Controls verfügbar macht.
Ansonsten, hoffe werde damit kommendes Wochenende fertig und kann schon etwas reinstellen. Dannach geht es an die Widgets und den DockingControler. Das SkinningTool für das erstellen der Assemblys folgt später, da dieses am meisten zeit beanspruchen wird.
Hallo heikowin
kannst du deine "HookProc" Methode reinposten evtl. ists nur was kleines?
Der Code geht ansonsten eigentlich, hab nur nen modifer geändert nachträglich und versehentlich das Ding public statt private gemacht, habe das mal geändert sollte nun via Copy and Paste gehen .-)
Na ja, eigentlich baut trotzdem im Hintergrund vieles auf der Win API auf, Egal ob C++, Java oder C# sobalds Plattformabhingigkeiten gibt ist schluss mit der unbegrenzten Freiheit.
Na ja, du kannst beim Click auf den Button diesen immer auf disable Stellen. Da der Focus von der ListView dann soweiso dann flöten geht.
Sprich OnClick -> disable button -> öffne dialog.
Jup 😉
Leider ist das ganze noch komplizierter und das Flackern wirst wahrscheinlich nicht komplett wegbekommen. Kannst mal versuchen und alle auf DoubleBuffer = true stellen und schauen ob es geht oder nicht.
Denn ControlStyles.AllPaintingInWmPaint ist ne gute Idee aber das gilt nur für die WindowsNachricht WM_PAINT nicht für das wofür DoubleBuffer eigentlich wirklich (meistens) gut ist. Die NonClientArea, also WM_NCCALCSIZE (hier passiert der Fehler) und die damit verbundende Nachricht WM_NCPAINT, diese wird nicht korrekt dargestellt und nicht gezeichnete Bereiche werden als schwarz gerendert - daher BitBlit um diese bereiche als ScreenCopy zu füllen.
Aber wie gesagt versuch einfach mal das mit DoubleBuffer bei allen Controls.
Achso, schau mal ob beim ListView die Eigenschaft HideSelection auf true gestellt hast und setz es wieder auf den Default false.
Und wie du richtig vermutest beinhaltet die Liste Controls sowohl deine Auto's und Lkw's labels. Wenn du diese mit einer Foreach Schleife durchläufst castest du diese nur auf die Kalsse Autos und das schmeißt dir bei einen Control vom Typ LKW natürlich eine Fehlermeldung.
Es gibt verschiedene Ansätze das ganze zu lösen: Gebe dir nur einen.
foreach(Control _ctr in MainProgram.mainForm.splitContainer3.Panel1.Controls)
{
Versuch.Formen.Auto auto = _ctr as Versuch.Formen.Auto;
Versuch.Formen.Lkw lkw = _ctr as Versuch.Formen.Lkw;
if(auto != null)
{
..... usw
}
if(lkw != null)
{
...usw
}
}
Aber sehr wahrscheinlich wird auch das dir abschmieren, da MainProgram.mainForm.splitContainer3.Panel1.Controls ein sehr komischer zugrifsweg auf deine Liste darstellt. Der statische member mainForm musss nicht zwangsläufig initalisiert und könnte daher auch null sein. Beachte dieses auch, entweder frägst nach null ab oder was besser wäre schau ob das wirklich sauber an der Stelle gelöst hast.
Verstehe dein Problem nicht so wirklich 🙂
Es ist klar das die Events nur geschmissen werden auf Control Seite.
Nur dein Button ist doch standardmäßig Enable = false (sprich klickst das Ding im Designer an und schaltest es schon von vornerein auf Button.Enabled = false). Erst wenn man etwas anklickt in der ListView wird der Button.Enable = true. Und wenn man durch irgendeine Aktion z.B. die ListView leert kann man da ebenso wieder reagieren.
Daher, welchen Anwenderfall gibt es den sonst das da genau dieses Problem auftritt?
Hrm, standardmäßig ist der Button deaktiviert.
private void OnSelectedIndexChanged(object sender, EventArgs e)
{
this.<Button>.Enabled = this.<ListView>.SelectedIndices.Count > 0;
}
Finde die Idee gut und würde mich gerne dran anhängen, hab diese Wochenende wahrscheinlcih ausser wieder ner Flasche Jacky nichts zu tun.
Würde gerne folgendes Anbieten für das Projekt:
Allerdings je nach zeit abhängig.
Später evtl. noch nen Skinning Tool für's Customizing
Das Problem an der Geschichte es gibt zu viele Wege das zu Lösen 😉
Im Moment fallen mir nur total übertriebene Varianten ein, die sich alle auf Windows API Lösungen beziehen. Würde mit den Gedanken spielen nen UserControl zu entwerfen und es zu einen Widget umzugestallten. Das geht indem man die WinProc überschreibt grade was WM_NCHITTEST angeht da hier ein Sizen nur in eine Logische richtung abhängig vom Parent erlaubt werden dürfte und man die CreateParam überschreibt und nur die passenden Styles einbindet. Dann würde ich nen intervall mit nen Timer einbauen um für die LinkeMaustaste bei der Left Mouse Down NonClient Area ein Docking zu realisieren. Den nur nach 2 Sekunden gedrückter Maustaste kommt meistens das typische Docking symbol. Die darstellung des Dockingsymbols übernimmt nen SubClassing einer Komponente die ich dann später aufs MainForm binde, dort wird nur via GDI die WM_PAINT angeschmissen mit den Abbild fürs Docken je nach Mauskoordinaten.
Das Parent wäre natürlich in deinen Fall ein normales Form. Die Menüs und aktionen würde ich über Command Pattern realisieren, würde die Sache vereinfachen.
Um nun die Speziellen Controls innerhalb der Widgeds zu relisieren würde ich den am nähesten kommenden Controls ableiten und Komponenten bzw. Controls / UserControls entwerfen die den gewünschten am nähesten kommen. Und diese dann auf den Widgeds platzieren.
Die Widgeds geben also die Logik für das Verhallten der Anordnung und das Docking vor während die UserControls spezialisiert sind und die jeweiligen spezialisierten Custom-Controls beinhalten. Und das Command Pattern kümmert sich um die verarbeitung und verteilung der Nachrichten zwischen den Widgeds den Controls usw. Ebenso kannst dann die Commands besser mitloggen falls das für Fehelrbehandlungen interessant sein könnte. Überschreibe dafür einfach in dne jeweiligen Command Klassen die ToString() Methode so kannst wie deren verarbeitung in einer Zentralen stelle wo diese über einen EventHandler verarbeitet werdne mitdokumentieren (oder Fehlerausgeben). Somit hätte deine ganze Anwendung grade mal ein try / catch drinnen.
Also kurz:
Widget => UserControl
DockingControler -> Component
Singleton -> CommandAction
Form -> Main Ansicht
SpecialControls => UserControls und vorhandene Controls
Nur mal ein Weg von vielen, denke nach ner Zigarette würden mir noch andere einfallen 😉
Hast nen leerzeichen zwischendrinnen string.split(,"Hier") 😉
Markier mal deinen Code dann siehst es.
Hrm, stimmt, habe das SQL Statement gar nicht angesehen: "select * from Werte"...
Schreib einfach dein Stamenet um... "... ORDER BY <SpaltenName> ASC" oder DESc wenn es vom letzten Datum ausgehen soll.
Bin irgendwie davon ausgegangen das dass schon drinnen wäre 😉
[Edit]herbivore war schneller 😉
Hrm, schade hätte darauf wetten können. Tjor, normal sollte er eigentlich nicht umsortieren wenn man sonst nichts angibt. Bleibt ja noch die Möglichkeit mit <DataTable>.DefaultView.Sort das ganze zu sortieren, damit es wieder passt. Wundern tut es mich aber ehrlich gesagt schon.
Schau dir trotzdem mal die <DataTable>.Columns["<SpaltenName>"].DataType an, ob da wirklich DateTime drinnen steht..
Wie Alphanumerisch mit strings die irendwelche "." zwischendrinnen besitzen sortiert aussehen weis ich nicht. Kann sein das 01.09 kleiner als 14.05.08 ist aus irgendeinen Grund.
Dictionary<int, CFrage> dic = new Dictionary<int, CFrage>();
XmlDocument doc= new XmlDocument();
doc.Load(menueLoad);
XmlElement root = doc.DocumentElement;
XmlNode node = root.SelectSingleNode("/fragen/index[@ID='0']");
label1.Text = Convert.ToString(node.InnerText);
CFrage myFrage = new Frage();
foreach (System.Xml.XmlNode _nd in node.ChildNodes)
{
if(_nd.Name == "frage")
myFrage.Frage = _nd.InnerText;
else
myFrage.Antworten.Add(_nd.InnerText);
}
dic.Add(node.InnerText, myFrage);
[PS] Freihand, hoffe man kann es trozdem lesen.
Hrm, fwürde einfach mal die Frage in den Raum werfen was du überhaupt vorhast. Nen LoginFenster und anschließend ne Form aufrufen und gut ist. Oder willst größeres Programm schreiben mit mehreren Fenstern Benutzern / Gruppen und Rechten?
Denke das wir dir dann am besten helfen können... nicht das nun versuchst über 20 Formulare über eren Proeprties oder Konstruktoren irgendwelche Logindaten hin und herzuschaufeln...
Hrm, du musst die Typen schon zuordnen nur mit einlesen ists nicht getan vorallem wenn es der falsche ist .-)
Du hast sehr wahrscheinlich in deiner Datenbank in der Tabelle für deine Datumswerte den Datentyp "TEXT" verwendet. Und das wird als string interpretiert, daher kann er logischerweise nicht korrekt sortieren - da er Alphanumerisch nunmehr vorgeht.
"1"
"11"
"12
"13"
...
"2"
"21"
"22"
...
usw...
Du kannst entweder den korrekten Datenbanktypen angeben also umstellen von "Text" auf "Datum/Uhrzeit", was das gescheiteste wäre. Oder den Datentyp nachträglich ändern über <DataTable>.Columns["<SpaltenName>"].DataType = typeof(DateTime); (was gehen sollte..) oder du schreibst einen <DataTable>.DefaultView.Sort indem die Spalte den Typ Datum anpasst... oder wandelst innerhalb deines Querys (dein SELECT Statment) den nvarchartypen via CAST()oder CONVERT() von nvarchar auf den Datentypen "Datum/Uhrzeit" um (irgendeines von beiden ging glaube ich bei OleDB nicht).
ServerNachricht = txtText.Text;
rtxtChat.Text += "Server:\n" + ServerNachricht; // <== hier
rtxtChat.SaveFile("c:/Chat/Verlauf.rtf");
txtText.Clear();
Hrm, kannst du evtl. nen Screenshot machen?
Überprüf mal ob das UserControl selbst auf AutoSize = False gestellt hast und ob die Controls die sich darin befindne evtl. irgendwie durch Dock oder Anchor ausgerichtet hast. Oder mit TableLayouts z.B. arbeitest.
Und ansonsten überprüf ob der Parent (denke mal wirst das Ding auf ne Form gezogen haben) vom UserControl ebenso nen Dock wie z.B. DockStyle.Fill verwendest.
this.<RichtextBox>.Text += this.<textbox>.Text;
Na ja du kannst xxxprod und herbivore Ansätze verwenden für ein StoredProcedure.
Du brauchst nur ne Tabelle innerhalb der Prozedur und nen paar Parameter um das ganze zu realisieren.
Die Tabelle dient als merker welche Treffer schon einmal vorkamen um die Suche zu indizieren.
Also du gehst die erste MengenID (denke das sind ja deine Mengen) durch und merkst dir jeden Treffer, die Treffer die du gefunden hast brauchst du nicht nochmals durchgehen und kannst sie somit aus der Suchschleife entfernen. So reduzierst du die Suche als solches und indizierst die Treffer.
Sprich, du merkst dir die Treffer und die Ergebnisse in einer Laufzeittabelle deiner Prozedur gleichzeitig hast du eine weitere Laufzeittabelle in deiner Prozedur die sich auf deine Tabelle bezieht bzw. dessen Inhalte. Du schmeißt dann nach jeden Treffer den Treffer aus deiner Laufzeittabelle die sich auf deine Tabelle bezieht heraus und verringsrt somit die Suche.
Somit läufst du nicht gefahr schon ein gefundenes MengenID nochmals zu suchen. Um die Suche zu optimieren achte darauf das die Datentypen und vorallem die Hilfsvariablen wirklich nur die größe beanspruchen die sie auch brauchen. Nicht das igendwo nen nvarchar statt nen int verwendest das evtl dann noch 250 zeichen groß ist. Das würde deine Suche enorm verschlechtern.
Wie das ganze deklarierst , wie ne WHILE Schleife auszusehen hat usw. siehe dazu google Stichwort: "T-SQL" folgende Dinge musst dazu wissen "TRUNCATE", "@@FETCH_STATUS", "FETCH", "DECLARE", "CURSOR", "OPEN", "DEALLOCATE"
Hoffe das hilft dir bei der Suche dann weiter 🙂