Laden...
S
sth_Weird myCSharp.de - Member
Dipl.Ing IT (BA) BaWü Dabei seit 17.01.2007 469 Beiträge
Benutzerbeschreibung

Forenbeiträge von sth_Weird Ingesamt 469 Beiträge

17.09.2008 - 16:28 Uhr

stimmt, sorry, wollte das Problem oben nicht verkomplizieren und hab das IFIlter Interface, das von der Basisklasse implementiert wird und von dem ich ja schon wusste, da kann ich keine Operatoren reinbringen, weggelassen...
Man interpretiere die Frage also unabhängig von der Frage oben:
Macht es Sinn / ist es schön überhaupt noch ein Interface zu haben, wenn ich aufgrund der Verwendung der Klassen die das Interface implementieren sollen sowieso gezwungen bin eine Basisklasse zu implementieren, von welcher alle abgeleiteten Klassen erben?
Beispiel: Ich habe ein Interface ITier und eine Klasse AlleTiere, welche eine Liste von verschiedenen Tieren enthalten soll. Da ich AlleTiere serialisieren will (also nicht ISerializable Interface implementieren sondern über das [Serializable] und [XmlElement(...)] für die Properties etc., hoff ihr wisst was ich meine), kann ich in AlleTiere nicht List<ITiere> als Property verwenden, da flieg ich auf die Nase, das bringt nen Fehler dass Interfaces nicht serialisiert werden können. Ich kann aber eine Basisklasse Tier einfügen und dann List<Tier> machen, und das serialisiert dann.
Meine Frage: Wenn ich nun so einen oder einen vergleichbaren Fall hab, ist es dann nicht überflüssig noch ein Interface ITier zu implementieren, ich muss ja eh mit der Klasse Tier arbeiten und von dort die einzelnen Tiere ableiten...??? Ich mein dass ich es rein funktional nicht bräuchte erklärt sich von selbst, aber ist es ein saubererer Programmierstil es trotzdem zu machen? Die Frage geht wohl etwas in die Richtung was ist besser: Interface oder (abstrakte) Basisklasse (oder beides)?

gruß & thx
sth_Weird

17.09.2008 - 12:59 Uhr

Danke für die Antworten, vor allem kleines_eichhoernchen für den Link zum anderen Beitrag (und darin bzw. auch hier JAck30lena für den Link zu der MSDN Diskussion zu diesem Thema).
Ok die Sache geht also scheinbar nicht so wie ich es gerne hätte, laut MSDN wäre ein Lösung für mich in der Liste statt Interface-Objekte Objekte der Basisklasse zu verwenden, dann würde es gehen (?!).
Nun die anschließende Frage, jetzt nicht nur für diesen Fall sondern allgemein: wenn ich sowieso eine Basisklasse brauche weil ich mit nem Interface was nicht machen kann (z.B. jetzt Operatoren überladen oder einfache Serialisierung), macht es dann überhaupt noch Sinn, ein Interface zu haben, das dann von der Basisklasse implementiert wird, wenn ich das Interface eh so nicht verwenden kann, sondern die Basisklasse brauche? Hab ich irgendwelche Vor-/Nachteile dadurch, ob ich jetzt ein Objekt nach Interface IMeineKlasse caste oder nach Klasse MeineBasisklasse, bzw. ob ich eine Liste<IMeineKlasse> oder eine Liste<MeineBasisklasse> verwende?

thx
sth_Weird

16.09.2008 - 17:19 Uhr

Ich weiß der Titel ist nicht aussagekräftig aber das ganze ist etwas kompliziert.
Ich probiers mal kurz, wenns niemand versteht dann kann ich ja immer noch ins Detail gehen...
Habe eine Basisklasse und einige abgeleitete Klassen. Sie beinhalten in meiner Anwendung Informationen für Datenfilter, genauer gesagt den Filterwert.
Die Basisklasse steht für irgendeinen Filterwert, die abgeleiteten Klassen für Filterwerte vom Typ Bool, Int, String etc.
Um einfacher vergleichen zu können überlade ich in den abgeleiteten Klassen die Operatoren groesser, kleiner, gleich etc. für den jeweiligen Typ für den die abgeleitete Klasse stehen soll, also Bool, Int oder String. So sollte ich ja schreiben können: meinZahlenWert == 12345 oder meinStringWert == "hallo", wenn meinZahlenWert ein Int-Filterwert und meinStrinWert ein String-Filterwert wären.
Nun das Problem, das ganze Filterzeugs ist in einer Dll, die verwende ich in meiner Anwendung (exe), dort habe ich eine Liste mit Filtern. Wenn ich nun aber schreibe
meinFilter.Filterwert == 12345 oder meinFilter.Filterwert = "xyz" dann meckert der Combiler und sagt, für die Basisklasse ist der Vergleich Basisklasse mit Int / String definiert. Logisch, gibt es ja nur in den abgeleiteten Klassen. Wenn ich aber nun explizit abfrage was für einen Typ Filterwert hat, dann muss ich die Anwendung immer nachziehen wenn in der anderen Dll ein neuer Filtertyp dazukommt. Oder ich implementiere die (überschreibbare) Operatorüberladung für jeden Typ bereits in der Basisklasse. Dann muss ich aber für jede neue Klasse die Basisklasse anpacken, sie weiß sozusagen von den abgeleiteten Klassen, was ja auch wieder nicht im Sinne der Objektorientierung ist...
Gibt es eine Möglichkeit in der Basisklasse eine Operatorüberladung für einen generellen Typ zu definieren? Mit object scheints nicht zu gehen...
Oder was wäre in diesem Fall eine "schöne" und "saubere" Lösung???

thx
sth_Weird

16.09.2008 - 16:57 Uhr

