Laden...

Forenbeiträge von Andreas.May Ingesamt 915 Beiträge

07.02.2008 - 17:14 Uhr

Musst dich halt etwas durchwühlen : Link
Und auf Wiki: Link

Fertigen Quellcode kann ich dir nicht geben, habe noch keine Erfahrungen damit gemacht. Aber in 3-6 Monaten, sollte ein Arbeitskollege ebenso eine Outlook Syncronisation angehen mit VS2008 Sync Framework.

Musst halt etwas unter diesen Stichworten nachgooglen 🙂

07.02.2008 - 11:08 Uhr

Gearbeitet habe ich damit noch nicht, aber sollte über System.Data.Odbc.OdbcConnection() zu handeln sein. Rest bleibt wie gehabt über Databindings arbeiten 🙂

07.02.2008 - 11:00 Uhr

Läuft IMHO etwas schneller. Vorallem das Kopieren von Dateien geht jetzt wesentlich fixer von statten.
Die Kompatibilität konnte ich nich nicht testen, da ich bis jetzt keine Anwendung hatte, die den Dienst komplett versagt hat wegen Vista. Wenn man das UAC aktiviert, wird man nicht mehr ganz so genervt. Meistens reicht jetzt nur noch eine Bestätigung anstatt zwei, oder sogar drei was ich auch schonmal hatte.

Und das war es auch im Großen und Ganzen. Viel hat sich sonst nicht getan IMHO.

Das mit der Kompatibilität würde mich aber mal interessieren...

Also, meinst es lohnt sich bereits es herunter zu laden?

07.02.2008 - 10:36 Uhr

Das kann auch das Form.Padding sein 🙂

07.02.2008 - 10:21 Uhr

Hrm, ich mein, wenn man ganz pervers sein will könntest wenigstens den Sonnenstand angeben. Da ja eh mit latitude ,longitude arbeitest kannst anhand also den Breiten und Längengrad nördliche oder südliche Entfernung bzw östlicher und westlicher. So kannst höchsten den Punkt anhand des Sonnenstandes und der der Höhe der Sterne ermitteln - aber ähm bei der Brechnung steig ich aus :p

Dir fehlt einfach noch ein Wert 🙂

07.02.2008 - 10:11 Uhr

Hrm, ich glaub hab das nur mal gesehen das es über Email ging, also über den Webcode. Die Bilder müssen halt auf nen Server dann liegen, der Dienst von GMX ladet dann über den Tagnamen das Bild herunter oder mapped das irgendwie in Postwriter Format das dann quasi gefaxt wird. Aber zu 100% bin ich mir auch nicht sicher.... Denke da hilft nur anrufen und fragen 🙂

07.02.2008 - 10:02 Uhr

if (args.Length >= 2 && args[0] == "-email")
     Console.WriteLine(args[1]);

args[0] -> args.Length == 1
args[1] -> args.Length == 2
args[2] -> args.Length == 3
....

Bei args.Length ≥ 2 && args[0] == "-email"
Wenn args Lenght ≥ kann args größer 2 sein, aber da args [0] == parameter email sein muss um die Bedingung zu erfüllen muss der logische zweite parameter immer die eine Emailadresse sein.

Aber ehrlich regex wäre evtl. besser 🙂

07.02.2008 - 09:49 Uhr

Na ja geh mal weg von der Methematik und stell dir eine Deutschlandkarte vor von der du weist, diese ist 20 cm lang und 20 breit. Deswegen findest du Berlin noch lange nicht, also das diese z.B. bei 18 cm Breite und 12 cm höhe zu finden sein muss. Du müsstest Berlin erst visuell suchen. Um Berlin nun nicht mehr suchen zu müssen über ein Koordinatensystem, musst du den Punkt erst bekannt machen. Bzw. eine Liste aller Städte führen mit Koordinaten um z.B. Berlin auf anhieb finden zu können.

07.02.2008 - 09:07 Uhr

Hrm, da man über DSL ja keine Faxe verschicken noch empfangen kann, brauchst ja einen kostenpflichtigen Dienstanbieter. Könntest das ganze auch über web.de oder gmx.de machen würde dann über Email laufen.

Kannst das auch über 1&1 machen, kostet glaube ich nur zusätzlich 2,49 EUR mehr im Monat. So wärst halt bei einen Anbieter - einfach bei 1&1 über http://www.control-center.de sollte man das auch aktivieren können. Oder zumindest die aktuelle Preisliste einsehen und einen Kundensupportnummer finden die dir dann weiter hilft.

06.02.2008 - 18:48 Uhr

Hrm, bin am rumprobieren von dem was Glücksbärchie schrieb. Der von der MSDN ist nen ThreadSpecificMouseHook also kein Systemweiter hook. Das ist dass was ich dich machen lassen wollte 😉

Der in Codeproject dagegen ist einer.
Warum das hInstance zurückgibt ist mir nen Rätsel, aber solange es funktioniert 🙂


Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0])

Also, lad dir das Codeproject *.Zip File runter und schau dir das dann mal genauer an. Das sollte dir weiterhelfen, vorallem da auch dein Keybordhook drinnen ist 🙂

Muss zugeben, hab selbst wieder was dazu gelernt.

06.02.2008 - 18:20 Uhr

Ich habe dir keinen Systemweiten Hook reingepostet, aus dem grund weil es unter C# wegen dem Framework einfach nicht möglich ist. Das funktioniert in C++, vielleicht auch in anderen Sprachen aber nicht in C#.

Das stimmt so nicht. Auszug von MS Seite (
>
)

Except for the WH_KEYBOARD_LL low-level hook and the WH_MOUSE_LL low-level hook, you cannot implement global hooks in the Microsoft .NET Framework...

Hier noch ein Artikel bei Codeproject zu dem Thema:
>
.

Hrm, dann müsste das glaube ich in etwa so aussehen?


[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr GetModuleHandle(string lpModuleName);


 hHook = SetWindowsHookEx(WH_KEYBOARD_LL, hookDeleg, GetModuleHandle(null), 0);

06.02.2008 - 17:17 Uhr

Ähm naja Eventhandler sind das nicht gerade...

Stell dir die Liste wie folgt vor.

MyHook3 willst du hinzufügen. MyHook1 und MyHook2 gibt es bereits. MyHook1 wird vor MyHook2 und MyHook1 dann ausgeführt. Es ist nur gut zu wissen aber nicht für dich jetzt so wichtig.

Das mit dem Breakpoint meinte ich wie folgt, wenn das Sampleprojekt öffnest und z.B. einen Breakpoint in die WndProc reinmachst. Sollte deine Maus nicht mehr Funktionieren oder wenn totalen wirwar verursachen evtl bleibt auch der Rechner hängen. Das kommt daher da im Sampleprojekt die Windowsnachrichten "quasi" weitergreicht werden. Schau es dir genau an, es ist wirklich gut gemacht und sehr einfach gehalten.

06.02.2008 - 16:31 Uhr

Muh! Es gibt sogar nen Sample hier im Forum...
Siehe LINK

/PS
Fast vergessen, denk dran unmanged Code nen Breakpoint in die WndProc und .. ach will gar nicht wissen was passiert - sieht sicher dann lustig aus 😉

06.02.2008 - 16:18 Uhr

Vielen Dank.

  1. Was bedeutet Low Level bzw. wann ist etwas Low Level?

Ok hole dazu kurz mal etwas aus:
Es gibt davon zwei Arten von hooks: lokale und Remote Hooks.

1.) Lokale Hooks verfolgen Ereignisse, die in Ihrem eigenen Prozess auftreten.
2.) Remote Hooks verfolgen Ereignisse, die in anderen Prozess(en) auftreten. Davon gibt es wiederum zwei Arten:

2.1) Thread-spezifisch verfolgt Erigenisse, die in einem bestimmten Thread eines anderen Prozesses auftreten. Ereignisse in bestimmten Threads / bestimmter Prozesse beobachten.

2.2) System-weit, verfolgt alle Ereignisse in allen Threads in allen Prozessen des Systems.

Jetzt noch ein Hinweis befor ich die Frage beantworte:
Wenn man einen Hook erzeugt, wird ebenso in Windows eine Daten-Struktur im Speicher erstellt - welche die Informationen über den Hook enthält. Ebenso wird der Hook in einer Liste von vorhandenen Hooks hinzugefügt. Neue Hooks werde vor den allten Hooks eingefügt.

Soo, zu dem Systemweiten Hook 2.2):
Für einen Remote Hook muss das System den Code der Hook-Prozedur in den Adressraum des anderen Prozesses einfügen! Und das kann nur geschehen, wenn sich die Funktion in einer DLL befindet.

Soo jetzt die Anweort, Low Level ist eine reine Abfangen von Hardware Eingabe-Ereignissen und beinhaltet keinen umgekehrten Fall. Warum ich das davor erklärt habe, ganz einfach. Ich habe dir keinen Systemweiten Hook reingepostet, aus dem grund weil es unter C# wegen dem Framework einfach nicht möglich ist. Das funktioniert in C++, vielleicht auch in anderen Sprachen aber nicht in C#. Daher habe ich dir einen Thread-spezifisch Hook (2.1) reingepostet und das EnumWindows um eben die ThreadIDs zu erhallten um sich über Subclassing darauf zu beziehen. Natürlich ist das umständlich aber mir fällt sonst kein besserer Weg dafür ein, ausser eben C++.

Vielen Dank.

2.1) Sehe ich das richtig, dass die Methode die als HOOKPROC der Function SetWindowsHookEx übergeben wird, als Parameter lParam eine Struktur von dem typ KBDLLHOOKSTRUCT liefert?

Jap, lParam gibt die Struktur von KBDLLHOOKSTRUCT beim Keybordhook wieder. Aber da diese unmanged ist benörigt man Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));. Wichtig ist auch als solches gekennzeichnet wird über [StructLayout(LayoutKind.Sequential)] von mir aus auch unsafe (Nicht das komplette Pointer-Land wird von der CLR verwaltet. Es gibt also immer noch eine kleine Enklave mit Namen unsafe :evil: ).

Vielen Dank.

2.2) Wenn das der Fall ist. Wie kann ich dann sagen, dass bei einer bestimmten Taste (die nicht gesperrt werden soll), der Hook "normal" durchgeführt werden soll.
Im moment würde ja die ganze Tastatur gesperrt werden oder?

Keine Taste wird gespeert, solange CallNextHook durchläuft.
Für Tasten die du speeren möchtest machst nen break 😉

Siehe hier mal nen alten C++ Code:


LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
	JNIEnv * env;
	KBDLLHOOKSTRUCT * p = (KBDLLHOOKSTRUCT *)lParam;

	if (jvm->AttachCurrentThread((void **)&env, NULL) >= 0)
	{
		switch (wParam)
		{
			case WM_KEYDOWN:
			case WM_SYSKEYDOWN:
			case WM_KEYUP:
			case WM_SYSKEYUP:
				env->CallVoidMethod(hookObj_kb, processKeyID_kb, (jboolean)FALSE, p->vkCode,g_kl);
				break;
			default:
				break;
		}
	}
	else
	{
		printf("C++: LowLevelKeyboardProc - Error on the attach current thread.\n");
	}

return CallNextHookEx(NULL, nCode, wParam, lParam);
}


  1. Was genau muss ich mit SetWindowLong machen?

Okay, nichts. Du versuchst wie im Beispiel den Hook zu realisieren und lässt SetWindowsLong weg. Ich hab da mist hingeschrieben, dachte über SetWindowLong könnte man nicht nur einen Hook erstellen für WNDPROC sondern auch für die Tastatur und die Maus. War mein Fehler, dieser ist absolut nur für C++ zugänglich oder halt um Windowsstyles umzusetzen wie die Position usw (Siehe Hook Typ 2.2).

  1. Mit UnhookWindowsHookEx mache ich die Änderungen von SetWindowsHookEx rückgängig oder?

Jap genau, den denk dran jeder Hook lässt das System und die Anwendungen instabieler werdne und du wirst merken das auch dein System an Performance verliert. Daher, entferne Hooks die nicht gebraucht werden.

  1. Innerhalb von HOOKPROC kann ich aus VS nicht debuggen oder?

Richtig, das kannst du nicht und wenn nen Breakpoint reinmachst sollte VS abschmieren 🙂

Ich weis immer noch nicht ob ich nicht besser nen C++ Hook reingepostet hätte den kannst ja auch einbinden und dir wäre viel Arbeit erspaart.

06.02.2008 - 14:27 Uhr

Hrm, ich habe halt immer nur ystem.Reflection.Assembly.Load("FileName") genutzt allerdings lief das ganze bei gerade mal 12 Assemblies auch recht gut durch. Das ganze hatte damals nur den Sinn und Zweck Module oder AddOns einzubinden. Aber bei 60 Stück keine Ahnung wie schnell das dann geht.

06.02.2008 - 14:11 Uhr

Hrm, okay das stimmt.

Ansonsten kann man es auch über System.IO.Directory.GetFiles("Path") durchgehen.

AppDomain.CurrentDomain.AppendPrivatePath(PathNew); wird zwar als veraltet angezeigt kannst es aber dennoch bedenkenlos benutzen.

06.02.2008 - 14:03 Uhr

@JAck30lena
Kann ich mir das "so einfach" machen, ich nutze einfach die ThreadId der "anderen" Anwendung?

Also laut SDK sollte genau das gehen, wenn nicht steht auf der MS Seite was falsches - was durchaus sein könnte, dann müsstest das ganze in C++ abbilden (was evtl sogar leichter sein könnte). Über EnumWindows bekommst halt nicht nur die Handels heraus sondern auch die ThreadIDs. Klar, schön wärs wenn es sowas wie ein EnumThreadId gäbe. Vielleicht gibt es soetwas auch - hab leider nur keines gefunden.

Denoch solltest es erstmal mit SetWindowsLong versuchen, da dieser Weg (zumindets als ich es vor urzeiten mal probiert habe) geklappt hatte, dafür brauchst dann allerdings die Fensterhandels von EnumWindows 😠

@JAck30lena
Dazu hätte ich eine grundsätzliche Frage, wie könnte man dies für "Systemtasten" umsetzen (Alt+Tab)?

Statt int WH_MOUSE_LL = 14, gibt es auch den WH_KEYBOARD_LL = 13 Hook, der genau gleich funktioniert nur eben in der HookProc wird das MouseHookStruct (siehe Code )


MouseHookStruct myMouseHook = (MouseHookStruct) Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));

zu folgenden Struct


