Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   C# Eigenes Ereignis für eine Klasse (https://www.delphipraxis.net/42192-c-eigenes-ereignis-fuer-eine-klasse.html)

Luckie 15. Mär 2005 14:27


C# Eigenes Ereignis für eine Klasse
 
Ich habe folgende Klasse zum Splitten einer Datei:
Code:
public class FileSplitter
   {
     private string BuildPartFilename(string Filename, long Part)
     {
      string s;
      s = Filename+"."+Part.ToString();
      return s;
     }

     private int MinToRead(int a, int b)
     {
      return Math.Min(a, b);
     }


     public void Split(string Filename, string DestFolder, long cntParts, int PartSize)
     {
      FileStream fts; // FileToSplit
      FileStream pf; // PartFile
      string PartFilename;
      int nBytes = 4096;
      byte[] ByteArray = new byte[nBytes];
      int BytesToRead, BytesRead;
      long Done, OldDone;

      try
      {
         fts = new FileStream(Filename, FileMode.Open, FileAccess.Read);
         fts.Seek(0, SeekOrigin.Begin);
         for (int i = 1; i <= cntParts; i++)
         {
            OldDone = 0;
            BytesToRead = PartSize * 1024; // Size of the file parts
            try
            {
               PartFilename = DestFolder+"\\"+BuildPartFilename(Path.GetFileName(Filename), i);
               if (File.Exists(PartFilename))
                 File.Delete(PartFilename);
               pf = new FileStream(PartFilename, FileMode.CreateNew, FileAccess.Write);
               do
               {
                  BytesRead = fts.Read(ByteArray, 0, Math.Min(ByteArray.Length, BytesToRead));
                  pf.Write(ByteArray, 0, BytesRead);
                  BytesToRead = BytesToRead - ByteArray.Length;
                  Done = fts.Position * 100 / fts.Length;
                  if (Done != OldDone)
                  {
                     OldDone = Done;
                  }
               }
               while (BytesToRead > 0);
               pf.Close();
            }
            catch (Exception e)
            {
               fts.Close();
               throw new FSException(e.Message);                  
               
            }
         }
         fts.Close();
      }
      catch (Exception e)
      {
         throw new FSException(e.Message);
      }
     }
   }
Der würde ich jetzt gerne ein eigenes Ereigniss verpassen, damit ich den Fortschritt anzeigen kann. Ich habe allerdings keinen Plan, wie ich das mache. Das heißt, ich weiß weder, wie ich das Ereigniss in die Klasse bekomme, noch wie ich es dann in der WinForm Klasse einbinde.

MathiasSimmack 15. Mär 2005 14:47

Re: C# Eigenes Ereiegnis für eine Klasse
 
Du hast doch sicher das deutsche .NET-Framework SDK? Dann schau mal bitte unter folgendem Link rein:
Code:
ms-help://MS.NETFrameworkSDKv1.1.DE/cpguidenf/html/cpconprovidingeventfunctionality.htm
Da wird gezeigt, wie man ein eigenes Ereignis mit eigenen Werten usw. erzeugt und auslöst. Ich habe ein ähnliches Prinzip (wenn auch einfacher) bei meinem Help 2.0-Dienst benutzt. Wenn du bspw. die Auswahl der Filter-Combobox im Inhaltsverzeichnis änderst, dann sollen das die Pads für den Index und die Suche mitkriegen und ihre Comboboxen entsprechend anpassen. Und dazu habe ich auch ein Ereignis benutzt. Allerdings brauchte ich keine speziellen Werte. Du allerdings schon, denn ich vermute, du willst den Progressstatus an- bzw. übergeben.

Bei mir sieht´s halt so aus:
Code:
public string FindFilterQuery(string filterName)
{
   if(String.Compare(filterName,currentSelectedFilterName) != 0)
   {
      currentSelectedFilterName = filterName;

      // Ereignis auslösen
      OnFilterQueryChanged(EventArgs.Empty);
   }

   // ... anderer Code ...
}

public event EventHandler FilterQueryChanged;

protected virtual void OnFilterQueryChanged(EventArgs e)
{
   if(FilterQueryChanged != null) {
      FilterQueryChanged(this, e);
   }
}
Du müsstest dein Ereignis an dem Punkt auslösen/aufrufen, an dem sich die Bearbeitung der Datei in irgendeiner Form ändert. Ich denke, irgendwo hier:
Code:
pf.Write(ByteArray, 0, BytesRead);

