Laden...

Forenbeiträge von AtzeX Ingesamt 217 Beiträge

24.11.2006 - 14:24 Uhr

Hi kleines_eichhoernchen,

leider habe ich erst gerade eben deinen Reply bemerkt.
Da er ja doch umfangreich ist und ich gleich weg muss, kann ich ihn mir erst die Tage zu Gemüte führen.

Ich melde mich dann aber auf jeden Fall noch einmal!

Gruß,
AtzeX

18.11.2006 - 15:24 Uhr

Stimmt, hast Recht. Der Callback einer asynchronen Funktion läuft ja auch im 'sterbenden' Thread.

18.11.2006 - 14:54 Uhr

Danke euch schon mal.

@Herbivore:

Natürlich bekommt man mit Threading.Thread alles hin, was das Herz begehrt - auch Callbacks. Kannst du mir nen Tipp geben, wie? Wäre klasse.
Bisher habe ich nur die Idee, dass ich am Ende der Klassen-Methode, welche als eigener Thread läuft, als letztes einen Event der Klasse aufrufe.
Allerdings wird dieser Event gefeuert, bevor der Thread wirklich zu Ende ist...
Vielleicht gehts ja auch eleganter/sicherer?

@kleines_eichhoernchen:
Ich nehme an, du meinst ich soll nach SingleThreadActor bzw. MultiThreadActor googlen? Leider findet man da so gut wie gar nichts.
Und STA bzw. MTA bringen andere Ergebnisse.
Deshalb greife ich mal

oder fragst halt nach... auf, um dich besser zu verstehen. 😉

Gruß,
Atze

18.11.2006 - 11:17 Uhr

Hallo.

Ich habe zwei Fragen zum Thema Threading, die ich mir leider nicht selber beantworten kann.

  1. Wenn ich asynchrone Funktionen verwende (Delegate mit BeginInvoke), kann ich dann steuern, ob der Thread als Background-Thread oder nicht läuft?
    Und wie sieht es mit der Priorität aus?

  2. Muss ich den asynchronen Vorgang eigentlich immer mit EndInvoke abschließen, oder kann ich das auch sein lassen, wenn ich eh keine Rückgabewerte oder out-Parameter habe?
    Konkrete Aussagen finde ich dazu nicht.

  3. Bei den oben genannten asynchronen Methoden kann ich ja prima eine Callback-Methode angeben.
    Nur wie mir scheint ist die Kontrolle über den Thread nicht so gegeben wie bei Threading.Thread.
    Deshalb würde ich gerne letztere Technik verwenden.
    Allerdings kann ich da keinen Callback wie oben definieren. Oder doch?

Danke im Vorraus, fürs 'Licht ins Dunkle bringen'. 🙂

Gruß,
Atze

13.11.2006 - 10:52 Uhr

Danke euch. 😉

13.11.2006 - 08:23 Uhr

Aha, clever. Danke dir.

Da bin ich schon fast der Meinung, man sollte das immer so handhaben, oder?
Quasi als Preventiv-Maßnahme.

12.11.2006 - 20:57 Uhr

Hallo.

Ich habe eben in einem MSDN Sample folgenden Code gesehen:

// This example demonstrates the EventHandler<T> delegate.

using System;
using System.Collections.Generic;

//---------------------------------------------------------
public class MyEventArgs : EventArgs
{
    private string msg;

    public MyEventArgs( string messageData ) {
        msg = messageData;
    }
    public string Message { 
        get { return msg; } 
        set { msg = value; }
    }
}
//---------------------------------------------------------
public class HasEvent
{
// Declare an event of delegate type EventHandler of 
// MyEventArgs.

    public event EventHandler<MyEventArgs> SampleEvent;

    public void DemoEvent(string val)
    {
    // Copy to a temporary variable to be thread-safe.
        EventHandler<MyEventArgs> temp = SampleEvent;
        if (temp != null)
            temp(this, new MyEventArgs(val));
    }
}
//---------------------------------------------------------
public class Sample
{
    public static void Main()
    {
        HasEvent he = new HasEvent();
        he.SampleEvent += 
                   new EventHandler<MyEventArgs>(SampleEventHandler);
        he.DemoEvent("Hey there, Bruce!");
        he.DemoEvent("How are you today?");
        he.DemoEvent("I'm pretty good.");
        he.DemoEvent("Thanks for asking!");
    }
    private static void SampleEventHandler(object src, MyEventArgs mea)
    {
        Console.WriteLine(mea.Message);
    }
}
//---------------------------------------------------------
/*
This example produces the following results:

Hey there, Bruce!
How are you today?
I'm pretty good.
Thanks for asking!

\*/