Tipp:
Erstell doch einfach mal per Code ein Objekt von A und serialisier es, dann siehste wie's rauskommt, daraus kann man oft ableiten warum's nicht geht (also so geht's mir meistens).
Ich find das Serialisieren übrigens viel schicker und praktischer als über das hier oft geratene Xml-Document zu gehen...

20.08.2008 - 11:37 Uhr

Also zum Zusammenklicken einer statischen "0815" GUI benutz ich fast immer den Designer in Visual Studio. Den find ich auch klasse!
Klar kann ich mir das ganze Gedöns mit der Größe und Ausrichtung und Farbe und Bla auch manuell zusammenschreiben. Und für einen Anfänger sinnvoll, das wirklich mal zu machen, damit er überhaupt weiß, wie das geht, ist es allemal.
Aber ich wüsste nicht weshalb ich mir unnötige Tipparbeit machen sollte, wenn mir der Designer das abnimmt (klar hat der seine Macken, aber die lernt man kennen und mit umzugehen). Nur weil man was auch ohne kann, heißt es ja nicht dass ich keine Hilfsmittel verwenden darf. Bei manchen hier hat man den Eindruck dass es ihre Würde verletzt, einen Designer zu nutzen...also das find übertrieben (is ja wie eine Homepage rein mit Notepad zu schreiben...beeindruckend wenn man's kann, bemitleidenswert wenn man's macht).
Es gibt wirklich gute und schlechte (das ganze Database Zeugs, wie schon erwähnt) Designer. Man muss selbst herausfinden, welche einem helfen und welche eher behindern.

sth_Weird

29.07.2008 - 13:56 Uhr

Danke für die Antwort!
Die Beschreibung des List-Konstruktors hörte sich bei msn so an, als würde es eine neue Liste generieren mit Kopien der Objekte. 😕 Oder ist es nur eine neue Liste aber die Einträge verweisen aufs gleiche? Doof.
Der Code den du geschrieben hast geht bei mir nicht, ich nehm deshalb an das liegt daran dass ich noch mit .NET 2 arbeite (hätt ich vielleicht dazuschreiben sollen)?
In meinem Fall müsste ich dann wohl ne nette for-Schleife bauen, oder?

sth_Weird

29.07.2008 - 13:27 Uhr

Bin grad vollkommen verwirrt.
sowas hab ich (vereinfacht):


public class A : IClonable
{
   string bla;
   List<B> listOfBs;
   // ...

   public string Bla
   {
       get
       {
          return bla;
       }
       set
       {
          bla = value;
       }
   };

   public List<B> ListOfBs
   {
       get
       {
          return listOfBs;
       }
       set
       {
          listOfBs = value;
       }
   };

   public object Clone()
   {
      A cloneOfA = this.MemberwiseClone() as A;
      cloneOfA.listOfBs = new List<B>(listOfBs);

      return cloneOfA;
   }
}

public class B : IClonable
{
   string blub;
   
   // ...

   public string Blub
   {
       get
       {
          return blub;
       }
       set
       {
          blub = value;
       }
   };

   public object Clone()
   {
      B cloneOfB = this.MemberwiseClone() as B;
   
      return cloneOfB;
   }
}

// IN EINER ANDEREN KLASSE

public void machWas(A instanzVonA)
{
    A geklonteInstanzVonA = A.Clone() as A;

     geklonteInstanzVonA.ListOfBs[0].Blub = "das ist ein Test";
}


Ich hätte vermutet dass ich unten in der machWas-Funktion NUR das "Blub" innerhalb der Liste aus geklonteInstanzA ändere, aber seltsamerweise ändert sich auch das "Blub" von instanzVonA mit. Ich dachte durch den Klon-Konstrukt hätte ich wirklich eine tiefe Kopier erreicht, oder doch nicht?
Was mach ich hier nur falsch???

thx
sth_Weird

10.07.2008 - 15:14 Uhr

habe mal ne prinzipielle Frage zum Casten von komplexen/primitiven Datentypen.

wenn ich ein einen string habe der eine Zahl enthält, kann ich den ja prinzipiell auf vier Arten in einen Int umwandeln...

1.) ich schreib einfach
int zahl = (int) MeineZahlAlsString
2.) mit Convert
int zahl = Convert.ToInt32(MeineZahlAlsString);
3.) parsen geht natürlich auch
int zahl = Int.Parse(MeineZahlAlsString);
4.) und zu guter letzt (ich gestehe das hab ich bisher nur bei komplexen Datentypen ausprobiert)
int zahl = MeineZahlAlsString as int;

mich würde mal interessieren was hier die Unterschiede sind bzgl. Laufzeit, Fehlern, "Stil".
Vor allem wenn man keine primitiven Datentypen hat sondern komplexere, eigene Typen, dann gehen ja (es sei denn man schreibt sich selbst was) nur sowohl das "(<typ>)objekt" als auch "objekt as <typ>". Ist da eins davon besser, sicherer, "schöner", oder kann man das damit halten wie man grad lustig ist?

thx
sth_Weird

03.07.2008 - 08:10 Uhr

Oops, wer lesen kann ist klar im Vorteil 😉
ich habe bei mir keine ListView sondern eine CheckedListBox...sorry für die Verwirrung!
Wie herbivore schon geschrieben hat, am besten mal das Projekt durchgucken, und die Einstellungen der alten/neuen ListView im Designer vergleichen.

sth_Weird

02.07.2008 - 12:50 Uhr

Hab das Event angebunden und setze die Image-Spalte darin auf mein Image.
Jetzt ändert sich das Image der NewRow vom X zu meinem Image, sobald ich die NewRow zum ersten Mal fokusiere (also auf irgendeine Spalte klicke). Und das Image bleibt dann auch so. Die dann wieder neu eingefügte NewRow hat dann zwar auch wieder das X-Image (das Event kommt anscheinend erst wenn man die NewRow wirklich selektiert), was unschön ist, aber für die Not kann ich damit leben.

gruß & danke!
sth_Weird

02.07.2008 - 11:53 Uhr

ich glaube damit hatte ich auch mal Probleme (schon recht lange her)...bei mir im Code habe ich nämlich folgende Lösung verwendet, was sicher nicht intuitiv war, da das Checked ja wirklich am naheliegendsten wäre hier:

(CLB = die CheckedListBox)


for (int i = 0; i < CLB.Items.Count; i++)
{
    if (CLB.GetItemChecked(i))
    {
        // Item ist angeklickt!
    }
})

gruß
sth_Weird

02.07.2008 - 11:24 Uhr

Entwicklungsumgebund: .NET 2.0, Visual Studio 2005
Mal wieder ein DataGridView Problem...
Die DataGridView ist nicht gebunden!!! Die Werte trage ich selber ein
Also, mein DataGridView hat u.a. eine DataGridViewImageCell. Das Image setze ich mit


ColDeleteRow.Image = imageList1.Images[(int)ImgListIndex.Cancel];

Problem nun: Beim init des das DataGridView enthaltenden Dialogs füge ich ein paar Zeilen ein mit


MyDataGrid.Rows.Add();
// hier setze ich dann Werte für die einzelnen Spalten, aber [U]nicht[/U] für ColDeleteRow (sollte also noch auf dem "Defaultwert" stehen für neue Zeilen)!

Bei der Anzeige ist dann in allen Rows mein Image in der ImageSpalte angezeigt, so wie ich's haben will.
Aber in der "NewRow" Zeile ist das X-Image (also das das man immer angezeigt bekommt wenn ein Bild nicht gefunden wird). Das geht auch nicht weg wenn ich die neue Zeile angelegt habe und wieder zur nächsten Zeile gehe.
Ich hätte aber gern dass immer mein Image angezeigt wird.
Ich habe es schon versucht mit


ColDeleteRow.InheritedStyle.NullValue = imageList1.Images[(int)ImgListIndex.Cancel];
      ColDeleteRow.InheritedStyle.DataSourceNullValue = imageList1.Images[(int)ImgListIndex.Cancel];
      ColDeleteRow.DefaultCellStyle.NullValue = imageList1.Images[(int)ImgListIndex.Cancel];
      ColDeleteRow.DefaultCellStyle.DataSourceNullValue = imageList1.Images[(int)ImgListIndex.Cancel];

dachte damit setze ich den Defaultwert auf jeden Fall auf mein Image. Aber hat nichts gebracht, immer noch das X...
Ich frage mich was der Unterschied ist ob ich jetzt mit Rows.Add eine Spalte hinzufüge und das Image richtig ist, oder wenn ich manuell im Dialog in die neue Spalte gehe???
Nu ja jedenfalls bin ich auf der Suche nach einer einfachen Lösung wie ich das X-Image weg bekomm...

gruß & danke
sth_Weird

02.07.2008 - 10:58 Uhr

Ich mache es so:

Also die Columns adde ich direkt über den Dialog, dort stelle ich auch den SortMode und die Sorted-Eigenschaft ein.
die Comboboxen fülle ich mit (beispielhaft)


ColCombo1.DataSouce = myDataObjects.ToArray();

wobei ColCombo1 eine DataGridViewComboBoxCell ist und myDataObjects eine List<MeineKlasse>.
Das ist alles.
Ich hab's jetzt aber selbst hinbekommen, wobei ich überhaupt nicht nachvollziehen kann, wie es zu dem Phänomen kommt (aber ich hatte schonmal so ein ähnliches, bei dem mir mein ColumnHeader-Style immer wieder verloren ging):
Also wie gesagt stelle ich SortMode und Sorted im Dialog auf NotSortable und false, aber aus irgendwelchen Gründen scheint sich das von alleine wieder umzustellen (ich habe keine Stelle im Designer (da steht's richtig, so wie ich's eingestellt habe) oder sonstwo im Code gefunden, wo das wieder umgestellt wird), denn beim Debuggen standen die Werte auf was anderem (es hat auch nichts gebracht das Projekt komplett zu cleanen oder Visual Studio/den Rechner neu zu starten) .
Stelle ich die Werte aber in der Funktion, in der ich die Comboboxen fülle, nochmal explizit auf NotSortable und false, abra-cadabra es geht!
Nu ja, man muss nicht alles verstehen, hauptsache jetzt geht's 🙂

gruß & danke für die Antworten
sth_Weird

01.07.2008 - 17:01 Uhr

Entwicklungsumgebung: .NET 2.0, Visual Studio 2005

Ich habe einen Dialog mit DataGridView, die DataGridView hat zwei DataGridViewComboBoxCells. DataSource der ComboBoxen sind jeweils Listen mit Objekten, DisplayMember ist jeweils ein String-Property des Objekts, ValueMember ist das Objekt selbst (hab ich durch ein "Itself"-Property in der Klasse, das für den getter "this" zurückgibt, gelöst). Das hab ich übrigends schonmal so gemacht und da hat's funktioniert, aber den Quellcode finde ich leider nicht mehr, also daran, wie ich die DataGridViews fülle (also mit einer Objekt-Liste), kann es nicht liegen.
Das DataGridView ist anfänglich leer. Wenn ich nun per Programm eine neue Zeile hinzufüge -> Rows.Add(), kommt eine Exception

{"Eine ComboBox mit festgelegter DataSource kann nicht sortiert werden. Sortieren Sie die Daten mit dem zugrunde liegenden Datenmodell."}

Dabei habe ich bei beiden Spalten extra eingestellt, dass sie NICHT sortierbar sind (SortMode auf NotSortable, und Sorted auf false, das habe ich jetzt x-mal schon nachgeprüft und ist so! Und es gibt definitiv nur diese beiden ComboBox-Spalten, keine anderen).
Warum kommt dann trotzdem die Exception, fehlt noch was? Oder ist der Text irreführend und kann eine ganz andere Urache haben als das Sorting???

gruß & thx
sth_Weird

02.06.2008 - 13:45 Uhr

Ich hab's:
(vielleicht hätt ich den ganzen Code posten sollen, dann wär vielleicht jemand eher draufgekommen):
Die Filter-Spalte wird von einer Funktion manipuliert, die die Filterbedingungen prüft, und dann wird die Spalte im DataGridView gesetzt:
MessageGrid.Rows_.Cells[COL_NAME_FILTER].Value = isFilterValid;
AABER den FilterString wende ich ja auf die Tabelle!!! an, die als DataSource des MessageGrid gesetzt ist. Die scheint zum Zeitpunkt, an dem ich den FilterString setze, noch nicht ganz abgeglichen mit dem DataGridView zu sein.
Wenn ich jetzt mache messageTable.AcceptChanges bevor ich den Filter setze, dann funktionierts. Muss wohl ein Timing-Problem sein (?), denn der Großteil der Rows wurde ja richtig gefiltert...

sth_Weird

02.06.2008 - 13:00 Uhr

weitere Infos:
Die Selection geht mit ClearSelection doch weg, und es ist jetzt auch kein Datensatz mehr aktiviert. Trotzdem steht die eine Zeile noch da 😦
Beim Debuggen rausgefunden:
Vor setzen des Filters hab ich mit ClearSelection die Selection gecleared, CurrentRow ist jetzt auch null, SelectedRows hat die Länge null.
Dann kommt das Setzen des Filters, und eine Codezeile später gibt es wieder eine SelectedRow und eine CurrentCell, nämlich eben die falsche.
Bin ich denn wirklich die einzige mit diesem Problem???

sth_Weird

02.06.2008 - 11:11 Uhr

ich bin mir absolut sicher dass der FilterString korrekt ist, siehe auch meinen Codeausschnitt oben "Filter = true" (die Spalte Filter ist eine Checkbox-Spalte)...da kann man glaub ich auch nicht viel falsch machen.
Und die Filterspalte zeige ich an, nach dem Filter stehen alle Zeilen die angezeigt werden auf true außer der falschen Zeile. Wenn ich den Filter dann entferne, also wieder alle Zeilen angezeigt werden, kann ich auch genau überprüfen, dass nur die Zeilen die Filter-Spalte auf true stehen haben, die ich berechtigterweise beim Filtern angezeigt bekommen hab. Mit Ausnahme eben der einen falsch angezeigten Zeile, die steht immer noch auf false, so wie all die anderen Zeilen, die aber beim beim Filtern korrekterweise ausgeblendet wurden).
Die Funktion Repaint hab ich für das DataGridView nicht gefunden, ein Aufruf der Funktionen Refresh oder Update nach Setzen des Filters hat nichts gebracht, die falsche Zeile ist immer noch da.
Ich hatte jetzt zwischenzeitlich auch mal das Phänomen dass zwei falsche Zeilen stehenblieben (wenn ich dann den Fokus auf die andere gewechselt hab verschwand aber die zuerst fokussierte).
So ein Mist...
Woran kann es denn sonst noch liegen? Bzw. wie bekomme ich denn die blöde Zeilenselektion im DataGridView weg, wenn ClearSelection nicht will? die ganzen SelectedIndices/etc. Properties sind ReadOnly 😦

sth_Weird

02.06.2008 - 10:05 Uhr

hi,

ich habe ein seltsames Problem mit meinem DataGridView.
Und zwar habe ich ein DataGridView (MessageGrid), dessen DataSource eine DataTable () ist (wird per Code erstellt und gefüllt).
Die DataSource ist genau:

MessageGrid.DataSource = messageTable.DefaultView;

nun möchte ich die Daten filtern, da der Filter recht komplex ist und nicht einfach über die Werte der Spalten geht, hat meine Tabelle eine extra Spalte "Filter", die mir eine Funktion auf true oder false stellt, je nachdem ob eine Zeile den Filterbedingungen genügt. Der Filterstring ist somit einfach

string filterString = "Filter = true";

Diesen weise ich der Tabelle zu:

messageTable.DefaultView.RowFilter = filterString;

Hier habe ich ein seltsames Phänomen: Es bleibt manchmal eine Zeile stehen, die garnicht zum Filter passt (zu Testzwecken habe ich die Filter-Spalte mal sichtbar gemacht, und sie ist nicht gesetzt).
Wenn ich also genau weiß dass kein Datensatz zum Filter passt, bleibt trotzdem eine Zeile stehen und die geht nicht weg. Aber wenn mehrere Zeilen stehenbleiben dann ist der Fokus auf der falschen Zeile, wenn ich nun in eine richtige Zeile wechsle wird die falsche plötzlich ausgeblendet. 😕
Meine Vermutung war nun, dass die eine Zeile nicht weg geht, weil sie den Fokus hatte, deshalb hab ich vor Setzen des Filters versucht:

MessageGrid.ClearSelection();

ich dachte damit kann ich sämtliche Selektionen entfernen.
Aber hat nichts gebracht, die falsche Zeile steht immer noch dabei.
Wie bekomme ich das Phänomen weg???

thx
sth_Weird

25.03.2008 - 11:52 Uhr

Hmm das mit dem Löschen erzwingen ist vielleicht doch nicht das wahre...
"Letzter Ausweg":
Ich verzichte darauf, das Fenster des Prozesses nicht anzuzeigen, dann ist alles perfekt mit dem Aufruf von CloseMainWindow().
Unabhängig vom im StartInfo eingestellten WindowStyle poppt der Prozess leider nach dem Start immer in den Vordergrund (das WindowStyle wird einfach ignoriert, ich kann das Fenster nicht minimiert haben).
Kann ich denn nun das Fenster irgendwie nachträglich minimieren, nachdem der Prozess gestartet wurde, oder bin ich da wieder beim gleichen Problem angelangt, das ich vorher hatte?

EDIT:
Hmm jetzt habe ich in der Windows-Api diese Funktion gefunden: ShowWindow und rufe die nachdem ich den Prozess (der in normaler Größe im Vordergrund aufpoppt) so auf:
ShowWindow(tSharkProcess.MainWindowHandle.ToInt32(), SW_SHOWMINIMIZED);
Wird leider genauso ignoriert wie das WindowStyle im StartInfo, das Fenster bleibt unbeeindruckt im Vordergrund und groß...
Bin ich denn einfach nur zu blöd dazu oder geht das was ich will nicht? Ersteres wär mir ja lieber dann hätte ich noch Hoffnung dass mir jemand sagt wie's richtig geht

25.03.2008 - 09:28 Uhr

mit MainWindowHandle bekomme ich einen IntPtr...wie schließe ich den Prozess damit?
An dieser Stelle evtl. noch wichtig (?): als unsichtbare Consolenanwendung gestartet.

Ok jetzt bin ich etwas weiter...
Laut msdn ist die einzige Möglichkeit einen Consolen-Prozess per Programm zu beenden wirklich die Kill-Funktion aufzurufen 😕
Alternativ hätte ich gefunden die win-Funktion GenerateConsoleCtrlEvent. So könnte man Ctrl+C schicken, aaaaber da gibt's auch wieder ein Problem: das funtioniert nur für die Prozesse die dieselbe Console verwenden wie der Prozess der die Funktion aufruft (was ja nun wieder nicht so ist). 😕
*kreisch* ist es denn wirklich so, dass es für dieses (mir einfach zu erscheinendes, und wie ich beim googlen rausgefunden hab auch nicht gerade exotisches) Problem keine Lösung gibt und ich mit meinen gesperrten Dateien leben muss (kann ich vielleicht die Dateien künstlich entsperren bzw. das Löschen erzwingen, auch wenn noch ein Handle drauf ist)?

25.03.2008 - 08:49 Uhr

Unlösbares Problem???

Ich starte in meinem C# Programm einen neuen Prozess, und zwar das Programm "tShark" (Sniffer-Engine von Wireshark).
tShark zeichnet dann fleißig den Netzwerktraffic auf und speichert ihn in eine Datei (so habe ich ihn per Kommandozeilenparameter parametriert).
Nun möchte ich den Prozess aber irgendwann mal manuell beenden, per Button-Click.
Nun das Problem:
wenn ich den Prozess mit
tSharkProcess.Close()
versuche zu beenden, ist der Prozess zwar anscheinend beendet, aber tShark läuft aus irgendwelchen Gründen trotzdem noch und zeichnet munter weiter auf (die Aufzeichnungsdatei ist auch gesperrt, ich kann sie nicht löschen oder umbenennen).
mache ich
tSharkProcess.Kill()
wunderbar, tShark ist auch beendet, aber auch hier ist das Dateihandle nicht freigegeben (es bringt hier auch nichts das ganze Programm zu beenden, die Datei wird erst bei einem Reboot des Rechners wieder freigegeben) 😕

Ideen???

Danke!
sth_Weird

20.03.2008 - 13:52 Uhr

Uuaah nö ne extra Wrapper-Klasse bauen dazu hab ich keine Lust. Ich dachte man könnte sich vielleicht irgendwie das GUI-Handle merken und dann die Methode darüber aufrufen.
Aber dann mach ich's halt doch über Invoke 😕

Danke!

Gruß
sth_weird

20.03.2008 - 13:43 Uhr

In meiner Gui erstelle ich ein externes Programm als Process.
Der Process kann auf zwei Arten beendet werden: entweder ich breche ihn ab (Klicken eines Buttons), oder er terminiert automatisch. Der erste fall funktioniert einwandfrei. Für den zweiten Fall habe ich mich an das Exited-Event des Process gehängt, und das wird auch brav aufgerufen.
So, jetzt das Problem: Die Funktion, die ich vom Abbruch-Button aufrufe bzw. die im Exited-Eventhandler aufgerufen wird, macht was mit der Gui. Beim Exited-Event fliegt das Programm jetzt mit der Exception raus, dass es ein anderer Thread ist.
Ich könnte jetzt natürlich ein Invoke ausenrumbasteln aber ich suche immer noch nach etwas "schöneren" bzw. einfacheren Lösungen... Kann ich mir denn nicht irgendwo den Gui-Thread merken und dann sagen: rufe mir die Funktion für den Gui-Thread auf?

thx
sth_Weird

08.02.2008 - 08:02 Uhr

Die Zeilen sind aber alle unterschiedlich hoch, da der Inhalt der Zellen mehrzeilig ist...

07.02.2008 - 16:43 Uhr

Es ist zwar nicht ganz dasselbe aber es passt irgendwie dazu...

Gibt es statt der FirstDisplayedCell" auch sowas wie eine "LastDisplayedCell", oder auch "ScrollCellToView(int cellNumber)"?
Mein Problem ist nämlich, dass ich automatisch scrollen will, aber ich will meine "aktuelle" Zelle nicht an oberster Stelle haben, sondern ich will soweit runter scrollen, dass ich sie gerade noch sehe (damit ich möglichst viel von dem sehen kann, was in der vorherigen Zeilen steht). Als Hintergrundinfo: Jede Zeile steht für eine im Hintergrund ausgeführte Aufgabe die Fortschritt und Ergebnis/Fehler an die Tabelle liefert, wenn ich nun immer wenn eine neue Aufgabe anfängt diese als erste Zelle setze, dann habe ich vor dem Bildschirm das was vorher als Ergebnis kam vielleicht noch garnicht fertig gelesen...

Gruß & Danke
sth_Weird

07.02.2008 - 13:14 Uhr

Entwicklungsumgebung: C# .NET 2.0 Visual Studio 2005

Ich versuche mit C# eine Datei zu transformieren, und zwar mit der Klasse XslCompiledTransform. Ich lade die xsl-Datei und rufe dann transform auf mit dem Namen der Eingabedatei und dem Namen der Ausgabedatei.
Soweit so gut, es geht.
Aber in der Xsl-Datei habe ich durch xsl:message an verschiedenen Stellen Ausgaben gemacht, die bei Verwendung von Saxon, Xalan etc. beim Aufruf über die Kommandozeile in der Console ausgegeben werden.
Gibt es eine Möglichkeit, auch von C# aus auf diese Ausgaben zuzugreifen?

thx
sth_Weird

03.12.2007 - 11:28 Uhr

Hallo!

Auf diesen Artikel bin ich beim Googeln nicht gestolpert.
Funktioniert aber prima und ich konnte die Klassen wirklich fast 1:1 für meinen Fall übernehmen (hat mich gerademal ne halbe Stunde Arbeit gekostet).

Danke!

Gruß
sth_Weird

29.11.2007 - 08:25 Uhr

hallo,

Das Problem was ich habe ähnelt etwas diesem Beitrag
PropertyGrid - CollectionEditorDialog anpassen
bei welchem das Editor-Fenster im PropertyGrid aufgeht, wenn man auf eine Collection klickt.
Mit der Ausnahme, dass ich dieses Editor-Fenster überhaupt nicht haben möchte.
Ich habe eine Liste<MeinTyp>, MeinTyp hat zwei einfache Eigenschaften (strings), nennen wir sie mal A und B.
Wenn ich im PropertyGrid SelectedObject = meineListe einstelle, kriege ich natürlich einen Eintrag mit ... der beim Klicken den Extra-Editor öffnet.
Ich würde aber gerne statt des Extra Editors die Daten lieber in der gleichen Ansicht aufmachen. Am betsen wäre es, wenn der Wert der Eigenschaft A links als Text stehen würde und der Wert der Eigenschaft B rechts als editierbarer Wert.
Aber mir würde schon reichen wenn ich einfach alle A-B-Paare untereinander angezeigt bekommen würde, anstatt dass sich der Editor öffnet.
Ich denke das könnte mit einem eigenen TypeConverter gehen?
Aber ich habe keine Ahnung davon, und die Beispiele die ich gefunden habe beschäftigten sich mit ganz anderen Problemen, Beschränken der Eingabemöglichkeiten und so.
Hat also jemand ne Idee (ich erwarte auch keine Komplett-Lösung, mir reicht ein Ansatz), wie ich das am geschicktesten hinbekommen könnte, ohne zu großen Aufwand (ich hab an das PropertyGrid gedacht weil es halt so einfach ist, wenn es aber zu komplex ist da mit dem TypeConverter was anzupassen dann kann ich mir auch gleich ein eigenes Control schreiben)?

gruß & thx
sth_Weird

16.11.2007 - 14:34 Uhr

Hätt mal ne Frage zum FTP-Zugriff...
Ich habe mir einen "FTP-Manager" geschrieben, der über die IP-Adresse auf einen FTP-Server in einem Gerät zugreift. Das Auslesen der Dateiliste, der Upload und Download von Dateien funktioniert schon alles. Was ich jetzt noch bräuchte ist eine Funktion, die mir sagt, wieviel Speicherplatz noch frei ist. Gibt es sowas und wenn ja wie geht das?

gruß & thx
sth_Weird

31.10.2007 - 12:46 Uhr

tach!

Ich habe in meiner Anwendung eine Progressbar, der Anzeigetyp ist Blockanzeige.
Gibt es eine möglichkeit abhängig vom Max-Wert herauszufinden, nach welchem Counter-Interval ein Block dazukommt (wenn ich z.B. Max = 1000 habe und die ProgressBar x breit ist, wieviele Blöcke gibt es dann insgesamt, wenn Value = 1000 erreicht hat?).
Zusatzfrage: Wenn ich PerformStep() aufrufe, aber kein Block dazukommt, wirkt sich das dann trotzdem gleichermaßen auf die Performance aus (es muss ja nichts neu gezeichnet werden)?

gruß & thx
sth_Weird

29.10.2007 - 15:03 Uhr

kann ich aus der fehlenden antwort schließen, dass ich den eintrag doch über meine schleife suchen muss?

29.10.2007 - 10:49 Uhr

vielleicht ganz einfach, aber ich krieg's nicht hin..
in spalte0 meines datagridviews (datasource ist ein dataview) steht eine id. wie kann ich am besten erreichen, dass eine zeile mit einer bestimmten id selektiert wird? Sozusagen bräuchte ich ein
datagridview.Rows[(spalte0.Value == 12345)].Select().
das einzige was mir im moment dazu einfällt ist alle zeilen durchzugehen und gucken wo der wert halt steht. ist aber maximal langsam.
geht's nicht auch anders und besser?

thx
sth_Weird

25.10.2007 - 15:31 Uhr

du meinst doch jetzt diese art von invoke, oder?



if (MyDataGrid.InvokeRequired)
{
    MyDataGrid.Invoke(new MyDataGridChangedDelegate(funktion));
}
else
{
    MyDataGrid.Refresh();
}

so hatte ich es, und es hat trotzdem blockiert...

andere Frage: ist es "stilvoll", in die Bearbeitungsfunktion des Thread einfach Thread.Sleep(0) einzubauen, so dass er wartet, bis die anderen Threads fertig sind? Damit scheint es nämlich auch zu gehen...
EDIT: nee da blockiert's letztendlich auch hin und wieder...so richtig verlässlich schein wirklich nur das peekmessage zu sein...

gruß
sth_Weird

24.10.2007 - 11:44 Uhr

ich hatte es doch komplett auf Threads umgebaut und dann mit Control.Invoke gearbeitet...aber gebracht hat es nichts.

24.10.2007 - 07:40 Uhr

ok, da alles nicht half, verwende ich jetzt die PeekMessage-Funktion aus der User32.dll um festzustellen, ob noch Messages anliegen...und falls ja, warte ich bis die abgearbeitet sind und mache dann erst weiter mit meiner filter-funktion...so funktioniert's, wenn's auch nicht gerade die schönste und schnellste lösung ist...

gruß
sth_Weird

23.10.2007 - 14:42 Uhr

ich habe das ganze jetzt auf Threads umgebaut, aber das Phänomen ist geblieben...der erste Thread blockiert die GUI nicht, der zweite Thread blockiert die GUI und auch hier: wenn ich in meine schleife in der zweiten Thread-Funktion ein Console.Writeline(...) einbaue, dann blockiert Thread 2 die GUI auch nicht mehr.
Laut Ausgabe beim Ende des Debuggens waren bei der Ausführung insgesamt vier Threads aktiv (teilweise nur zeitweise)

23.10.2007 - 09:37 Uhr

hallo

jep, scheint echt so zu sein...
hab in mein DoWork einfach noch ein Console.Writeline in die Schleife eingebaut und siehe da: es blockiert nichts mehr. Natürlich ist die Schleife jetzt aber SEHR langsam...kann man irgendwie rausfinden, ob dieser Queue schon "gefährlich voll" ist, und abhängig davon etwas warten, bis man das Event feuert?

gruß & danke
sth_Weird

23.10.2007 - 08:54 Uhr

Wie ist dieser gegenseitige Ausschluss realisiert?

der Menupunkt zum Filtern (2.BackgroundWorker) wird erst freigeschaltet, wenn der erste BackgroundWorker das Finished-Event erzeugt hat...umgekehrt kann ich nur neue Daten übers Menu laden, wenn der 2.BackgroundWorker das Finished-Event erzeugt hat.
Haggy's anregung mit dem häufigen feuern hört sich interessant an...denn ich habe mal probiert, einfach in derselben schleife was auf der Console auszugeben (sinnvollerweise greife ich dabei auf dieselbe liste zu in der ich normal sortiere, damit ich ausschließen kann, dass das blockieren durch einen ungültigen zugriff auf daten ausgelöst wird). die gui blockiert hier nicht. die events werden aber auch in viel großerem abstand gefeuert wie normal.
kann es also daran liegen, dass der gui-block daher kommt, dass das processchanged-event in zu kleinen abständen gefeuert wird?

23.10.2007 - 08:24 Uhr

beide BackgroundWorker werden im Gui-Thread erzeugt und von dort aus gestartet. Ich habe auch mal testweise an der Stelle, wo ich normalerweise den Gui-blockierenden BackgroundWorker2 starte, stattdessen BackgroundWorker1 gestartet. Die Gui wurde nicht blockiert.
Die beiden BackgroundWorker schließen sich gegenseitig aus, d.h. entweder der eine ist aktiv oder der andere. Sie arbeiten nie beide.
Wie kann ich erkennen, in welchem Thread was läuft?

23.10.2007 - 07:50 Uhr

Ich konnte die Fehlerquelle genauer lokalisieren:
wenn ich in der DoWork Funktion des zweiten BackgroundWorkers das


BGWorkerFilterData.ReportProgress(i, show);

entferne, dann wird die Gui nicht blockiert.
Sie wird blockiert, sobald die Funktion drin ist, auch wenn ich die ProgressChanged-Funktion leer lasse...
???

22.10.2007 - 15:20 Uhr

hmm vielleicht fehlt in meiner beschreibung was...
vielleicht hilft das weiter (die klasse ist ziemlich umfangreich, ich hab deshalb versucht das ganze unnütze/irrelevante zeugs rauszuwerfen bzw. nur durch kommentar darzustellen)?



  /// <summary>
  /// Anzeige der Packete
  /// </summary>
  public partial class PacketViewer : UserControl
  {
   
    #region Deklaration

    // in dieser Liste stehen die Daten die von beiden BackgroundWorkern 
    // bei DoWork benutzt werden
    private MessageList messageList = new MessageList ();

    private FilterDialog filterDlg;

    #endregion Deklaration

    #region Konstruktor

    /// <summary>
    /// Konstruktor
    /// </summary>
    public PacketViewer ()
    {
    }

    #endregion Konstruktor

    #region Funktionen

    #region Datei laden 

    /// <summary>
    /// Datei laden
    /// </summary>
    /// <param name="filePath">
    /// Dateipfad
    /// </param>
    /// <returns>
    /// Rueckmeldung ob Laden erfolgreich
    /// </returns>
    private bool LoadFile (string filePath)
    {
      bool loadSucceeded = false;
      
      // hier wird Datei geladen und Daten in der messageList gespeichert
      
      // DataGridView aufbauen
      FillDataGridView ();

      return loadSucceeded;
    }


    #region DataGridView fuellen

    /// <summary>
    /// DataGridView aufbauen
    /// </summary>
    private void FillDataGridView ()
    {
      // erster BackgroundWorker (funktioniert ohne die GUI zu blockieren)
      BGWorkerFillData.RunWorkerAsync ();
    }

    #endregion DataGridView fuellen

    #endregion Funktionen

    #region User-Interaktion

    #region Menu

    /// <summary>
    /// Menu Filter
    /// </summary>
    private void MainMenuViewFilter_Click (object sender, EventArgs e)
    {
      if (filterDlg.ShowDialog () == DialogResult.OK)
      {
        MainMenuViewFilter.Checked = true;

        // hier werden Filter-Infos werden in ein Filter Dictionary gespeichert
      }
      else
      {
        MainMenuViewFilter.Checked = false;
      }
      // Wenn Filter ein dann BackgroundWorker 2 (der der blockiert) starten
      if (MainMenuViewFilter.Checked)
      {
        StartFilterBGWorker ();
      }
    }

    /// <summary>
    /// BackgroundWorker 2 starten
    /// </summary>
    private void StartFilterBGWorker ()
    {
      // hier wird zweiter BackgroundWorker gestartet (blockiert GUI)
      BGWorkerFilterData.RunWorkerAsync ();
    }

    #endregion Menu

    #endregion User-Interaktion

    #region Background Worker

    #region BGWorkerFillData

    /// <summary>
    /// BackgroundWorker 1 in Aktion (blockiert nicht)
    /// </summary>
    /// <param name="sender">
    /// object
    /// </param>
    /// <param name="e">
    /// EventArgs
    /// </param>
    private void BGWorkerFillData_DoWork (object sender, DoWorkEventArgs e)
    {
      // hier wird die neue Row fuer das datagridview zusammengebastelt
     
      object[] dgRow; 
      for (int i = 0; i < messageList.Count; i++)
      {
        dgRow = new object[5] { /* hier stehen spalteninfos aus der messageList */};
        BGWorkerFillData.ReportProgress (0, dgRow);
      }
    }

    /// <summary>
    /// BackgroundWorker 1 Abschnitt melden
    /// </summary>
    /// <param name="sender">
    /// object
    /// </param>
    /// <param name="e">
    /// ProgressChangedEventArgs
    /// </param>
    private void BGWorkerFillData_ProgressChanged (object sender, ProgressChangedEventArgs e)
    {
      dataGridView1.Rows.Add ( (object[])e.UserState);
      MyProgressBar.PerformStep ();
    }

    /// <summary>
    /// BackgroundWorker 1 ist fertig
    /// </summary>
    /// <param name="sender">
    /// object
    /// </param>
    /// <param name="e">
    /// RunWorkerCompletedEventArgs
    /// </param>
    private void BGWorkerFillData_RunWorkerCompleted (object sender, RunWorkerCompletedEventArgs e)
    {
      ActionProgress.Value = 0;
    }

    #endregion BGWorkerFillData

    #region BGWorkerFilterData

    /// <summary>
    /// BackgroundWorker 2 in Aktion (blockiert)
    /// </summary>
    /// <param name="sender">
    /// object
    /// </param>
    /// <param name="e">
    /// DoWorkEventArgs
    /// </param>
    private void BGWorkerFilterData_DoWork (object sender, DoWorkEventArgs e)
    {
      bool show = false;

      for (int i = 0; i < messageList.Count; i++)
      {
        show = false;

        // hier wird abhaengig von den Filtereinstellungen wird show = true gesetzt)
        
        BGWorkerFilterData.ReportProgress (i, show);

      } // for (int i = 0; i < messageList.Count; i++)      
  
    }

    /// <summary>
    /// BackgroundWorker 2 Abschitt melden
    /// </summary>
    /// <param name="sender">
    /// object
    /// </param>
    /// <param name="e">
    /// EventArgs
    /// </param>
    private void BGWorkerFilterData_ProgressChanged (object sender, ProgressChangedEventArgs e)
    {
      dataGridView1.Rows[e.ProgressPercentage].Visible = Convert.ToBoolean (e.UserState);
      ActionProgress.PerformStep ();
    }

    /// <summary>
    /// BackgroundWorker 2 ist fertig
    /// </summary>
    /// <param name="sender">
    /// object
    /// </param>
    /// <param name="e">
    /// EventArgs
    /// </param>
    private void BGWorkerFilterData_RunWorkerCompleted (object sender, RunWorkerCompletedEventArgs e)
    {
      ActionProgress.Value = 0;
      Console.WriteLine (e.Error.ToString ());
    }

    #endregion BGWorker

    #endregion Background Worker

  }
}


// AUS DER DESIGN-Datei:
// 
      // BGWorkerFillData
      // 
      this.BGWorkerFillData.WorkerReportsProgress = true;
      this.BGWorkerFillData.WorkerSupportsCancellation = true;
      this.BGWorkerFillData.DoWork += new System.ComponentModel.DoWorkEventHandler (this.BGWorkerFillData_DoWork);
      this.BGWorkerFillData.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler (this.BGWorkerFillData_RunWorkerCompleted);
      this.BGWorkerFillData.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler (this.BGWorkerFillData_ProgressChanged);
      // 
      // BGWorkerFilterData
      // 
      this.BGWorkerFilterData.WorkerReportsProgress = true;
      this.BGWorkerFilterData.WorkerSupportsCancellation = true;
      this.BGWorkerFilterData.DoWork += new System.ComponentModel.DoWorkEventHandler (this.BGWorkerFilterData_DoWork);
      this.BGWorkerFilterData.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler (this.BGWorkerFilterData_RunWorkerCompleted);
      this.BGWorkerFilterData.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler (this.BGWorkerFilterData_ProgressChanged);

22.10.2007 - 14:49 Uhr

hallo!
in meiner anwendung werden sehr viele daten geladen und in ein datagridview eingefuegt. damit die gui während des ladens nicht blockiert ist (dauert ggf 2-3 minuten), habe ich das laden in einen backgroundworker (1) verlagert. das funktioniert auch, und während des ladens kann ich die gui vollständig bedienen, und sehe wie sich das datagridview lädt (rows werden im progresschanged-event hinzugefügt).
nun wollte ich die rows filtern, und da es so viele zeilen sind die ich auf bestimmte kriterien prüfen muss, dachte ich, ich mache das in nem neuen backgroundworker.
es wird liste, die dem inhalt des datagridviews entspricht, durchgegangen und für die zeilen die nicht angezeigt werden sollen wird das processchanged-event gefeuert mit der anweisung, diese zeile im datagridview auszublenden.
leider wird während der ausführung dieses backgroundworkers die komplette gui blockiert. im eigenschaftsfenster der beiden backgroundworker sind bis auf den namen die eigenschaften gleich. ich bekomme keine exceptions. nachdem der backgroundworker fertig ist ist die anzeige wieder einwandfrei zugänglich, der filter wurde auf das datagridview angewandt (es hat also alles funktioniert). aber die gui war halt blockiert 😕
ich kann mir nicht denken warum der eine funktioniert und der andere nicht.
ich habe keine DoEvents oder sonstiges irgendwo drin (im in anderen bgw-threads verwiesenen "Warum blockiert meine GUI" thread konnte ich keine anhaltspunkte für das problem finden).
beide backgroundworker starte ich mit StartWorkerAsync, den ersten, nachdem ich eine datei geladen habe, der zweite wird in einer funktion aufgerufen, die ich nach schließen eines filter-formulars aufrufe.
jemand ne idee?

gruß
sth_Weird

22.10.2007 - 10:55 Uhr

hallo

ich habe ein DataGridView in meiner Anwendung, es ist nicht gebunden und wird im stil
datagridview1.Rows.Add(new object[]{1,2,3});
gefüllt.
nun möchte ich die Daten gerne bei Knopfdruck filtern, habe aber keine Funktion dazu gefunden. die Datasource des DataGridViews ist ja null da nicht gebunden, d.h. auf der Schiene komme ich nicht weiter.
Kann ich doch irgendwie filtern, ohne manuell alle Zeilen durchzulaufen und zu gucken ob das was ich suche dabei ist?
Kann man vielleicht was mit der DataGridViewRowCollection anfangen? Daraus irgendwie eine DataTable oder ein DataSet zaubern, da man dann filtern kann?

thx
sth_Weird

ps: Erst ne DataTable erstellen und dann diese als DataSource fuer das DataGrid zu verwenden passt in meiner Anwendung sehr schlecht. Es sollte schon so bleiben wie es ist mit dem Rows.Add(..).

19.10.2007 - 15:38 Uhr

Hallo

@Flo das mit dem DataTable füllen und dann dem DataGridView zuordnen hab ich schon probiert, ist schneller als direkt mit <datagridview>.Rows.Add zu arbeiten, aber dauert bei "normal" großen Datenlisten schon teilweise mehr als 1 Minute. Da drehen meine ungeduldigen User durch, wenn so lange nichts zu sehen ist und - schlimmer noch - die GUI garnicht reagiert...

Ich hab jetzt aber eine Lösung gefunden, mit der denk ich alle leben können...
Die meiste Arbeit zum Füllen des DataGridViews macht ein BackgroundWorker, jede vorbereitete Zeile wird über ein ProcessChanged-Event an den GUI-Thread übergeben und dort nur noch in das DataGridView eingefügt. Das dauert zwar insgesamt etwas länger als es "normal" zu machen, aber man kann dann (mit minimalen "Auszeiten", die man aber kaum merkt) immer auf die GUI zugreifen, d-h. die Datensätze die ich schon seh kann ich auswählen (theoretisch auch bearbeite, im konkreten Fall sind sie aber alle readonly), ich kann das Laden abbrechen etc. 🙂 🙂 🙂 schicke Sache so ein Background Worker, hatte ich bisher noch nichts mit gemacht

Gruß & allen vielen Dank
sth_Weird

19.10.2007 - 12:30 Uhr

sorry, ich habe listview mit listbox verwechselt...listview hat natürlich icons...
hab ich jetzt auch ausprobiert aber da fand ich datagridview doch komfortabler...
deshalb such ich jetzt ne lösung "mit extra thread" für folgendes:

im moment habe ich die funktion (beispielhaft)


Funktion: FillMySelectionList()
{
    //für alle objekte in liste
       // füge zeile zu datagridview hinzu und zähle progressbar eins weiter
}

damit ich, während das passiert, trotzdem noch auf die form zugreifen kann (und vielleicht auch schon was mit den vorhandenen einträgen anfangen), müsste das füllen in einem separaten thread geschehen...wie mach ich das jetzt?
probiert hab ich:


private void BuildTree()
 {
      Thread gbWorkerThread = new Thread(new ThreadStart(BuildTreeThread));
      gbWorkerThread.Start();
 }

private void BuildTreeThread()
 {
      if (InvokeRequired)
      {
        FillTreeThreadDelegate fillTree = new FillTreeThreadDelegate(BuildTreeThread);
        fillTree.Invoke();
      }
      else 
     {
        // fuer alle eintraege in meiner liste
            // fuege neue zeile in datagridview ein und zähle fortschrittsbalken eins weiter
     }
}

mit dieser methode bekomme ich keine fehler, aber die gui ist trotzdem nicht zugänglich, ich kann also während des ladens keine buttons oder menüeinträge betätitgen...fast so als ob der extra-thread garnicht da wäre 😦
wie geht's richtig?
[EDIT]: bei größern datenmengen bekomme ich so beim invoke auch eine stackoverflow-exception 😦

gruß & thx
sth_Weird

19.10.2007 - 10:41 Uhr

ich experiementiere schon ein paar tage mit diversen steuerelemente zu anzeige sehr vieler datensätze herum. was ich habe ich eine liste mit diversen objekten). die objekte sollen dem user in einer art liste links im formular in form eines icons und eines einfachen textes angezeigt werden und beim klicken soll rechts im formular eine detailansicht aufgehen.
das problem ist nun, dass die objektliste SEHR lang werden kann, ich habe zum teil über 60.000 elemente da drin (und es können auch noch mehr werden).
ich suche deshalb eine methode um die objekte anzuzeigen und das mit möglichst geringer wartezeit. beim treeview (welches mir optisch am besten gefallen würde) habe ich schnell herausgefunden: das wird nichts, da wartet man ewig. ein listview kann ja keine icons anzeigen deshalb hab ich's gleich aussortiert. jetzt bin ich beim datagridview angelangt aber es dauert immer noch recht lang (aber immerhin ist es von den controls am schnellsten). dann habe ich versucht das ganze selbst zu zeichnen (drawstring auf einem label im paint event). das zeichnen ging sehr schnell (ich zeichne auch nur die messages die gerade im sichtbaren bereich sind), aber wenn ich scrolle dann ruckelt es und ist garnicht flüssig (wie es bei treeview und datagridview ist)
hat jemand tips oder ideen, wie man das am besten lösen kann (vielleicht ginge auch was mit nem thread, der ein datagridview im hintergrund fertiglädt während der user schon drin rumklicken kann? denn zur zeit ist das formular während der ladezeit tot)?

gruß & thx
sth_Weird

16.10.2007 - 07:26 Uhr

mein gedanke war halt, dass man die xml-datei sowohl über mein programm als auch von außerhalb (anderer xml-editor) editieren kann und die xsd-datei in beiden fällen bestimmt, wie's auszusehen hat bzw was erlaubt ist...
ich hatte anfangs z.b. meine xml-datei (spalten als attribute) ohne schema als dataset mit meinem programm eingelesen, editiert und das dataset wieder gespeichert, und er hat mir statt der attribute elemente ausgegeben... 😕

jetzt hab ich aber doch wieder ein "problem"...das dataset aus meinem beispiel hab ich ja testweise per code erstellt, es sollte aber eigentlich komplett aus der xml kommen...also DataSet.ReadXml(...) und später DataSet.WriteXml(...). da bleibt mir dann wohl nichts anderes übrig, alle spalten durchzugehen und den columnmappingtype nachträglich auf attribut zu ändern.
aber flexibel bin ich so eigentlich nicht. wenn ich lust hätte attribute und elemente zu mixen (z.b. nur die id/die schlüsselspalten als attribute und den rest als elemente) wäre ich beim speichern aufgeschmissen, würde ich die struktur der tabelle bzw. die namen der spalten nicht kennen 😦
nun ja, für das was ich machen will ist's ausreichend 😉

gruß & danke nochmal
sth_Weird

15.10.2007 - 16:22 Uhr

so funktionierts...aber es macht das xsd eigentlich (rein für das aussehen der xml-datei) überflüssig, oder?
denn die attribute habe ich ja jetzt durch den mappingtype und nicht durch mein xsd bekommen...
ist das xsd denn eigentlich nicht (auch) zum festlegen der ausgegebenen struktur gedacht (bzw. legt beim einlesen einer xml über dataset.readxml fest wie diese strukturiert ist)?

danke für den tipp!

gruß 🙂
sth_Weird

15.10.2007 - 16:00 Uhr

tach!
ich habe ein problem mit der xml-ausgabe eines datasets im xml-format bzw. auch mit dem einlesen...
ich habe, da ich mich mit der materie noch nicht groß beschäftigt habe, ein dataset mit einer tabelle einfach mal per code erstellt:


DataSet ds = new DataSet("MyTables");
DataTable dt = new DataTable("Table1");
dt.Columns.Add("C1", typeof(string));
dt.Columns.Add("C2", typeof(string));
dt.Columns.Add("C3", typeof(string));

dt.Rows.Add(new object[] { "blahC1", "blahC2", "blahC3 });

ds.Tables.Add(dt);

// jetzt als xml schreiben
ds.WriteXml(@"C:\test1.xml");
ds.WriteXmlSchema(@"C:\schema.xsd");

herauskommen tut das:


<?xml version="1.0" standalone="yes"?>
<Test>
  <Table1>
    <C1>blahC1</C1>
    <C2>blahC2</C2>
    <C3>blahC3</C3>
  </Table1>
</Test>

<?xml version="1.0" standalone="yes"?>
<xs:schema id="MyTables" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
  <xs:element name="MyTables" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
    <xs:complexType>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element name="Table1">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="C1" type="xs:string" minOccurs="0" />
              <xs:element name="C2" type="xs:string" minOccurs="0" />
              <xs:element name="C3" type="xs:string" minOccurs="0" />
             </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:choice>
    </xs:complexType>
  </xs:element>
</xs:schema>

ich hätte aber für die spalten anstelle von elemente lieber attribute, deshalb habe ich in der xsd den inhalt vom element "Table1" geändert zu


<xs:complexType>
   <xs:attribute name="C1" type="xs:string" use="optional" />
   <xs:attribute name="C2" type="xs:string" use="optional" />
   <xs:attribute name="C3" type="xs:string" use="optional" />    
 </xs:complexType>

damit dieses schema auch für die ausgabe verwendet wird, dachte ich, es reicht, das in den c# code oben einzufügen:


ds.ReadXmlSchema(@"C:\mySchema.xsd"); // <-- neu: mein Schema einlesen
ds.WriteXml(@"C:\test1.xml"); 
ds.WriteXmlSchema(@"C:\schema.xsd"); // 

ich bekomme keine exceptions, es funktioniert aber leider auch nicht 😦
sowohl xml- als auch die erzeugte xsd-datei sehen so aus wie vorher...mein xsd-schema scheint einfach ignoriert zu werden 😕
was mache ich falsch???

gruß & danke
sth_Weird