PS: Das Benutzen habe ich wieder vergessen. :oops: Ist auch ganz einfach. Da das Ereignis von meinem Dienst zur Verfügung gestellt wird, schreibe ich eine Zuweisung:
Code:
// h2env ist meine Dienstklasse "HtmlHelp2Environment"
h2env.FilterQueryChanged += new EventHandler(OnFilterQueryChanged);
und die passende Funktion
Code:
private void OnFilterQueryChanged(object sender, EventArgs e)
{
   mainPanel.Refresh();
   filterCombobox.SelectedIndex = filterCombobox.Items.IndexOf(h2env.CurrentFilterName);
}
und das war´s. Das wäre jetzt ein Auszug aus dem Suchpad; sprich: einer eigenen Klasse (bei dir mit deinem WinForms-Teil vergleichbar).

Luckie 15. Mär 2005 15:15

Re: C# Eigenes Ereiegnis für eine Klasse
 
Danke ich werde es mir mal angucken. Aber nicht mehr jetzt.

Luckie 16. Mär 2005 14:33

Re: C# Eigenes Ereiegnis für eine Klasse
 
Puh. So weit habe ich es geschafft:
Code:
public event EventHandler Progress;
protected void OnProgress(EventArgs e, long Done)
{   
   if(Progress != null)
   {
        //???      
   }
}
Done hat hier schon den ruichtigen Wert. Nur wie bekomme ich den nach private void OnProgress(object sender, EventArgs e) von WinForm?

Das steht in meiner Klasse drinne. So sieht der Aufruf beim teilen aus:
Code:
if (Done != OldDone)
{
   OldDone = Done;
   OnProgress(EventArgs.Empty, Done);
}
So die Zuweisung beim Erstellen des Objektes un der neue EventHandler:
Code:
private void OnProgress(object sender, EventArgs e)
{
   //progressBar1.Value =
   Application.DoEvents;
}
Ich habe gerade gemerkt, wenn ich hier eine Messaagbox einbaue, dann wird die gar nicht aufgerufen. :gruebel:
Code:
private void btnGo_Click(object sender, System.EventArgs e)
{
   FileSplitter fs;
   try
   {
      fs = new FileSplitter();
      fs.Progress += new EventHandler(OnProgress);
      fs.Split(txtFile.Text, txtFolder.Text,
        Convert.ToInt32(lblCntFiles.Text),
        Convert.ToInt32(txtFileSize.Text));
   }
   catch(FSException fse)
   {   
      MessageBox.Show(fse.Message, APPNAME, MessageBoxButtons.OK, MessageBoxIcon.Error);
   }
}

Luckie 19. Mär 2005 10:23

Re: C# Eigenes Ereignis für eine Klasse
 
Ich darf es noch mal nach oben holen. ;)

Generalissimo 19. Mär 2005 11:41

Re: C# Eigenes Ereignis für eine Klasse
 
Ich denke so ohne weiteres wird das nicht gehen.
Vielleicht hilft dir das ja weiter

C# Galileo Open Book Kapitel 23 Ereignisse

Luckie 19. Mär 2005 15:44

Re: C# Eigenes Ereignis für eine Klasse
 
Also so kompliziert kann das doch nicht seim. Und ich kann mir nicht vorstellen, dass das noch niemand gemacht hat. Mit der VCL geht das ja auch ohne Probleme.

MathiasSimmack 19. Mär 2005 18:29

Re: C# Eigenes Ereignis für eine Klasse
 
Ich hatte dir eigentlich den Link ins Framework-SDK gegeben. Dort wird am Beispiel eines Weckers gezeigt, wie das Ereignis eigene Daten bzw. Werte an die Anwendung weiterreicht und wie diese dort abgefragt werden.

Robert_G 19. Mär 2005 19:23

Re: C# Eigenes Ereignis für eine Klasse
 
Wenn ihm der Bleistift aus der SDK Doku nicht zusagt, muss er sich eben mein wirres Beispiel antun. :P
Code:
/*
 * Created by SharpDevelop.
 * User: Robert
 * Date: 19.03.2005
 * Time: 20:11 PM
 */
using System;

namespace DelphiPRAXIS.Samples.EventsFürHerrnPuff // ;-)
{
   public class EventTest
   {
      /// <summary>
      /// <see cref="EventArgs"/>ableitung, die einen String hält.
      /// </summary>
      public class MyEventArgs :EventArgs
      {
         string someString;
         