[StructLayout(LayoutKind.Sequential)]
public class KBDLLHOOKSTRUCT
{
    public UInt32 vkCode;
    public UInt32 scanCode;
    public UInt32 flags;
    public UInt32 time;
    public IntPtr dwExtraInfo;
}

So kannst dann ein zweites Subclassing eben für die Tastatur laufen lassen und der vkCode ist der Bitweise wert von System.Windows.Forms.Keys (okay ist geraten sollte es aber sein).

Wenn die Anwendung, deren Hook ich "umgemapped" habe, neugestartet wird, ist dann wieder alles i. O.?

Dein Hook macht nichts anderes als die WindowsNachrichten abzufangen das heisst auch sollte eine Anwendung erst nach deiner Anwendung starten kann sich dein Hook nicht mehr drauf bezeiehen. Du müsstest also Quasi nen endlosthread haben der die Anwendungen überwacht ob eine gestartet oder beendet wird. Um dich reinzuhooken oder wieder den Hook zu beenden. Ansonsten, ja wenn die Anwendung neu gestartet wird, ist quasi wieder alles i.O. 🙂

06.02.2008 - 13:45 Uhr

Ups.. hatte mir deine Frage nicht genau durchgelesen.. Dachte nen einzelner Text der Selectiert wurde 😜

TNDAri's Lösung trifft den Nagel auf dem Kopf 😁
Für die Datenhaltung musst evtl. mal schauen ob die Daten in der Schleife durchgehst und Chars entfernst die nicht Sinnvoll sind wie eben das Fragezeichen. Oder eben mit Replace.

06.02.2008 - 13:43 Uhr

Hrm, mal so ne blöde Frage wolltest nen Plugintechnologie benutzen - Wenn ja, das rumkopieren der Assymbies kennst ja nun schon.

Um diese dann natürlich wieder in deine Anwendung mit einzubinden musst du sie auch wieder reinladen. Über System.Reflection.Assembly.Load("FileName"). Erst dann kannst auch die Funktionen davon nutzen.

Evtl. blick ichs auch grad nicht, denn wie Khalid schon meinte, über AppDomain.CurrentDomain.AppendPrivatePath reinladen macht das doch mit dem anderen Folder irgendwie unnötig oder nicht?

06.02.2008 - 13:25 Uhr

Ganz einfach 🙂

Erstell eine Klasse und leite von ListView ab, bei mir im Beispiel habe ich die RechteMaustaste mal genommen. Kannst das ganze beliebig umstellen wie du es eben brauchst.


public class ListViewEx : ListView
    {

        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                ListViewItem itm = base.GetItemAt(e.X, e.Y);

                if (itm != null)
                    return;
                ListViewItem.ListViewSubItem subitm = itm.GetSubItemAt(e.X, e.Y);

                if (subitm != null)
                    return;

                Clipboard.SetData(DataFormats.Text, subitm.Text);

                // only test
                string sData = Clipboard.GetData(DataFormats.Text) as String;
                if (string.IsNullOrEmpty(sData))
                    return;

                MessageBox.Show(sData);
            }

            base.OnMouseDown(e);
        }
    }

06.02.2008 - 13:05 Uhr

...

Die Windows API Funktionen :


[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);

[DllImport("user32.dll", SetLastError=true)]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);

[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);

Soo, du machst nun folgendes, vorrhin war es ja nur ein MouseHook kein LL Mousehook um nun den LL-Hook Systemweit hinzubekommen, nutzt du SetWindowLong wobei hier jedes Active Fenster durchgehst und für jedes Fenster ein eigenes Subclassing erstellst statt über SetWindowsHookEx, erstellst du diesen Hook dann über SetWindowLong!

Und denk dran statt :


public const int WH_MOUSE = 7;

Musst du folgendes benutzen:


public const int WH_MOUSE_LL = 14;

Wie gesagt, normal sollte das funktionieren, wenn nicht dann musst es wohl oder übel in C++ angehen.

06.02.2008 - 12:56 Uhr

Also, wenn das ganze Systemübergreifen gemacht werden soll gibt es da ein paar Dinge zu beachten 🙂

Wichtig zu erwähnen ausser WH_KEYBOARD_LL-Hooks und dem einfachen WH_MOUSE_LL-Hooks werden vom .NET Framework keine anderen Hooks unterstüzt! (LL = LowLevel).

Hier die Hook Types im einzelnen:


public enum HookType : int
{
     WH_JOURNALRECORD = 0,
     WH_JOURNALPLAYBACK = 1,
     WH_KEYBOARD = 2,
     WH_GETMESSAGE = 3,
     WH_CALLWNDPROC = 4,
     WH_CBT = 5,
     WH_SYSMSGFILTER = 6,
     WH_MOUSE = 7,
     WH_HARDWARE = 8,
     WH_DEBUG = 9,
     WH_SHELL = 10,
     WH_FOREGROUNDIDLE = 11,
     WH_CALLWNDPROCRET = 12,    
     WH_KEYBOARD_LL = 13,
     WH_MOUSE_LL = 14
}

Ich erkläre es lieber in 2 Schritten da ich selbst zu faul bin fertigen Code reinzuposten - ausserdem kann ich so einfach rumkopieren 😮)

Erstmal ein Beispiel für einen MouseHook für einen bestimmten Thread (KEIN SYSTEMWEITER HOOK🙂

Imports / Structs p/invoke


public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);

// hook handle as an int.
static int hHook = 0;

// constants
public const int WH_MOUSE = 7;

// MouseHookProcedure
HookProc MouseHookProcedure;			

// wrapper managed POINT class
[StructLayout(LayoutKind.Sequential)]
public class POINT 
{
	public int x;
	public int y;
}

// wrapper managed MouseHook struct
[StructLayout(LayoutKind.Sequential)]
public class MouseHookStruct 
{
	public POINT pt;
	public int hwnd;
	public int wHitTestCode;
	public int dwExtraInfo;
}


[DllImport("user32.dll",CharSet=CharSet.Auto,
 CallingConvention=CallingConvention.StdCall)]
public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, 
IntPtr hInstance, int threadId);

//This is the Import for the UnhookWindowsHookEx function.
//Call this function to uninstall the hook.
[DllImport("user32.dll",CharSet=CharSet.Auto,
 CallingConvention=CallingConvention.StdCall)]
public static extern bool UnhookWindowsHookEx(int idHook);
		
//This is the Import for the CallNextHookEx function.
//Use this function to pass the hook information to the next hook procedure in chain.
[DllImport("user32.dll",CharSet=CharSet.Auto,
 CallingConvention=CallingConvention.StdCall)]
public static extern int CallNextHookEx(int idHook, int nCode, 
IntPtr wParam, IntPtr lParam);

Aufruf Hook


if(hHook == 0)
	{
	        // Create an instance of HookProc.
		MouseHookProcedure = new HookProc(MouseHookProc); // siehe unteren code Abschnitt
				
		hHook = SetWindowsHookEx(WH_MOUSE, 
					MouseHookProcedure, 
					(IntPtr)0, // wir wollen ja nicht nur ein bestimmtes Fenster abfragen
					AppDomain.GetCurrentThreadId());
		//If the SetWindowsHookEx function fails.
		if(hHook == 0 )
		{
			MessageBox.Show("Hook failed");
			return;
		}
	}
	else
	{
		bool ret = UnhookWindowsHookEx(hHook);
		if(ret == false )
		{
			MessageBox.Show("Unhook failed");
			return;
		}
		hHook = 0;
	} 

Hook Proc


public static int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
	//Marshall the data from the callback.
	MouseHookStruct myMouseHook = (MouseHookStruct) Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));

	if (nCode < 0)
	{
		return CallNextHookEx(hHook, nCode, wParam, lParam);
	}
	else
	{
                // dein code bzw myMouseHook.pt.x gibt z.B X Coordinate zurück usw..

        
		return CallNextHookEx(hHook, nCode, wParam, lParam); 
	}
}

Genau das selbe gilt dann für die Keyboardabfrage schau unter www.pinvoke.net nach für das KeyboardHookStruct und in der Microsoft Platform SDK für alle anderne Fragen. Um das ganze nun Systemübergreifend zu gestallten. Brauchst du folgendes...

06.02.2008 - 12:13 Uhr

Hrm, also was willst du den an einen Barcodeleser senden?
Würde mich sogar wundern wenn das ginge 🙂

Das Einrichten wirst wohl oder übel über die Installationsroutine Lösen müssen. Das ca. so aussehen könnte "Bitte schließen sie den Barcodeleser an ihren PC an den RS232 Anschluss an. Vergweissern Sie sich das keine anderen Endgeräte angeschlossen sind. Scannen Sie bitte den mitgelieferten Barcode ein bis "Weiter" gedrückt werdne kann". Solange der Benutzer rumscannt gehst sämmtliche Ports durch bis einer dir etwas sendet. Diesen merkst du dir dann in irgend einen SettingFile (XML File usw..). Viel mehr Chancen wirst sonst nicht haben.

06.02.2008 - 11:42 Uhr

Ah Oki, hatte es dann falsch verstanden 🙂

Ich hoffe nur das s4rge das ganze versteht.

06.02.2008 - 11:34 Uhr

Hrm, du kannst dir mal den Artikel ansehen um das was ich nun schreibe besser zu verstehen.

Du kannst deiner Basisklasse (Mutterklasse) die Enum Werte A,B und C geben. Deine Nebenklassen (Kindklassen) beinhalten dann eine Bitweise veroderung. A | B = D, B | C = E.

Ich habe soetwas z.B. für mein CTI PopUpFenster für Telefonanrufe:


  [Flags]
        public enum PopUpManger : uint
        {
            PM_NONE = 0x00000000,
            PM_AUTO_SHOW = 0x80000000,
            PM_AUTO_HIDE = 0x20000000,
            PM_AUTO_HIDEONLAST = 0x10000000,
            PM_MODE_BIG = 0x08000000,
            PM_MODE_SMALL = 0x04000000,
            PM_AUTOMANGED = PM_AUTO_SHOW | PM_AUTO_HIDEONLAST | PM_MODE_BIG
        }

Ansonsten, wie talla schrieb Enums sind immer sealed.

06.02.2008 - 11:06 Uhr

Hrm, nö - dafür ist die Klasse ComboBoxItemEx ja eben gut. Der Abschnitt "only for test" im Konstruktor war nur um klar zu machen wie das ganze gefüllt wird.

Allerdings sehe ich grade das ich nen kleinen Teil vergessen habe mir reinzukopieren 🙂

Das hier fehlte oben, habs nachträglich eingefügt.


public class ComboBoxEx : ComboBox

Beispiel:


             // code im vs designer
             ComboBoxEx cbMyBrowser = new ComboBoxEx();

             // code zum füllen
             foreach(System.IO.DriveInfo dv in System.IO.DriveInfo.GetDrives())
             {
                 Image img = null;

                 switch(dv.DriveType)
                 {
                     case System.IO.DriveType.Ram:
                         img = <RamImage>;
                         break;

                         // usw
                 }

                 cbMyBrowser.Items.Add(new ComboBoxItemEx(dv.Name,img));

                 //usw..
             }

Die anderen Ordner wie "Current User Directory" kannst dann über Environment SpecialFolder herausbekommen und wie das durchsuchen halt manuell anfügen. Für das Durchsuchen kannst dann wiederum die Klasse ComboBoxItemEx überschreiben und eine Methode HitTest hinzufügen bei der Auswahl wird dann eben der standard Folder Browser aufgerufen. Oder du machst durch das SelectedValueChanged Event bei der ComboBox. Je nachdem, was dir schöner erscheint.

Wie gesagt das ganze kann man auch mit einer TreeView verbinden so das sogar mehrere Stufen ähnlich wie beim Explorer darstellen kann.

06.02.2008 - 11:02 Uhr

Hrm, das stimmt, aber ich glaube s4rge noch etwas Probleme hat sich vorzustellen wie die Modifiers eigentlich genau Funktionieren daher wollte ich mit dem etwas unschönen Beispiel ihm nur klar machen warum er nicht das Event seines UserControls das einen Button instanziert in seinem UserControl findet.

Persöhnlich finde ich es nicht gut, wenn ein UserControl das standardmäßig ja schon ein ClickEvent beinhaltet nochmals ein zweites ClickEvent beinhaltet das von einen Button stammt. Man weis dann nicht gleich zwangsläufig das dass zweite ClickEvent vom Button herkommt. Normal würde sich hier dann Command Pattern bzw. Actions anbieten oder man kann sich überlegen ob man das ClickEvent des Buttons weiterreicht indem man einfach das vom UserControl überschreibt und darin ebenso wie das base.Click weitergibt. Durch den sender wüsste man dann welches der Controls es gesendet hat - Aber das kommt drauf an was das UserControl eigentlich macht.

Sollte der Button auf dem UserControl etwas triggern so wäre es ja nicht mehr das Click Ereigniss das Daten ausgibt sondern die darauffolgende verarbeitung und da ein eigenes Event anzuknüpfen finde ich absolut in ordnung.

Hrm, ich hoffe man konnte verstehen was ich meine, ließt sich ziemlich konfus... 🤔

05.02.2008 - 23:02 Uhr

Also, ich poste mal den Namen des netten Internetproviders nicht rein bei dem ich mich mal beworben hatte. Aber ja, das gibt es tatzächlich auch in Deutschland und sogar noch mehr Nettigkeiten - leider hatte es nur nicht geklappt 😦

Ansonsten ich kann mich nicht beklagen, kann kommen und gehen wann ich will und bis zu 20 Fehlstunden in den neuen Monat mit reinnehmen. Für Überstunden gibt es dann Freizeit als Ausgleich. Trinken gibt es umsonst, von Cola bis zum normalen Wasser und das wichtigste, jede menge Kaffee. Ab und zu gibt es auch mal was Süßes oder Wecken zur freien verfügung.

Aber wie gesagt, das beste ist die freie Zeiteinteilung - ich habe morgens extreme Probleme aus dem Bett zu kommen, da ich meistens bis spät in die Nach hinein meine Fantasyromane verschlinge (bin Süchtig). Vor 8 Uhr aufstehen ist für mich nen Alptraum.. da lob ich es mir auch erst mal um 9-10 Uhr im Geschäfft auftauchen zu können. Das einzige was nicht wirklich störend ist, das man leider auch die Raucherzeiten abstempeln und hierzu ne Etage höher laufen muss. Aber das ist echt verschmezbar und gegenüber den Nichtraucherkollegen absolut Fair.

Kenne das ganze auch andersrum, wenn man bereits das Leben eines Leibeigenen führt und ganz ehrlich - Nie wieder. Trotzdem, vermisse ich gerade von dieser Firma her meine alten Kollegen, da gemeinsammes Leid doch sehr zusammenschweißt 🙂

05.02.2008 - 22:40 Uhr

Hrm,

JAck30lena hat das ganze relativ ausführlich erklärt 🙂

Mach erstmal die einfachste Lösung, geh in den Designer auf dein UserControl und klicke deinen Button an. Dort gibt es dann Modifiers (wie das in der Deutschen Virsual Studio Version genannt wird weis ich grade nicht) dort schaltest diesen dann von "private" auf "public". Wenn nun in dein MainForm reingehst und dein UserControl instanzierst wirst du deinen Button finden und dort dann via UserControl.Button.Click += new EventHandler(<methode>) erhällst du deinen ButtonClick Event auf dem MainForm 😉

05.02.2008 - 17:35 Uhr

Hrm, normal sollte das über die Office API kein Ding sein allerdings wenn das Thema Synchronisation dazu kommt solltest dir evtl. das Syncpaket in VS 2008 ansehen. Das sollte dir Lästige Kleinarbeit erspaaren.

[Edit]
Bin zu blöd nen Link zu posten...

05.02.2008 - 17:33 Uhr

Gerne doch, denk dran ist nur schnell hingesudelt. Einige Sachen wirst noch rund machen müssen und ein paar andere waren unnötig - Aber die Funktionsweise sollte denke ich damit zumindest nachvolziehbar sein 🙂

05.02.2008 - 16:18 Uhr

Im Prinzip ganz einfach, erstell zwei Klassen, eine DataGridViewEx die von DataGridView ableitet und eine TreeViewEx die von TreeView ableitet.

DataGridViewEx


public class DataGridViewEx : DataGridView
    {
        
        public DataGridViewEx()
        {
            base.AllowDrop = true;
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);

            if (e.Button == MouseButtons.Right)
            {

                HitTestInfo oInfo = base.HitTest(e.X, e.Y);
                if (oInfo.RowIndex == -1 && oInfo.ColumnIndex == -1)
                    return;

                object objToDrag = base.Rows[oInfo.RowIndex].Cells[oInfo.ColumnIndex].EditedFormattedValue;

                if (objToDrag == null && objToDrag as string != string.Empty)
                    return;


                base.DoDragDrop(objToDrag, DragDropEffects.Move);
            }
        }

        protected override void OnDragOver(DragEventArgs drgevent)
        {
            drgevent.Effect = DragDropEffects.Move;
        }
    }

Code in deiner Form



// für dne Konstruktor oder designer egal...
 this.dataGridView1.DragDrop += new DragEventHandler(dataGridView1_DragDrop);

// die funktion
 void dataGridView1_DragDrop(object sender, DragEventArgs e)
        {
            this.treeView1.DoDragDrop(e.Data, e.Effect);
        }



TreeViewEx



   public class TreeViewEx : TreeView
    {
        public TreeViewEx()
        {
            base.AllowDrop = true;
        }

        protected override void OnDragEnter(DragEventArgs drgevent)
        {
            base.OnDragEnter(drgevent);
        }

        protected override void OnDragOver(DragEventArgs drgevent)
        {
            drgevent.Effect = DragDropEffects.Move;
            base.OnDragOver(drgevent);
        }

        protected override void OnDragDrop(DragEventArgs drgevent)
        {
            this.Nodes.Add(drgevent.Data.GetData(typeof(string)) as string);
            base.OnDragDrop(drgevent);
        }

    }

Das war schon alles, simple und einfach. Ich war nur zu faul das mit den Nodeplatzierungen zu machen. X und Y Coordinaten usw. bekommst dann in der OnDragDrop Methode von TreeViewEx über den parameter drgevent mit rein. Über base.GetNodeAt(drgevent.X, drgevent.Y) kannst nachsehen wie die ParentNode dann heisst und die neue Node an der richtigen stelle platzieren.

05.02.2008 - 15:32 Uhr

Wüsste nicht was dagegen spricht ein Disposed Event einzubauen. Sofern die Klasse an einer Stelle disposed wird an der du die Buttons nicht auch gleich deaktivieren kannst.

Binde das Interface IDisposable in deine Klasse ein und löse dann das Event am Ende des dispose Vorgangs einfach aus.

Vergiss nicht :


if (this.Disposed != null)
    this.Disposed(this, null);

Für das initalisieren kannst das ganze umgekehrt dann im Konstruktor verwenden.

Aber meistens sollte es möglich sein dort wo die Klasse auf NULL gesetzt wird auch die Buttons gleich zu deaktivieren und dort wo sie initalisiert wird wieder zu aktivieren.

05.02.2008 - 14:45 Uhr

[Edit]
Klappt leider nicht..

Also ich "vermute" mal nach dem eben schiefgegangenen Test (daher das Edit) das die Ports deshalb offen sind da es sich um einen Barcodescanner handelt der Tastaturbefehle sendet. Also du scanst etwas ein und er tippt direkt schon den übersetzten string dort wo sich der Mousecursor befindet ein.

Was besseres fällt mir nicht ein, da man normalerweise bei den Scannern die ich kannte erst den Port öffnen musste....

05.02.2008 - 13:43 Uhr

Achso, hrm.. das ist natürlich blöd.

Ich positioniere die Fenster direkt beim Handle Create, da sie fix an der Position bleiben sollen. Ne art Snapin habe ich daher gar nicht.

Du könntest mit WinAPI GetWindowRect die Tazächlichen Fensterkoordinaten und größe (also mit den NonClientAreas) holen und in der WM_PAINT Nachricht in der WndProc nachschauen ob Right oder Left je nachdem gegen Screen.PrimaryScreen.WorkingArea.Right oder Screen.PrimaryScreen.WorkingArea.Left usw. läuft. Und wenn ja verhinderst das Zeichnen indem nen Break machst. Dann rufst du entweder über SetWindowPos oder MoveWindow die Position auf an der es gebunden werden soll und löst dann erst ein Invalidate auf. Würde sogar noch das Form um nen DockStyle enum LEFT TOP RIGHT BOTTOM erweitern. Damit dann beim wieder reinkommen in die WndPRoc Nachricht WM_PAINT weisst, wohin es nun einsnappen soll.

Dadurch das eben das Zeichnen unterbunden hast während der kritischen Stelle wird das Fenster erst positioniert (snappin) und dann erst angezeigt. Somit sollte es (eigentlich) kein flackern geben.

05.02.2008 - 13:26 Uhr

Hrm, du darfst nicht vergessen jedes Control besitzt ein Handle und besitzt somit eigenständige Windowsnachrichten (eigentlich kann man sagen, alles was nen Handle besitzt, besitzt auch eigenständige Windowsnachrichten). Windowsnachrichten werden daher nur auf dem jeweiligen Control abgearbeitet, somit auch die jeweilige Zeichenroutine.

Sprich, hast du ein UserControl auf dem du dann ein Panel drauf legst das ja wiederum ein Control ist. Bringt es dir wenig nur OnPaint Methode des das UserControl zu überschreiben oder dieses Transparent zu machen. Das Panel würde dennoch seine Standardfarben anzeigen und Controls und Bilder die auf dem Panel liegen würden dessen Hintergrundfarbe wenn diese Transparent sind durchlässig anzeigen.

Daher, musst etweder alle Controls überschreiben oder Subclassing anwenden. Oder du entwirfst ein UserControl, das nur grafische Objecte anzeigt. So dass nur das UserControl zu überschreiben brauchst und je nachdem die grafischen Objecte die du in einer Liste hinzufügst veränderst. Dann könntest du dieses auf eine Form bringen die dann Transparent machst - falls das so gewünscht sein sollte.

Es gibt aber auch tatzächlich die Möglichkeit über base.SetStyle(ControlStyles.AllPaintingInWmPaint, true); alle Controls die auf z.B. der Form liegen (somit auf einen ParenControl) diese zusammengefasst in den Windowsnachrichten der Form zu bringen. Somit könntest dann die Windowsnachrichten der Form (des ParentControls) abfangen wie z.B. die WM_PAINT Nachricht und dann darin zeichnen (da auch die ChildCOntrols dort nun ihre WindowsNachrichten weitergeben).

Ich würde evtl. sogar das angehen, da es vielleicht am einfachsten ist.

05.02.2008 - 12:41 Uhr

Setzt dafür einfach


this.DoubleBuffered = true;

oder über


base.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

Läuft bedes aufs selbe hinaus.

Hrm, denke nur das es über die WinAPI Funktion SetWindowPos (vielleicht?) leichter gewesen wäre da man hierbei auch noch den WindowsStyle entsprechend setzen kann. Um so z.B. das Fenster als PopUpFenster anzeigen zu lassen (SWP_FRAMECHANGED nicht dafür nicht vergessen).

05.02.2008 - 12:38 Uhr

Hrm, ich glaube solltest dir auf der MSDN mal die Access Modifiers ansehen.

public
The type or member can be accessed by any other code in the same assembly or another assembly that references it.

private
The type or member can only be accessed by code in the same class or struct.

protected
The type or member can only be accessed by code in the same class or struct, or in a derived class.
internal

internal
The type or member can be accessed by any code in the same assembly, but not from another assembly

Dein UserControl ist nichts anderes als eine Klasse.
Um Events die nicht durch die Basisklasse geerbt werden, nach aussen zu geben musst du entweder mit public oder internal deklarieren (je nachdem siehe Beschreibung). Du kannst auch die Liste der Controls durchgehen vom UserControl udn entsprechend casten um dann z.B. ein Button Event nach aussen zu geben. Du kannst das ganze auch via Design Patterns lösen indem zum Beispiel Aktionen nach aussen gibst, je nachdem.

Wichtig ist nur, mache nicht den Fehler ein Klick Event eines Buttons im UserControl nachmals als Event im UserControl zu deklarieren um dieses wieder nach aussen zu geben an eine Form. Das ist kein wirklich guter Ansatz, vorher mach lieber den entsprechenden Button public.

05.02.2008 - 12:20 Uhr

Oh, das kannst du selber angehen.

Gebe dir mal einen möglichen Ansatz (kein fertiger Code!):


    public class ComboBoxEx : ComboBox
    {
        public ComboBoxEx()
        {
            // important for owner draw
            base.DrawMode = DrawMode.OwnerDrawVariable;
            base.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
           
            
            // only for test
            this.Items.Add(new ComboBoxItemEx("TEST", <myImage1>));
            this.Items.Add(new ComboBoxItemEx("TEST", <myImage2>));
            this.Items.Add(new ComboBoxItemEx("TEST", <myImage3>));
        }


        protected override void OnMeasureItem(MeasureItemEventArgs e)
        {
            e.ItemHeight = 20;
            base.OnMeasureItem(e);
        }

        protected override void OnDrawItem(DrawItemEventArgs e)
        {
            e.DrawBackground();
            if (e.Index != -1 && this.Items[e.Index] is ComboBoxItemEx)
            {
                ComboBoxItemEx item = this.Items[e.Index] as ComboBoxItemEx;
                // own item draw
                item.OnDraw(e.Graphics, e.Bounds);
            }
                
            e.DrawFocusRectangle();
            base.OnDrawItem(e);
        }
    }

    public class ComboBoxItemEx
    {
        private Image m_oImg = null;
        private string m_sText = string.Empty;
        private Color m_oForeColor = Color.Black;
        private Font m_oFont = new Font("Arial", 8.2f);

        public Image Image
        {
            get { return this.m_oImg; }
            set { this.m_oImg = value; }
        }

        public Color ForeColor
        {
            get { return this.m_oForeColor; }
            set { this.m_oForeColor = value; }
        }

        public string Text
        {
            get { return this.m_sText; }
            set { this.m_sText = value; }
        }

        public override string ToString()
        {
            return this.m_sText;
        }

        public ComboBoxItemEx(string text, Image img)
        {
            this.m_sText = text;
            this.m_oImg = img;
        }
        public ComboBoxItemEx(string text) : this(text, null) { }
        public ComboBoxItemEx(Image img) : this(string.Empty, img) { }

        public virtual void OnDraw(Graphics e, Rectangle bounds)
        {

            // habe diesen teil nur schnell hingekritzelt...
            if (this.m_oImg != null)
                e.DrawImage(this.m_oImg, new Point(bounds.X, bounds.Y));

            e.DrawString(this.m_sText, this.m_oFont, new SolidBrush(this.m_oForeColor), new Point(bounds.X, bounds.Y));
        }

Was ebenso angehen könntest wäre wiederrum von ComboBox ableiten und im Konstruktor base.SetStyle(ControlStyles.EnableNotifyMessage, true); setzen, dann über protected override void OnNotifyMessage(Message m) die Nachrichten abfangen und eine TreeView drüber zeichnen oder über Controls Add eine TreeView direkt anzeigen. Die TreeView wäre dann natürlich entsprechend angepasst das die + und - Seperatoren nicht angezeigt werden.

05.02.2008 - 10:24 Uhr

Ah, okay das erklärt einiges 😉
Danke dir!

04.02.2008 - 17:37 Uhr

Du kannst das über Windows Themes angehen, damit auch diese berücksichtigt werden.
Unter folgenden Link findest du auch nen *.zip File mit Beispielcode für einen Windows Theme Button.

Denk dran, alle MS OS die älter als WinXP sind bereiten dir dann Probleme (Win200 geht evtl. mit SP4..).

Du kannst aber vorher Abfragen ob Windows Themes überhaupt vorhanden sind. Ansonsten bleibt dir nur über GDI alles selbst zu zeichnen oder mal unter WPF nachzusehen ob da das ganze möglich ist.

04.02.2008 - 14:46 Uhr

verwendetes Datenbanksystem: MSSQL 2000 / 2005

Hallo,
ich habe vor einiger Zeit eine SQL Funktion erstellt für das Filtern von Telefonnummern. Dabei viel mir etwas auf das ich noch nicht ganz verstehe.

Hier mal ein Beispiel:


IF OBJECT_ID (N'dbo.MyFunction') IS NOT NULL
   DROP FUNCTION dbo.[MyFunction]
GO
CREATE FUNCTION dbo.[MyFunction]
(
  @Number as varchar(MAX)
)  
RETURNS varchar(MAX) AS  
BEGIN
	DECLARE @Value as CHAR(1),
			@TmpNumber AS VARCHAR(MAX)

	-- removes all chars that are not numeric
	SET @TmpNumber = ''
	WHILE (LEN(@Number) > 0)
	BEGIN	
		SET @Value = LEFT(@Number, 1)
		IF(PATINDEX('[0-9+()]', @Value) > 0)
			SET	@TmpNumber = @TmpNumber + @Value
		SET @Number = RIGHT(@Number, LEN(@Number)-1)
	END

	RETURN @TmpNumber
END
GO
DECLARE @Output AS VARCHAR(MAX) 
SET @Output = (SELECT dbo.[MyFunction]('+++bla123blallala456,+++777/&(&&$88)'))
PRINT 'Wert: '+ @Output

Die Beispielfunktion läuft zwar durch, aber bei mehreren tausenden von Datensätzen wird das ganze langsam. Ändere ich nun alle VARCHAR(MAX) Datentypen auf z.B. VARCHAR(255) ab. So erhöhe ich damit die Performance.

Mir ist einfach nicht klar warum MAX VARCHARS (ich glaube das sind 6400 CHARS) anders behandelt werden als 255 CHARS. Den in der WHILE Schleife spielt das ja keine Rolle. Bei LEN(@Number) ist LENGTH ja die wirkliche string größe vielleicht nur 22 Zeichen lang.

Weis evtl. jemand warum das so ist?

17.01.2008 - 16:47 Uhr

Hrm, man kann CCar auch als "nicht abstract" deklarieren und wie folgt initalisieren. CVehicle<CCar> Car = new CVehicle<CCar>(); was aber zur folge hat das die Spezialisierungen rausfallen, irgendwelche ganz wichtigen besonderheiten.

Es kommt halt auf die Daten drauf an, wenn ich nur abstrakte Daten auswerte wie Modell, Hersteller, Anzahl Räder, anzahl Türen, Gangschaltung oder Automatik usw. gibt es keine Schwierigkeiten. Aber es gibt immer unterschiede z.B in der Technik des Autos. Nen Beispiel wäre der Sensor für den Ölstand. Ein Trabbi hat sowas evtl. überhaupt nicht während ein Dieselfahrzeug von BMW vom Typ XY einen Senser der Firma Hamatchi Unitet CXRV5 beinhaltet (Werte alle erfunden). Das aber sonst kein Auto besitzt.

Man kann auch den Ansatz angehen, eine Klasse Names: CUnknowCars :CCar zu erstellen um Z.B. Autos zu Identifizieren wie einen Trabbi, mit halt nur abstracten Daten die eh alle Autos besitzen.

Kommt halt drauf an wie viele spezifische Daten man hat. Ich wollte halt den Vorschlag aufzeigen, das man Daten aufdröseln kann befor man sie Abfrägt. Wie tief man dann reingeht ist Sache der Datenhaltung, Menge und Spezifikationen.

In den meisten Fällen wird es sich "nicht" lohnen CCar bzw. CBike wirklich abstract zu machen. Ich wollte es nur übertrieben darstellen. Ich hätte die beiden Klassen nicht abstrakt darstellen dürfen bzw. was drüber kritzeln sollen damit man erkennt das diese beiden Basiswerte ausreichen um aus einen Auto ein Auto zu machen und aus einen Motorrad eben ein Motorrad. Nur fand ich es wichtig das man eben den Mechanismuss zum Weiterverschachteln erkennt.

17.01.2008 - 15:37 Uhr

Hrm, CCar und CBike sind abstract 🙂

Aber was dir richtig aufgefallen ist, beide haben das selbe Interface IEngine. Daher wäre es möglich eine abstrakte Basisklasse namens CEngine zu erstellen die IEngine Implementiert und dort die Methode public abstract int GetMilesperhour(); beinhaltet. Die Klassen CCar und CBike würden dann von dieser ableiten und dennoch abstract bleiben. Aber das ist nicht notwendig CVehicle verbindet die meistens Eigenschaften die eben alle Fahrzeuge miteinander Verbindet. Wie Räder, Sitze, Seitenspiegel usw. Milesperhouer war unglücklich gewählt eigentlich wäre es sogar besser IEngine besitzt keine wirkliche Implementation.

Wichtiger ist aber die Frage:Warum müssen CCar und CBike bleiben?
Ganz einfach, das fängt damit an das ein Motorrad ja kein Auto ist, ein Auto hat z.B. Seitenfenster, Türen die besitzt ein Motorrad nicht. Aber nicht nur deswegen bleiben sie, vorallem wegen der Typisierung wie z.B das Motorrad ist von CBMW das andere dann von CHonda. Ebenso wichtig ist das CBMW wiederum ableitbar ist, da es sogenannte Sondermodelle gibt. Modelle die sogar den selben Namen haben aber sich nur in einem Kriterium unterscheiden.

Das Beispiel soll nur aufzeigen das man auf mehrere Stufen runter brechen kann ohne zu viele Basisklassen schreiben zu müssen. Aber ich denke JuyJuka's Ansatz sollte besser sein wenn VS2008 einsetzt.

Man kann das auch anderst Lösen, ich finde nur den Abfrageweg viel einfacher. Da ich gleich nach z.B. BMW Motorräder fragen kannst, oder nur nach allen Autos, alle Fahrzeuge oder einen bestimmten Auto usw. Also verschachtelte Abfragen. Wie Find und FindEx aufzeigen 🙂 Wobei ich evtl. mit etwas grübelarbeit das ganze auch auf einer Abfrage hinbekommen könnte. Auswertungen werden so vereinfacht, wichtig ist ja das später egal ob dann OR Mapping benutzt oder nicht, schnell Typbasierte Abfragen deinen Kollegen zur verfügung stellst. Und die beste suchst du dir schlussendlich raus.

Aber es gibt noch viel mehr Lösungsansätze. Hab das Ding nur schnell mal hingekritzelt ohne viel nachzudenken 🙂

17.01.2008 - 14:59 Uhr

Hrm, ich kann nur die Situation in Baden-Württemberg wiedergeben. Bzw. Raum: Stuttgart-Karlsruhe-Pforzheim-Heidelberg-Konstanz-Singen-Tuttlingen.

Hier gibt es massig viele Ausbildungsplätze, Fachinformatiker und vor allem BA-Studenten sind sehr beliebt.

17.01.2008 - 12:55 Uhr

Hrm, bei mir werden alle Laufwerke angezeigt.. ebenso bei vollen Zugrifsrechten.

17.01.2008 - 12:25 Uhr

Ups...
Sorry toaogrimreaper hatte mich etwas vertan.

17.01.2008 - 12:18 Uhr

Hrm, würde ganz einfach sowas machen 🙂



    public class CVehicles : List<IVehicle>
    {
        public CVehicles()
        {
            // only test <-- von hier bis..
            CVehicle<CHonda> Bike1 = new CVehicle<CHonda>();
            CHonda honda = Bike1.Create("CBR");
            honda.ABS = CHonda.ABSType.ELECTRONIC;

            CVehicle<CBMW> Bike2 = new CVehicle<CBMW>();
            CBMW bmw = Bike2.Create("BMW F 650 GS");
            bmw.SteeringWheelHeater = true;

            CVehicle<CBMW> Bike3 = new CVehicle<CBMW>();
            bmw = Bike3.Create("BMW F 650 GT");
            bmw.SteeringWheelHeater = true;

            CVehicle<CBMW> Bike4 = new CVehicle<CBMW>();
            bmw = Bike4.Create("BMW G 450 X");
            bmw.SteeringWheelHeater = false;

            CVehicle<CAudi> Car1 = new CVehicle<CAudi>();
            CAudi audi = Car1.Create("UDI A4 Avant");
            audi.Doors = CAudi.AvailableDoors.FourDoor;

            CVehicle<CAudi> Car2 = new CVehicle<CAudi>();
            audi = Car2.Create("Audi A3");
            audi.Doors = CAudi.AvailableDoors.FiveDoor;

            base.AddRange(new IVehicle[] { Bike1, Bike2, Bike3, Bike4, Car1, Car2 });

            // alle bmw maschinen die ne lenkradheizung haben
            CBMW[] MyBmwList = this.FindAllEx<CBMW>(delegate(CBMW _bmw) { return _bmw.SteeringWheelHeater == true; });

            // alle bikes die schneller als 200 fahren
            CBike[] MyBikesList = this.FindAllEx<CBike>(delegate(CBike _bike) { return _bike.GetMilesperhour() > 200; });

            // alle fahrzeuge die langsammer als 200 fahren
            List<IVehicle> MyVehicleList = this.FindAll(delegate(IVehicle _IVehicle) { return _IVehicle.Engine.GetMilesperhour() < 200; });

            // suche nen audi 4 türer
            CAudi[] MyAudi = this.FindAllEx<CAudi>(delegate(CAudi _audi) { return _audi.Doors == CAudi.AvailableDoors.FourDoor; });

            // <-- ... hier soll es nur nen Beispiel sein
        }

        public T[] FindAllEx<T>(Predicate<T> match)
        {
            List<T> itms = new List<T>();
            foreach (IVehicle vh in this)
                if (vh.Engine is T)
                    itms.Add((T)vh.Engine);

            return Array.FindAll<T>(itms.ToArray(), match);
        }
        public T FindEx<T>(Predicate<T> match)
        {
            List<T> itms = new List<T>();
            foreach (IVehicle vh in this)
                if (vh.Engine is T)
                    itms.Add((T)vh.Engine);

            return Array.Find<T>(itms.ToArray(), match);
        }
    }

    public class CBMW : CBike
    {
        // lenkgradheizung...ka wie das heisst ;-)
        private bool m_bSteeringWheelHeater = false;

        public bool SteeringWheelHeater
        {
            get { return this.m_bSteeringWheelHeater; }
            set { this.m_bSteeringWheelHeater = value; }
        }

        public override int GetMilesperhour()
        {
            return 210;
        }

        public CBMW()
        {
        }
    }

    public class CHonda : CBike
    {
        public enum ABSType
        {
            NONE = 0,
            MOTOR,
            ELECTRONIC,
        }
        private ABSType m_eABS;

        public ABSType ABS
        {
            get { return this.m_eABS; }
            set { this.m_eABS = value; }
        }

        public override int GetMilesperhour()
        {
            return 210;
        }

        public CHonda()
        {
        }
    }

    public class CAudi : CCar
    {
        public enum AvailableDoors
        {
            OneDoor = 0,
            TwoDoor,
            ThreeDoor,
            FourDoor,
            FiveDoor
        }
        private AvailableDoors m_eDoors;

        public AvailableDoors Doors
        {
            get { return this.m_eDoors; }
            set { this.m_eDoors = value; }
        }

        public override int GetMilesperhour()
        {
            return 150;
        }

        public CAudi()
        {
        }
    }

    public interface IEngine
    {
        int GetMilesperhour();
    }

    public interface IVehicle
    {
        string Model { get;}
        IEngine Engine { get;}
    }

    public abstract class CBike : IEngine
    {
        public abstract int GetMilesperhour();
    }

    public abstract class CCar : IEngine
    {
        public abstract int GetMilesperhour();
    }

    public class CVehicle<T> : IVehicle where T : IEngine
    {
        private string m_sModel;
        private IEngine m_IEngine;

        public string Model
        {
            get { return this.m_sModel; }
        }

        public IEngine Engine
        {
            get { return m_IEngine; }
        }

        public T Create(string _sModel)
        {
            this.m_sModel = _sModel;
            this.m_IEngine = Activator.CreateInstance<T>();
            return (T)this.m_IEngine;
        }
    }

Ich habe hier nur mal Bikes und irgendwelche Daten genommen, anhand vom interface IEngine kannst auch wie als Beispiel in der Klasse Cars, noch LKWS, Dreiräder, Busse usw. einbinden und je nach Model unterscheiden oder auch nicht, je nachdem wie viele Unterschiede halt machen musst. Und das was alle gemein haben eben in CVehicle bzw. IVehicle. Was alle Typen gleich haben dann eben in IEngine, was die Nebentypen bei mir dann Cars oder Bikes dann dort. Und wenn einen Sonderfall hast wie z.B. eine Sonderedition des Honda CBR 600 Models dann eben ableiten von CHonda. Also, es sind jede menge Verschachtelungen möglich.

FindAllEx und FindEx in der Liste sollen nur den ungefähren Weg aufzeigen den man dafür gehen kann um Suchanfragen einzubinden. Wahrscheinlich lässt sich da mit Array.ForEach was verbessern (wobei ich glaube das es eh aufs selbe hinausläuf).

Anhand von der Klasse CVehicle kannst diesen dann als Acessor verwenden, grade um die Daten effektiv dann von der Datenbank zu ziehen. Indem in den Klassen die IEngine implementieren beim Konstruktor z.B. das Select-Statement abbildest z.B in der Art:"SELECT * BLA BLA FROM BLA WHERE TYPE = 'IENGINE.TYPEENUM.CARS'".

ES gibt etliche Möglichkeiten das weiter zu treiben oder noch zu verbessern 🙂

[EDIT]
Die CBR 600 hat ne Motor ABS Bremswirkung oder sowas.. das konnte ich ja nicht falsch drinnen stehen lassen :p

17.01.2008 - 10:41 Uhr

Machs dir einfach...


    public void OnSerialDataReceived(object sender, SerialDataReceivedEventArgs args)
        {
            lock (this)
            {
            stream += sp.ReadTo(sp.NewLine);
            }
        }


Und nimm abrufen.Join(); wieder raus.

Dein Problem ist recht simple dein Thread greift auf eine Methode zu die evtl. von einen anderen Thread Blokiert wird. das geshcieht durch den sp.DataReceived += OnSerialDataReceived;aufruf. Daher, wird der globale Stream den du dir hälst Asynchron. Das passiert vorallem wenn der Benutzer mehrfach das button1_Click Ereigniss auslöst. Deswegen laufen dir die Daten davon... was sicher lustig aussieht 😮)

Aber schau dir am besten noch diesen Link an 🙂

Solltest das ein oder andere verändern - zB eine ThreadKlasse erstellen in dieser Klasse wird der Stream dann nicht nur Abgerufen sondenr auch verarbeitet, wichtig ist dann nur noch das Stream Synchronisiert wird. Somit sind die Schichten etwas besser getrennt. Es besteht ja keine notwendigkeit für die OnSerialDataReceived Methode inenrhalb der Klasse ComConnecter zu exestieren (Muss man aber nicht machen).

17.01.2008 - 10:26 Uhr

Nein das geht nicht aber du kannst sie einzelnd iterieren (ich hasse dieses Wort..).


this.GetType().GetMethods()
this.GetType().GetMembers()
this.GetType().GetProperties()


 typeof(CHuman).GetMembers()
typeof(CHuman).GetMethods()
typeof(CHuman).GetProperties()

usw..