Speziell dieser Teil erschließt sich mir nicht:

    // Copy to a temporary variable to be thread-safe.
        EventHandler<MyEventArgs> temp = SampleEvent;
        if (temp != null)
            temp(this, new MyEventArgs(val));

Inwiefern wird was damit Thread-Safe?

Gruß,
AtzeX

11.11.2006 - 10:17 Uhr

Ich kann dir leider nur sagen, wie es beim MS SQL Server 2000 ist, aber vielleicht wurde an der Logik ja nicht viel geändert.

Solltest du einen Enterprise MAnager haben (so hieß die Verwaltungskonsole beim 2000er) dann kannst du dort die DB rechts anklicken und mittels "Datenbank trennen" die DB abhängen.
Wo sie liegt und wie die Dateien heißen weißt du ja bereits, also kannst du diese Dateien dann verschieben.

Nun kannst du im Kontextmenü von "Datenbanken" die Datenbank wieder anhängen.

Das ganze lies sich im Query Analyzer (eine Art Kommandozeilentool des SQL Server 2000) auch mit den stored procedures "sp_detach_db" und "sp_attach_db" machen.

Vielleicht hilft es dir ja weiter.

Gruß,
Atze

06.11.2006 - 21:57 Uhr

Tu ich doch, tu ich doch... 😁

BTW:
Solche 'kleinen' Tipps sind immer gerne gesehen.
Man sollte viel öfter ein Stück Code hier reinstellen, nur um anschließend wieder mal aus seinen eigenen Fehlern zu lernen.
Ok, nicht immer sind's Fehler, aber man (zumindest ich) ist doch stets bemüht eine Sache 'besser' zu machen. 🙂

06.11.2006 - 17:31 Uhr

In der Tat, das gefällt.
Sollte in meinem Code zwar nicht auftreten, aber ich bau's trotzdem ein. 👍

06.11.2006 - 15:05 Uhr

Yep, eure Argumentation ist zwingend. 😁

Ich werde es so machen wie du es aufgezeichnet hast svenson.
Allerdings muss in deinem Beispiel noch "mServerState = parServerState;" gelöscht werden.
Kleiner Test meiner Aufmerksamkeit, he? 😉

Danke euch nochmals.

Gruß,
AtzeX

06.11.2006 - 14:27 Uhr

Hallo.

Mit stellt sich gerade eine kleine Frage bzgl. der 'Microsoft Vorgaben' in Bezug auf Events.

Ich habe getreu der Microsoft 'Vorgaben' einen Event "ServerStateChanged" und eine zugehörige Methode "OnServerStateChanged()" erstellt.

Nun überlege ich, ob ich diese Methode wirklich nur zum Auslösen des Events verwenden, oder ob ich da noch zusätzliche Logik implementieren soll/darf?

Konkret frage ich mich, ob ich die Zeile

mServerState = parServerState;

im unten stehenden Beispiel da lassen kann wo sie ist, oder ob ich sie in "Test()" verlegen soll.

public enum ServerState : int
{
	Started,
	PendingStart,
	PendingStop,
	Stopped
}

class Foo
{
	private ServerState mServerState;
	
	public event EventHandler<ServerStateEventArgs> ServerStateChanged;

	public void Test()
	{
		OnServerStateChanged(ServerState.Started);
	}
	
	protected void OnServerStateChanged(ServerState parServerState)
	{
		mServerState = parServerState;
		
		if (this.ServerStateChanged != null)
			this.ServerStateChanged(this, new ServerStateEventArgs(parServerState));
	}

		
}

public class ServerStateEventArgs : EventArgs
{
	private ServerState mServerState;

	private ServerStateEventArgs() { }

	public ServerStateEventArgs(ServerState parServerState)
	{
		mServerState parServerState;
	}

	public ServerState ServerState
	{
		get { return (mServerState); }
	}
}

P.S.:
Gibt es statt "Event-auslöse-Methoden" einen passenderen Namen? 😁

Gruß,
AtzeX

06.11.2006 - 11:31 Uhr

Gefunden im MSDN

Der Vorteil der @-Schreibweise besteht darin, dass Escapesequenzen nicht verarbeitet werden, wodurch z. B. das Schreiben vollqualifizierter Namen erleichtert wird:

@"c:\Docs\Source\a.txt"  // rather than "c:\\Docs\\Source\\a.txt"  

Gruß,
AtzeX

Edit:
Mist, zu langsam. 🙂
@norman_timo:
Klasse Signatur! 👍

30.10.2006 - 19:43 Uhr

Danke dir, genau das war es!

In obigem Fall kann ich den Namen mit

dr.RelationName

auslesen. Er lautet hier:

BBB_CCC

Dann kann ich mittels

DR.GetChildRows("BBB_CCC")

die Liste ermitteln und in der Schleife ausgeben.
Da hatte sich noch ein kleiner bis dato unbemerkter Fehler eingeschlichen:Es muss natürlich

drx["ID"].ToString()

statt

DR["ID"].ToString()

heißen.

Danke nochmals. 👍

30.10.2006 - 15:44 Uhr

Hallo.

Ich habe folgende XML-Datei:

<AAA>
	<BBB id="Hallo">
		<CCC id="test1"/>
		<CCC id="test2"/>
	</BBB>
</AAA>

Diese lese ich ein und schiebe sie in ein Dataset.

Nun lasse ich mir die enthaltenen Tabellen und Relationen anzeigen, was auch wunderbar funktioniert.
Die Relation zwischen Tabelle BBB und CCC ist also im Dataset bekannt, hoffe ich zumindest.

Danach lasse ich mir den Inhalt der Tabelle BBB anzeigen und möchte im Anschluss alle zugeordneten Datensätze der Tabelle CCC sehen.
Dazu verwende ich GetChildRows.

Allerdings scheint die Auflistung leer zu sein.

Anbei der Code:

System.Data.DataSet DS = new System.Data.DataSet();

FileStream fs = new FileStream(@"Z:\_\XML\Test.xml", FileMode.Open, FileAccess.Read);
StreamReader sr = new StreamReader(fs);
DS.ReadXml(sr);

foreach (DataTable dt in DS.Tables)
{
	Console.WriteLine("Table '{0}':",dt.TableName);
	foreach (DataRelation dr in dt.ChildRelations)
	{
		Console.WriteLine("  Has relation to '{0}'", dr.ChildTable.TableName);
	}
}

Console.WriteLine("--------------------------------------------------");

DataTable dt2 = DS.Tables["BBB"];
Console.WriteLine("Anzahl: " + dt2.Rows.Count);
foreach (DataRow DR in dt2.Rows)
{
	Console.WriteLine(DR["ID"].ToString());
	foreach (DataRow drx in DR.GetChildRows("CCC"))
	{
		Console.WriteLine("Childrow: {0}", DR["ID"].ToString());
	}
}
Console.ReadKey();

Das Ergebnis sieht so aus:

Table 'BBB':
  Has relation to 'CCC'
Table 'CCC':
--------------------------------------------------
Anzahl: 1
Hallo

Kann mir jemand sagen, warum?

Danke im Vorraus,

Gruß,
AtzeX

24.10.2006 - 12:32 Uhr

Ok, das wäre dann die oben von mir genannte zweite Alternative.
Du nutzt nur eine MDB, ohne Access selber zu verwenden. 😉

Ich denke jedoch, dass es nun auch keine Rolle spielt, ob das Ziel eine MDB (Jet-Engine) oder SQL-Server Tabelle ist.

Die Interpretation der Daten ist das Ausschlaggebende.

Leider kann ich da mangels Erfahrung nicht helfen.

23.10.2006 - 20:51 Uhr

Hast du Microsoft Access oder sprichst du nur von einer MDB-Datei, in die du ohne Access die Daten importieren möchtest?

Ich gehe mal davon aus, dass du Access hast:
Öffne die MDB Datei mit Access und rufe dann im Menü "Datei/Externe Daten/Importieren" auf.
Als Datei-Typ wählst du "Textdateien" und suchst die zu importierende Datei raus.
Alles weitere sollte recht logisch mittels des Wizards umsetzbar sein.

Um die Einstellungen des Wizards möglichst gut angeben zu können reicht schon mal ein Blick mit Notepad in die Datei. 😉

Gruß,
AtzeX

13.09.2006 - 10:22 Uhr

@herbivore:
Das gefällt mir sehr gut.
Und es funktioniert sogar! 😁

Man, hier kann man immer wieder was lernen.

Danke! 👍

12.09.2006 - 20:17 Uhr

Ich fand kakaomilchs oben zitierte Idee sehr gut, diese Logik vom Formular zu entkoppeln.

Ein zentrales Anwendungshandling halt.

Fahrt ihr wirklich immer über ein zentrales Form (und schaltet dieses evtl. unsichtbar)?

12.09.2006 - 20:14 Uhr

Wie lange dauert denn der Start einer Windows-Forms-Anwendung (kleine Hello-World-Applikation) bei ersten und weiteren Starts?

Ich hatte die Situation, dass jeder Start (egal ob der erste oder weitere) mind. 3 Sekunden dauerte und exzessive Festplattenzugriffe dabei stattfanden.

Letztendlich, nach tagelanger Suche, hat mir leider nur eine Neuinstallation von Windows weitergeholfen.
Nun ist nur der erste Start etwas verzögert, was aber durchaus normal ist.

Vielleicht probierst du es zum Vergleich auch mal auf anderen Rechnern aus.

Gruß,
AtzeX

12.09.2006 - 16:35 Uhr

Hmmm...
Kann ich daraus interpretieren, dass ich den richtigen Weg eingeschlagen habe?

11.09.2006 - 22:41 Uhr

Nun ja, aber dann habe ich das Problem, dass ich es nicht zentral verwalten kann.
Das müsste ja in das/die Form(s) rein, richtig?

Ich habe es jetzt mal so gemacht:

static void Main()
{
	Application.EnableVisualStyles();
	Application.SetCompatibleTextRenderingDefault(false);
	Controller mController = new Controller();
	mController.StartUp();
	while (Application.OpenForms.Count > 0)
	{
		Application.DoEvents();
		System.Threading.Thread.Sleep(100);
	}
}

Aber so richtig elegant ist das nicht.

Ich frag noch mal in die Runde, wie ihr das macht / machen würdet.

Gruß,
AtzeX

11.09.2006 - 14:28 Uhr

Dann terminiert es aber leider gar nicht mehr. 😉

11.09.2006 - 13:16 Uhr

Hallo Leute.

Folgende Aussage im Thread Trennung User Interface Anwendungslogik - best practice? hat mich angestachelt:

Original von kakaomilch
Die Referenz auf die View halte ich mir im Controller deshalb, weil bei mir alle Views erst vom controller generiert werden...

Das hört sich interessant an, speziell der Ansatz den Controller als zentralen Punkt einzusetzen und ohne ein laufzeitbestimmendes Formular zu arbeiten.
Deshalb habe ich auch einmal probiert das umzusetzen.

Ich habe eine Windows-Forms-Applikation erstellt und in der "program.cs" foldenden Code:

static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Controller mController = new Controller();
    mController.StartUp();
}

In der Methode "StartUp()" des Controllers habe ich

mView = new frmMain(this);
mView.Show();

// ... diverse Methodenaufrufe, welche über Events auch den View modifizieren.

// Doch leider beendet sich das Programm hier sofort.

Eigentlich klappt mit der Umsetzung von MVC gut, nur beendet sich das Programm nach Abarbeitung von "StartUp()" sofort.
Das ist nachvollziehbar, da das Formular ja nicht mit "Application.Run()" geöffnet wurde.
Deshalb muss logischer Weise eine andere Logik her.

Eine Möglichkeit wäre eine Schleife am Ende von "StartUp()", welche schaut, ob noch mindestens ein Formular geladen ist (oder je nach Bedarf, ob noch ein bestimmtes Formular offen ist).
Leider hakt es da bei der Umsetzung bei mir.

Andersherum frage ich mich, welche Logik ihr (oder speziell du, kakaomilch) in euren Anwendungen anwendet.
Oder arbeitet ihr immer mit einem 'primären Formular', welches mittels "Application.Run()" geöffnet wird und benutzt dieses dann um den Controller zu initialisieren?

Danke im Vorraus,
AtzeX

09.09.2006 - 21:30 Uhr

@marsgk:
Oder so. Danke. 😉

09.09.2006 - 14:51 Uhr

Z.B. so:

System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.UseShellExecute = true;
p.StartInfo.FileName = "MeineDatei.txt;
p.StartInfo.Verb = "open";
p.Start();
while (!p.HasExited)
{
    System.Threading.Thread.Sleep(100);
}

Gruß,
AtzeX

04.09.2006 - 16:53 Uhr

Danke euch beiden.
Das sind Argumente, die mein Gewissen beruhigen. 😉

@herbivore:
Ich wiederhole mich der Übersichtlichkeit halber auch in diesem Fall noch einmal:

Original von AtzeX
Wäre es nicht besser, wenn ich in jeder Klasse eine Art Log-Event erstelle und dann diesen Event zum Loggen jeweils in der übergeordneten Klasse abonieren lasse?
Dann wäre ich quasi beim 'bubblen'.
Allerdings schreibst du

Ich habe schon überlegt, ob man solche Log-Meldungen einfach irgendwie hoch-bubblen' lassen könnte/sollte und sie zentral abarbeitet?

Halte ich für keine gute Idee.

herbivore.
Was spricht denn eigentlich so dagegen?

😉

04.09.2006 - 16:29 Uhr

@Programmierhans:
Ich muss mich nochmal wiederholen:

Das heißt doch aber auch, dass sämtliche Klassen, quasi von der Log-Klasse abhängig sind und nicht autag funktionieren können. Macht man den Code dann nicht zu abhängig?
In deinem Fall ist es doch genauso?

04.09.2006 - 15:31 Uhr

So, ein Singleton Beispiel habe ich mir auch angeschaut.
Das heißt doch aber auch, dass sämtliche Klassen, quasi von der Log-Klasse abhängig sind und nicht autag funktionieren können.
Ist irgendwie auch nicht das Gelbe vom Ei.
Wäre es nicht besser, wenn ich in jeder Klasse eine Art Log-Event erstelle und dann diesen Event zum Loggen jeweils in der übergeordneten Klasse abonieren lasse?
Dann wäre ich quasi beim 'bubblen'.
Allerdings schreibst du

Ich habe schon überlegt, ob man solche Log-Meldungen einfach irgendwie hoch-bubblen' lassen könnte/sollte und sie zentral abarbeitet?

Halte ich für keine gute Idee.

herbivore.
Was spricht denn eigentlich so dagegen?

04.09.2006 - 15:18 Uhr

Nun, dann nehm' ich das mal frisch fromm fröhlich als nettgemeinten Tipp an und bedanke mich, allerdings mit der Anmerkung, dass mir das nicht fremd war. 😉

04.09.2006 - 15:10 Uhr

Hallo frisch.
Da kann ich dir leider nicht folgen.
Hast du den richtigen Thread verlinked?

04.09.2006 - 15:02 Uhr

Zum Thema Singleton:
Ich finde hier im Forum irgendwie kein Beispiel, bin aber mit der Suche noch nicht am Ende. 😉
Aber das hier habe ich gefunden:
Globale Variable
Speziell die beiden letzten Beiträge.
Also besser doch kein Singleton?
Oder eher gefragt: Wie sonst?

04.09.2006 - 14:27 Uhr

Hallo.

Da ich hier schon das ein oder andere mal äußerst überascht gewesen bin, was alternative Lösungsansätze angeht, dachte ich, ich frage mal in die Runde.

Mein bisheriges Anwendungsdesign gefällt mir irgendwie nicht.

Als Beispiel greife ich einmal das Logging heraus (dass .Net eigene/andere Log-Lösungen bietet möchte ich einmal außen vor lassen, das Loggen soll mal eher exemplarisch zu sehen sein).

Ich habe einen Einstieg ins Programm (Methode "Main()" in Klasse "Program").
Dort erstelle ich ein Logging-Objekt.
Allen weiteren Klassen-Instanzen anderer Typen übergebe ich nun jeweils dieses Log-Objekt, damit diese die Log-Funktionalität nutzen können.
Das ganze kaskadiert sich entsprechend weiter runter in tiefere Klassen.
Vorteil: Ich bin nicht an eine bestehende Infrastruktur gebunden. Ich könnte 'null' übergeben, wenn ich mal nicht loggen will/kann.
Nachteil: Ich muss das Objekt immer im Konstruktor mit-übergeben.

Ich habe schon überlegt, ob man solche Log-Meldungen einfach irgendwie 'hoch-bubblen' lassen könnte/sollte und sie zentral abarbeitet?

Wie würdet ihr das machen?

Des Weiteren überlege ich wie ich es am besten anstelle, wenn verschiedene Klassen, welche hierarchisch z.B. auch auf unterschiedlichen Ebenen liegen und demnach auch in einem Abhängigkeitsverhältnis stehen, mit dem UI kommunizieren.
Sollte/könnte man dort die Informationen ebenfalls 'bubblen' lassen?
Bei Objekten 'erster Ebene', die ich also selber z.B. im Form erstelle kann ich das über Ereignisse machen, klar.
Aber Ereignisse tiefer geschachtelter Objekte kann ich so einfach nicht abfangen.
Oder fehlt es mir an der richtigen Idee/dem Verständnis?

Wäre nett von euch, wenn ihr mir mit eurer Erfahrung ein wenig auf die Sprünge helfen könntet.

Gruß,
AtzeX

01.09.2006 - 20:09 Uhr

Ne, im MS Umfeld kann ich keinen Provider empfehlen, da ich bisher nur LAMP (Linux Apache MySql Php) Provider hatte.

01.09.2006 - 15:50 Uhr

Tja, leider habe ich das

Register(d); gar nicht als Pseudo-Code interpretiert.
Aber so sehe ich nun wie es gemeint war.
Ich werde mir aber natürlich Zeile für Zeile zu Gemüte führen!

Danke dir!

01.09.2006 - 11:32 Uhr

Ok, das Thema "Anonyme Methoden" hat weitergeholfen.
Nun verstehe ich was der Code machen soll. 😉

Allerdings erhalte ich die Exception "Cannot convert anonymous method block to type 'System.Delegate' because it is not a delegate type".

Jetzt weiß ich nur nicht, ob das evtl. mit dem mir immer noch unbekannten

Register(d); zusammen hängt.

01.09.2006 - 10:41 Uhr

Ich benutzte bereits VS 2005 / .Net 2.0.

01.09.2006 - 09:21 Uhr

Hi ihr beiden.

Register(d);

sagt mir leider gar nichts, und leider gibts da mehrere...
Aus welchem Namespace kommt es denn?

Edit:
Deinem Beispiel-Code kann ich auch nicht ganz folgen, Bernhard, der Compiler mag ihn irgendwie gar nicht...

01.09.2006 - 08:14 Uhr

Hi.

Hier würde ich ansetzen:

under the default settings SQL Server does not allow remote connections.

Meinen googeleien zu Folge entnehme ich, dass es mehr ein Feature denn ein Fehler ist. 😉

Ich denke hier wirste Klarheit finden:
http://www.anthonyalvarado.info/2006/06/sql-server-2005-express-connection.html

http://blogs.msdn.com/sql_protocols/archive/2005/12/22/506607.aspx

Gruß,
Atze

31.08.2006 - 16:47 Uhr

Hallo Bernhard.

Danke für deine Idee.
Die kommt meiner weiter oben genannten ja schon sehr nahe!
Ich habe es jetzt mal so implementiert (der alte Code ist auskommentiert):

public void Run()
{

	// ...

	//Click cl2 = new Click();
	//EventHandler eh2 = new EventHandler(MyKlickHandler2);
	//cl2.OnClick += eh2;
	//em.AddDelegate(eh2);

	Click cl2 = new Click();
	cl2.OnClick += (EventHandler)em.Decorate(new EventHandler(MyKlickHandler2));

	// ...
}


public class EventManager
{

	// ...

	public Delegate Decorate(Delegate dg)
	{
		delegateList.Add(dg, false);
		return (Delegate)dg;
	}

	// ...
}

Allerdings war die Anwendung von "delegate.Clone()" nicht notwendig, bzw. es funktioniert sowohl mit als auch ohne.
Oder habe ich dich falsch verstanden?

Gruß,
AtzeX

@the_lmich:
Schade, dass du dich nicht mehr meldest.
Mich hätte schon noch interessiert, warum es z.B. mit der foreach-Schleife bei dir funktionierte...

Edit:
@Bernhard:
Was ich noch fragen wollte:
Warum hast du die Methode eigentlich "Decorate" genannt?
Entspringt das evtl. einem Pattern oder einer grundsätzlichen Idee/Konvention?

31.08.2006 - 12:05 Uhr

Original von frisch
So kannst du nämlich bei jedem Parameter den Datentyp mit angeben und brauchst dir so keine Sorgen mehr machen.

...und verhinderst (insofern du Benutzereingaben übergibst) auch SQL-Injection-Angriffe. 😉

Gruß,
Atze

31.08.2006 - 11:30 Uhr

Soderle, anbei mal meine laufende Version.
Gibt es da technisch noch etwas zu verbessern/vereinfachen?

@herbivore
Die Methode "ResetAllEventsUnraised" habe ich mal anders aufgebaut, weil ich es als "For"-Schleife nicht hinbekommen habe.
Wie hätte das denn ausgesehen?

using System;
using System.Collections.Generic;
using System.Text;

namespace EventsTest
{
    class Program
    {
        static void Main(string[] args)
        {
            new TestBed().Run();
        }
    }

    public class TestBed
    {
        private EventManager em;

        public void Run()
        {
            em = new EventManager();
            em.AllEventsRaised += new EventManagerEventHandler(AllEventsRaisedHandler);

            Click cl1 = new Click();
            EventHandler eh1 = new EventHandler(MyKlickHandler1);
            cl1.OnClick += eh1;
            em.AddDelegate(eh1);

            Click cl2 = new Click();
            EventHandler eh2 = new EventHandler(MyKlickHandler2);
            cl2.OnClick += eh2;
            em.AddDelegate(eh2);

            cl1.NotifyClick();
            cl2.NotifyClick();

            cl2.NotifyClick();
            cl1.NotifyClick();

            Console.WriteLine("Press any key");
            Console.ReadKey();
        }

        void MyKlickHandler1(object o, EventArgs e)
        {
            Console.WriteLine("MyKlickHandler1 fired...");
            em.SetEventAsRaised(new EventHandler(MyKlickHandler1));
        }

        void MyKlickHandler2(object o, EventArgs e)
        {
            Console.WriteLine("MyKlickHandler2 fired...");
            em.SetEventAsRaised(new EventHandler(MyKlickHandler2));
        }

        void AllEventsRaisedHandler()
        {
            Console.WriteLine("AllEventsRaisedHandler fired...");
        }
    }

    public class Click
    {
        public event EventHandler OnClick;
        public void NotifyClick()
        {
            EventArgs e = new EventArgs();
            if (!(OnClick == null))
                OnClick(this, e);
        }
    }
    
    public delegate void EventManagerEventHandler();

    public class EventManager
    {
        public event EventManagerEventHandler AllEventsRaised;

        Dictionary<Delegate, bool> delegateList;

        public EventManager()
        {
            delegateList = new Dictionary<Delegate, bool>();
        }

        public void AddDelegate(Delegate dg)
        {
            delegateList.Add(dg, false);
        }

        public void RemoveDelegate(Delegate dg)
        {
            delegateList.Remove(dg);
        }

        public void SetEventAsRaised(Delegate dg)
        {
            if (delegateList.ContainsKey(dg))
                delegateList[dg] = true;

            if (CheckAllEventsRaised())
            {
                ResetAllEventsUnraised();
                if (!(AllEventsRaised == null))
                    AllEventsRaised();
            }
        }

        private void ResetAllEventsUnraised()
        {
            Delegate[] arrDG = new Delegate[delegateList.Keys.Count];
            delegateList.Keys.CopyTo(arrDG,0);
            foreach (Delegate dg in arrDG)
            {
                delegateList[dg] = false;
            }
        }

        private bool CheckAllEventsRaised()
        {
            bool isAllEventsRaised = true;

            foreach (bool isThisEventRaised in delegateList.Values)
            {
                if (!isThisEventRaised)
                {
                    isAllEventsRaised = isThisEventRaised;
                    break;
                }
            }

            return isAllEventsRaised;
        }
    }
}
30.08.2006 - 16:52 Uhr

Na die sind aber zimperlich.
Man lernt nie aus. 😉

Ich schau mir deine Vorschläge nachher mal an.
Jetzt gehts erst mal nach Haus.
Danke!

Edit:
Ich kann nur nicht nachvollziehen, warum du damit keine Probleme hattest the_lmich. 😉

30.08.2006 - 16:50 Uhr

Ich hoffe mal es handelt sich um einen SQL-Server 2000 (weil ich zum 2005er nicht viel sagen kann)?

Es wird wohl ein Backup einer Datenbank sein.
Dem kann man nämlich einen beliebigen Namen geben.

Du willst die DB jetzt sicherlich in deinen SQL-Server importieren?

Am einfachsten geht das im Enterprise Manager.
Dort erstellt du dir eine neue Datenbank, rufst von dieser dann das Kontextmenü auf und wählst dort im SubMenü "Alle Tasks" "Datenbank wiederherstellen" auf.
"Von Medien" wäre die Option deiner Wahl.

Danach unter Umständen noch die Berechtigungen korigieren (aber das hängt nun wirklich von deiner Umgebung ab).

Gruß,
AtzeX

30.08.2006 - 16:40 Uhr

Sorry, dass ich nochmal fragen muss.
Ich habe jetzt die ganze Zeit probiert und bekomme es nicht hin.
Bist du dir sicher dass ich ein Generic Dictionary mit einer For-Schleife iterieren kann?

Außerdem habe ich trotzdem versucht die foreach-Schleife ans Laufen zu bekommen.
Die oben genannte Exception wird nur ausgelöst, wenn diese Zeile zuvor ausgeführt wurde:

this.delegateList[eh] = false;

Hast du eine Ahnung warum?
Die Keys-Auflistung sollte doch dadurch nicht wiklich geändert werden.

30.08.2006 - 15:48 Uhr

Ok, hört sich alles plausibel an. Danke!

Verlierst du eigentlich nie den Überblick?
Unglaublich. 👍
Ich muss jetzt mal abkühlen. 😁

30.08.2006 - 15:37 Uhr

@the_lmich:
Ich nutze in meinem Beispiel noch "EventHandler" 😉

Original von herbivore
Hallo AtzeX,

Oder funktioniert es deshalb, weil der Typ Dictionary intern einen Hash-Wert ablegt um das Objekt zu identifizieren, und dieser Hash auch beim zweiten mal der gleiche ist?
nein, es funktioniert, weil es hier um einen Key geht. Und da zählt nicht, ob es derselbe ist, sondern es reicht, das es der Gleiche ist. Genauso, wie es bei einem Array-Index nicht darauf ankommt, welches int-Objekt übergeben wird, sondern nur welchen Wert es hat.

Aha. Aber ich verstehe noch nicht ganz, sorry.
Ich habe noch mal in der Hilfe zum Thema Dictionary-Generic nachgelesen.
Da steht "TKey" ist "The type of the keys in the dictionary.".
Ok, also in meinem Fall ist der Key vom Typ "EventHandler".
Demnach ging ich davon aus, dass ein Objektvergleich stattfinden muss, weshalb ich daraus schloss, dass ein Vergleich nicht klappen kann.
Da es aber funktioniert und du es auch schreibst wird von dem Objekt wohl irgendwie ein Key gebildet.
Deshalb dachte ich da an einen Hash.
Du schreibst es sei kein Hash. hehehe 😉
Was ist es dann?
Es muss doch letztendlich ein 'elementarer' Datentyp sein, der vergleichbar ist, oder?
Leider finde ich da nix drüber.

die ich mir nicht erklären kann.
Weiche auf eine for-Schleife aus.

Danke, werde ich probieren.
Ging es denn bei dir the_lmich?

30.08.2006 - 15:23 Uhr

Hach ich sehe ich kenne noch vieles aus dem .Net-Framework nicht. 🙁

Meine alternative (old-school) Lösung, die du aber auch in Scripten verwenden kannst) wäre

System.Diagnostics.Process.Start("NET START MSSQLSERVER")

abzusetzen.
Vorrausgesetzt du hast den Instanznamen des SQL-Servers nicht geändert.

Gruß,
Atze

30.08.2006 - 15:17 Uhr

Original von herbivore
naja, eben genau xxx oder wenn dir das lieber ist auch new EventHandler(xxx).

Sorry, hatte ich wohl übersehen.
Also der Code

em.SetEventAsRaised(xxx);

funktioniert tatsächlich. Nur warum?
Müsste es nicht eine neue Instanz eines EventHandler-Objektes sein?
Oder funktioniert es deshalb, weil der Typ Dictionary intern einen Hash-Wert ablegt um das Objekt zu identifizieren, und dieser Hash auch beim zweiten mal der gleiche ist?

Des Weiteren bekomme ich nun, wo die Methode "ResetAllEventsUnraised" zum ersten mal ausgeführt wird, in der Zeile

foreach (EventHandler eh in delegateList.Keys)

eine "InvalidOperationException" ("Die Auflistung wurde geändert. Der Enumerationsvorgang kann möglicherweise nicht ausgeführt werden.") die ich mir nicht erklären kann.

Sollte die nicht auch bei the_lmich auftreten?

30.08.2006 - 14:57 Uhr

So, habs mal im (neuen) Test-Code kommentiert. 😉

class Program
{
	static void Main(string[] args)
	{
		new TestBed().Run();
	}
}

public class TestBed
{
	private EventManager em;

	public void Run()
	{
		Click cl1 = new Click();
		em = new EventManager();

		EventHandler eh = new EventHandler(xxx);
		cl1.OnClick += eh;

		em.AddEventHandler(eh);
		cl1.NotifyClick();
		Console.WriteLine("Press any key");
		Console.ReadKey();
	}

	void xxx(object o, EventArgs e)
	{
		Console.WriteLine("xxx");
		// Wie komme ich hier an den EventHandler, über den "xxx" aufgerufen wurde?
		// Muss dafür "eh" auch eine Member-Variable von "TestBed" sein, oder kann ich die z.B. hier irgendwie ermitteln?
		em.SetEventAsRaised(???));
	}
}

public class Click
{
	public event EventHandler OnClick;
	public void NotifyClick()
	{
		EventArgs e = new EventArgs();
		if (!(OnClick == null))
			OnClick(this, e);
	}
}