         public string SomeString
         {
            get   {return someString;}
            set {someString = value;}
         }
         
         public MyEventArgs(string someString)
         {
            this.someString = someString;
         }
      }
      
      /// <summary>
      /// Los <see cref="Delegate">Delegatos</see>...
      /// </summary>
      public delegate void SampleEventHandler(object sender, MyEventArgs e);
      
      /// <summary>
      /// Der zu <see cref="EventTest.SampleEventHandler">SampleEventHandler<see/> gehörende <see cref="Event"/>
      /// </summary>
      /// <param name="e">siehe <see cref="EventTest.MyEventArgs">MyEventArgs</see></param>
      public event SampleEventHandler SampleEvent;
      
      /// <summary>
      /// Die Methode, die <see cref="EventTest.SampleEvent">SampleEvent<see/> feuert.
      /// </summary>
      protected virtual void OnSampleEvent(MyEventArgs e)
      {
         if (SampleEvent != null)
         {
            SampleEvent(this, e);
         }
      }
      
      /// <summary>
      /// Eine simple Beispielmethode.
      /// <remarks>Sie wird eigentlich "Hallo" in die Kommmandozeile ausspucken.
      /// dieser Wert kann aber durch den <see cref="EventTest.SampleEvent">SampleEvent<see/> abgefangen und verändert werden.</remarks>
      /// </summary>
      public void DoSomething()
      {
         MyEventArgs eventArgs = new MyEventArgs("Hallo");
         
         OnSampleEvent(eventArgs);
         
         Console.WriteLine(eventArgs.SomeString);
      }
   }
   
   class Program
   {
      
      void SampleEventCall(object sender, EventTest.MyEventArgs e)
      {
         e.SomeString = "Möööp";
      }
      
      
      public void RunSample()
      {
         EventTest eventTest = new EventTest();
         eventTest.SampleEvent += new EventTest.SampleEventHandler(SampleEventCall);
         
         eventTest.DoSomething();
         
      }
      
      
      public static void Main(string[] args)
      {
         Program program = new Program();
         program.RunSample();
      }
   }
}

Luckie 19. Mär 2005 19:38

Re: C# Eigenes Ereignis für eine Klasse
 
Zitat:

Zitat von MathiasSimmack
Ich hatte dir eigentlich den Link ins Framework-SDK gegeben. Dort wird am Beispiel eines Weckers gezeigt, wie das Ereignis eigene Daten bzw. Werte an die Anwendung weiterreicht und wie diese dort abgefragt werden.

Ach so, der ließ sich nicht aufrufen.

Luckie 19. Mär 2005 20:56

Re: C# Eigenes Ereignis für eine Klasse
 
Liste der Anhänge anzeigen (Anzahl: 1)
So, ich habe das jetzt mal nach diesem Galileo Dingsbums probiert. Hier mal der Komplette Source im Anhang.

So langsam habe ich fast die Nase voll. Muss das denn so kompliziert sein? :roll:

MathiasSimmack 19. Mär 2005 20:59

Re: C# Eigenes Ereignis für eine Klasse
 
Das Thema mit den Namespaces von Help 2.0-Dateien hatten wir doch schon bei deiner CHM-Datei, die Links aus dem Framework benutzt. Ich sehe ja von hier nicht, welche Version oder Sprachversion du benutzt. Also, du könntest entweder im Hilfebetrachter von Microsoft nachschauen, ob der Name
Code:
MS.NETFrameworkSDKv1.1.DE
mit deiner Version übereinstimmt, oder du schaust im Index unter "Auslösen von Ereignissen", oder du benutzt die Suche und suchst nach "AlarmEventArgs". Das sollte dich alles in das entsprechende Kapitel deiner Framework-SDK-Version bringen.

Robert_G 19. Mär 2005 21:08

Re: C# Eigenes Ereignis für eine Klasse
 
Zitat:

Zitat von Luckie
So, ich habe das jetzt mal nach diesem Galileo Dingsbums probiert. Hie rmal der Komplette Source:
Code:
...eine Menge blödsinniger Code, der einem alles mögliche erklären will. Nur als abstraktes event Beispiel taugt er nix... :?

Zu solchen "Tutorials" sage ich jetzt besser nix... :roll:

Zitat:

Zitat von Luckie
So langsam habe ich fast die Nase voll. Muss das denn so kompliziert sein? :roll:

Ist es doch gar nicht!
Wie deklarierst du in Delphi einen Event?
Du deklarierst einen FunktionsPointer:
Delphi-Quellcode:
type TSampleEventHandler = procedure (Sender :TObject;e :TMyEventArgs) of object;
Jetzt braucht deine Klasse noch die passende Property
Delphi-Quellcode:
type TEventTest = class
  private
    fSampleEvent :TSampleEventHandler;
  public
    property OnSampleEvent :TSampleEventHandler read fEvent write fEvent;
end;
In irgend einer Methode würdest du ihn dann aufrufen:
Delphi-Quellcode:
var
  MyEventArgs :TMyEventArgs;
begin
  ...
  if Assigned(fSampleEvent) then
  begin
    MyEventArgs := TMyEventArgs.Create('Hallo');
    try
      fSampleEvent(this, MyEventArgs);
    finally
      MyEventArgs.Free();
    end;
  end;

  ....
end;
Ist doch fast das gleiche. Wobei ich den .Net Weg für einfacher halte. Der eigentliche Unterschied besteht nur darin, dass du in .Net soviele Delegates an den Event hängen kannst wie du lustig bist. :)

Luckie 19. Mär 2005 21:13

Re: C# Eigenes Ereignis für eine Klasse
 
Na ja . bei .NET kommt noch die Klasse für die Argumente hinzu. Und igrnedwann gehen einem die Varaiblennenamen aus bzw. man hat so viele, dass man nicht mehr weiß, wo was hingehört. Ich bin übrigens der Meinung, dass ich schon ziemlich dicht dran bin. Könntest du mir bitte mal eben unter die Arme greifen (Aber bitte nicht kitzeln.) und den Rest machen? Es soll einfach nur der Fortschritt in der Progressbar angezeigt werden.

MathiasSimmack 19. Mär 2005 21:14

Re: C# Eigenes Ereignis für eine Klasse
 
Ich hänge mich mal rein und sage, dass sich der Quellcode mit folgenden Änderungen immerhin kompilieren lässt:
Code:
   class FileSplitter
   {   
      public delegate void FSProgressEventHandler(object sender, FSProgressEventArgs e);
      public event FSProgressEventHandler   OnProgressHandler;
      
      protected void OnProgress(FSProgressEventArgs e)
      {
         if(OnProgressHandler != null)
         {
            OnProgressHandler(this, e);
         }
      }
      

      /*
      FSProgress fsProgress;
      public void OnProgress(FSProgress fsProgress)
      {
         this.fsProgress = fsProgress;
         fsProgress.OnProgressHandler += new FSProgress.OnProgressHandler();
      }
      */

// der Rest der Klasse
}
und dann für die Form:
Code:
      public WinForm()
      {
         //
         // Required for Windows Form Designer support
         //
         InitializeComponent();

         FileSplitter splitter = new FileSplitter();
         splitter.OnProgressHandler += new FileSplitter.FSProgressEventHandler(this.FileSplittingProgress);
         
         //
         // TODO: Add any constructor code after InitializeComponent call
         //

      }


      private void FileSplittingProgress(object sender, FSProgressEventArgs e)
      {
         // mach was draus
      }
Boah, endlich kann ich auch mal den Chef kritisieren :mrgreen:, @Luckie: Du solltest unbedingt deinen Klassencode in eine extra Datei auslagern. Bei dem Gewurschtel sieht man ja nicht durch.

MathiasSimmack 19. Mär 2005 21:15

Re: C# Eigenes Ereignis für eine Klasse
 
Zitat:

Zitat von Luckie
Könntest du mir bitte mal eben unter die Arme greifen (Aber bitte nicht kitzeln.)

Ach so, Robert soll ... Okay, :| :pale: :cry:

Luckie 19. Mär 2005 21:26

Re: C# Eigenes Ereignis für eine Klasse
 
Jetzt habe ich nur noch mit dieser Zeile Probleme:
Code:
fs.OnProgressHandler += new FileSplitter.FSProgressEventHandler(this.OnProgress, FSProgressEventArgs);
@Mathias: Das kommt im nächtsen Schritt, das Auslagern in eine extra Datei.

Robert_G 19. Mär 2005 21:33

Re: C# Eigenes Ereignis für eine Klasse
 
Zitat:

Zitat von Luckie
Jetzt habe ich nur noch mit dieser Zeile Probleme:
Code:
fs.OnProgressHandler += new FileSplitter.FSProgressEventHandler(this.OnProgress, FSProgressEventArgs);

Mensch Micha...
Du kannst doch kein Delagte mit Parametern übergeben. Das geht doch mit Delphis FunktionsPointern auch nicht. ;)

Du hängst einfach an den event eine neue Instanz deines Delegates ran. Diese bekommt die benötigte Methode im Konstruktor übergeben. So hatte es Methias doch auch geschrieben....
Zitat:

Zitat von Luckie
@Mathias: Das kommt im nächtsen Schritt, das Auslagern in eine extra Datei.

Nix leichter als das. :mrgreen:
Combine\add\new project\ClassLibrary
Einfach die Dateien mit deinen Klassen runter ziehen und in deiner WinForms GUI eine Referenz auf das neue ClassLib Projekt setzen -> färtsch. ;)
Genau wie in Delphi32 mit Packages auch. ;) (C# und Delphi sind sich viel ähnlicher als es die meisten wahrhaben wollen. ;) )

MathiasSimmack 19. Mär 2005 21:33

Re: C# Eigenes Ereignis für eine Klasse
 
Was für ein Problem ist denn das? Bei mir hat´s nur nix angezeigt, ansonsten ließ sich das Programm kompilieren und starten. Aber kann sein, dass ich das irgendwie falsch zugeordnet habe, und dass der Progressbar deshalb nichts zeigte. Die Dateiteile wurden problemlos erstellt. Hm ...

Ich wollte dir einfach nur zeigen, wo IMHO der Code reinmuss, und wie du das Ereignis dann in deiner Form benutzt. Ich habe -Gott sei Dank!- keine eigenen Werte gebraucht, darum ging das bei mir mit meinem Ereignis in meinen Pads ratzfatz. :stupid:

MathiasSimmack 19. Mär 2005 23:03

Re: C# Eigenes Ereignis für eine Klasse
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hah, bei mir geht´s jetzt. :zwinker:
Vielleicht nicht gerade der schönste Code, aber das überlass ich dir.

Mirilin 19. Mär 2005 23:14

Re: C# Eigenes Ereignis für eine Klasse
 
:hi:

Fürs Protokoll : FAQ-Eintrag zum Stichwort "9""9"
Zitat:

Manchmal ist es einfach nötig, auch längere Code-Beispiele zu veröffentlichen. In so einem Fall hänge diese bitte als Attachment an Deinen Beitrag an, anstatt diese im Beitrag selbst zu veröffentlichen. Dein Beitrag würde sonst eindeutig zu lang und zu unübersichtlich.
danke :)

mfg Tobias

Luckie 21. Mär 2005 02:49

Re: C# Eigenes Ereignis für eine Klasse
 
Meine Güte war das eine schwere Geburt. Besten Dank euch beiden. Und jetzt hätte ich das ganze gerne noch in einem Thread. :mrgreen:

Ach eine Frage habe ich noch: Ich habe jetzt die ganze Splitter Klasse in einer eigenen Datei. So weit so gut. Die habe ich dann dem SharpDevelop Projekt hinzugefügt. Aber in der Haupt-datei, also in der datei von meiner Form steht nirgens ein Verweis auf die Datei mit der FileSplitter-Klasse. Wie findet der jetzt beim Kompilieren den Code?

Und warum habe ich zwei namespaces FileSplitter? Einmal in der WinForms.cs datei und einmal in der extra datei für die FileSplitter-Klasse? Was hat das mit den namespaces auf sich?

MathiasSimmack 21. Mär 2005 08:13

Re: C# Eigenes Ereignis für eine Klasse
 
Die Namespaces sind der Vorteil, den ich persönlich bei .NET sehe. Weil sowohl dein Programm als auch die Klasse zum gleichen Namespace gehören, brauchst du keinen Verweis. Anders wäre es, wenn du bspw. in die "SplitterClass.cs" schreiben würdest:
Code:
namespace FileSplitterClass
{
     // und hier der Klassencode
}
In dem Fall müsstest du im Hauptprogramm oben
Code:
using FileSplitterClass;
angeben, damit es wieder funktioniert. Würdest du aus der "SplitterClass.cs" nun eine eigene Assembly machen, dann könntest du alles so lassen wie es ist. Du müsstest nur eine Referenz auf die DLL setzen, und fertig.


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:50 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz