Laden...
Avatar #avatar-1693.jpg
citizen.ron myCSharp.de - Member
Selbst. Software-Architekt Frankfurt / Main Dabei seit 23.07.2005 432 Beiträge
Benutzerbeschreibung

Forenbeiträge von citizen.ron Ingesamt 432 Beiträge

13.07.2007 - 09:48 Uhr

Hi proc

Da aber das Word-Formular im Anschluss ggf. noch angepasst wird - ist es also nicht möglich, die Textmarken auszulesen

Wenn ich Dich richtig verstehe, kann es vorkommen, dass das Worddokument vom Formularmodus wieder in den (ungesperrten) Entwurfsmodus umgeschaltet wird und dadurch die Textmarkeninhalte verlorengehen, Du sie aber in Deiner Anwendung beim nächsten Mal trotzdem wieder sehen willst?

Wenn Du eine Datenbankanbindung hast und das Dokument dort irgendwie archiviert werden soll, könntest Du die Textmarkeninhalte in einer separaten Tabelle mit Verweis auf das Dokument ablegen.

Ohne Datenbank würde ich lieber nicht eine separate Datei erzeugen sondern die CustomDocumentProperties verwenden, um alle Textmarken als Kopien dort abzulegen; die kannst Du nämlich auch von C# wieder auslesen.

hth
ron

12.07.2007 - 08:21 Uhr

Hi Tobias,

hängt zwischen den Controls und der DataTable eine BindingSource?
Wenn nicht, würde ich Dir raten, eine BindingSource dazwischenzuhängen, das Hinzufügen der Zeile auch über die BindingSource zu erledigen


BindingSource bds = new BindingSource(myDataset, myDataTableName);
...
DataRowView row = (DataRowView)bds.AddNew();
row[spaltenname] = ...;

hth
Ron

12.07.2007 - 08:15 Uhr

Hi bellheim,

wie wär´s, wenn Du die Tabelle mit einem Zeitstempelfeld versiehst, und das DataGridView absteigend nach dieser Spalte sortierst?

Dann stehen die neuesten / zuletzt geänderten Datensätze immer oben und das Clear/Refill mit der Folge, dass der Cursor immer oben links steht ist dann sogar praktisch...

hth
Ron

11.07.2007 - 14:28 Uhr

@svenson,

alles klar svenson, dann hatte ich Dich nur nicht richtig verstanden (und C# zum Glück doch ein bisschen...) 😉

11.07.2007 - 13:53 Uhr

@svenson

Es gibt ein paar No-Gos für PlugIn-Architekturen

Entweder hab ich Dich oder in C# etwas nicht verstanden..
"Keinerlei Typabfragen mit is",
was spricht gegen:


if (myPlugIn is IPlugIn) 
{
   PlugMe("oh yeah, baby!");
}

"keine Konstruktoren"
Was macht denn CreateInstance, wenn die Klasse keinen Konstruktor hat?
Sogar parameterbehaftete Konstruktorsignaturen sind zulässig.

@Joetempes
Dich könnte in diesem Zusammenhang der Microkernel interessieren:Microkernel

Gruß
Ron

11.07.2007 - 09:29 Uhr

nasowas,

die hat in der Tat mal geklappt .... 😁

Danke für Deine Ermutigung zu diesem Schritt !

Gruß
Ron

11.07.2007 - 09:27 Uhr

Hi Stefan,

wenn Dein Datengitter an eine BindingSource gebunden ist, würde ich es so machen:


   (ConfigGrid.DataSource as BindingSource).MoveNext();
// bzw.
   (ConfigGrid.DataSource as BindingSource).MovePrevious();

Da das Datengitter mit der BindingSource verbunden ist, wird die markierte automatisch immer mit BindingSource.Current synchronisiert.

hth, gruß
Ron

11.07.2007 - 09:09 Uhr

Hallo zusammen,

ich bekomme beim Versuch die Visual Studio Hilfe zu öffnen die Fehlermeldung:

Microsoft Document Explorer kann nicht angezeigt werden, da die angegebene Hilfeauflistung "ms-help://ms.vscc.v80" ungültig ist.

Beim Drücken von F1 im Studio geht zwar der Explorer auf, aber er enthält keine Hilfedokumente mehr.

Was muss ich tun, um sie wiederzukriegen?

Thanx
Ron

10.07.2007 - 14:29 Uhr

hi gollum,

konkret im Zusammenhang mit Deinem Beispiel bin ich nicht sicher, ob das bei uns einen BusinessContext "wert wäre".

Der BusinessContext soll ja insbesondere auch die Aktualisierung von Daten handhaben.

In deinem Beispiel habe ich das Gefühl, dass es mehr um Reporting geht.
Anyway, Aufbereitung der Daten inkl. Nachkommastellenkürzung etc. würde ich noch immer auf Stored Procedure Ebene lösen.

Ich würde auf jeden Fall immer dafür sorgen, dass Daten so aufbereitet wie möglich in meinen Programmen ankommen.

Wenn ich auf Dein Beispiel einen BusinessContext anwenden würde, dann wenn z.B. die erstellten Berichte/Statistikdaten in dieser aufbereiteten Form persistent bleiben sollen oder wenn die Art der Aufbereitung mit SQL einfach nicht machbar wäre.

hth
ron

Find ich echt geil, dass Du Dir ohne eigenes Interesse soviel Zeit nimmst uns das zu vermitteln

Sozialfimmel 😁
Sagen wir´s mal so: Heute ist einer dieser Tage, wo alles was ich im Projekt anpacke, nur zu Verschlimmbesserungen führt - da mach ich mich doch lieber hier nützlich... 😉

10.07.2007 - 12:24 Uhr

Ooops,

gleich so viel Resonanz... 😉

@langalaxy:
Ralf Westphal hat meines Wissens nach nicht explizit zu dem Thema BusinessContext vs. BusinessObject veröffentlicht, da wir uns in einen firmenspezifischen Workshop eingebucht haben und mit ihm unser Framework diskutiert haben, in diesem Rahmen eben nur obengenannter Verbesserungsvorschlag, der dann weiter ausgearbeitet wurde.

@gollum9

Ein weiterer Punkt ist die Tatsache, dass die Daten beim Laden in die BusinessObjects noch nach Vorgaben der Geschäftslogik vorverarbeitet/manipuliert werden müssen

@falangkinjau

und würde micht auch sehr freuen über mehr Informationen/Material oder Beispiele.

Wie aufbereitet oder roh die Daten in das BusinessContext-Objekt gelangen, ist bei uns Aufgabe der Datenlogik und die ist komplett in der Datenbank SQL Server 2005.
Wir haben keine einzige SQL Anweisung im Code; Jeder BusinessContext kommuniziert über Stored Procedures mit der Datenbank. Dabei verwenden wir die Schemata des SQL Servers im wesentlichen auch zur Aufteilung in Anwendungsmodule.
Beispiel:
Das Datenbank-Schema "PM" (für "Projektmanagement") hat alle möglichen Tabellen und Stored Procedures.
Eine Anwendungsview PM hat alle GUI Ansichten zu dem Schema und wird kompiliert in eine [Projektname].PM.dll.
Eine Geschäftsschicht PM.Business hält die Geschäftslogik und damit alle Implementierungen der Schnittstellen und wird kompiliert in [Projektname].PM.Business.dll.
Die Schnittstellen selbst schließlich befinden sich alle in einer gemeinsamen Bibliothek [Projektname].Contracts.dll.

Der Vorteil des BusinessContext liegt meiner Meinung nach bspw. auch in folgendem tabellenübergreifenden Sachverhalt:
Nehmen wir das Szenario an, dass zu einem neuen Kunden automatisch ein Buchungskonto angelegt werden soll. Ausserdem darf er nicht gespeichert werden, wenn nicht mindestens eine Adresse angegeben wurde.
Der BusinessContext enthält nun folgende Tabellen: (s. Bild)
Dabei enthält die "Haupttabelle" natürlich immer nur einen Datensatz (hier: einen Kontakt).

Der Kontext bietet, wie ihr in vorigen Diagramm seht die Methode Save an, um die Daten in die Datenbank zu schreiben.
Save geht aber nur, wenn IsValid = true, und wann sie gültig ist, entscheidet die jeweilige Kontextimplementierung eben aufgrund ihrer Geschäftslogik.
In diesem Falle würde der Kundenkontext eben Save nicht erlauben, wenn zu dem neu angelegten Kontakt nicht mindestens auch ein Eintrag in KONTO, PERSON und ADRESSE erfolgt sind.

hth, gruß
Ron

10.07.2007 - 08:56 Uhr

Guten Morgen Katja,

da mir Dein Ansatz wie gesagt ziemlich bekannt vorkommt, hier noch ein anderer Denkanstoß:

Wir hatten zu Beginn unseres Framework-Designs so etwas wie BusinessObject´s, wo ebenfalls das einzelne Objekt für seine Datenbeschaffung und -speicherung verantwortlich war.

Im Rahmen eines sehr effizienten Workshops im Dezember hat uns Ralf Westphal darauf gebracht, dass es ggf. viel sinnvoller ist, aus BusinessObject einen BusinessContext zu machen: eine Klasse, die eben nicht nur eine Tabelle sondern ein ganzes DataSet enthält, in dem jeweils alle zu verarbeitenden Daten eines Geschäftsprozesses drin sind.

Seine Argumentation war, dass DataSets klein und billig sind und dass eine durchschnittliche Datenbank heutigen Standards sich freut, wenn sie ausreichend zu tun bekommt 🙂

Beispiel: In der GUI soll ein Mitarbeiter mit seiner Anschrift, Unternehmensrolle etc. bearbeitet werden. Der BusinessContext "Mitarbeiter" enthält jetzt ein DataSet mit den Tabellen MITARBEITER, PERSON, ADRESSE, KONTO, TELEFON, AKTIVITAET.

Ausserdem kennt sein DataSet die Beziehungen der Tabellen untereinander und weiß diese zu verarbeiten bzw. zu berücksichtigen: Ein neuer anzulegender Mitarbeiter bspw. erzeugt seine eigene GUID und kann bereits alle Detaildaten in die abhängigen DataTables ebenfalls einfügen, bevor eine Kommunikation mit der physikalischen Datenbank nötig ist.

Wir haben diesen Vorschlag beherzigt und können nur gutes davon berichten.

Anbei mal das Geheimnis unseres Erfolgs als Diagramm 😉

Vielleicht bringt Dich das auch nochmal auf neue Ideen...

Liebe Grüße
Ron

09.07.2007 - 20:24 Uhr

hi twin,

jede Tabelle benötigt ihren eigenen DataAdapter.

Gruß´
Ron

09.07.2007 - 17:22 Uhr

Hallo Katja,

Somit umgeh ich das Umschaufeln beim Einlesen der Daten in die Properties, kein Zurückschaufeln beim Speichern, kein Reinschaufeln bei Aktualisierung.

Ich hab´nicht so recht verstanden, wo Du das genau "umgehst", denn **jede **abgeleitete Klasse muss ja genau das machen: Die veröffentlichten Properties jetzt in Feldnamen umleiten und der DataRow der Basisklasse entnehmen.

Wir haben etwas ähnliches gemacht und verwenden aber einfach einen Indexer, um auf die Feldnamen draufzukommen.
Das mag vielleicht hinsichtlich der Typsicherheit Einbußen bringen, aber an der Stelle, wo man auf die Eigenschaften einer Klasse draufwill, muss man als Programmier ja eh wissen was man tut 😉

Auf Dein Beispiel bezogen sähe das dann wohl so aus:


public class BasisObjekt<T>
{
    public object this[string fieldName] 
    {
        get { return mDataRow[fieldName]; }
        set { mDataRow[fieldName] = value; }
    }

} 

Die abgeleiteten Klassen müssen jetzt hinsichtlich der Properties gar nichts mehr machen.

Und bei der Verwendung sieht´s dann so aus


Kunde customer = new Kunde();
string Nachname = customer["Nachname"].ToString();
float Umsatz = (float)customer["Umsatz"];

hth, gruß
Ron

09.07.2007 - 09:39 Uhr

Hallo Leute,

alle reden von Design by Contract / Contract-First-Design.

Dazu braucht man sinnvollerweise auch eine Fabrik, um zur Laufzeit die Instanzen der Schnittstellenimplementierungen zu erzeugen.

Anbei mal ein Beispiel für einen Microkernel.

Er hat folgende Leistungsmerkmale:*Singleton *Typsichere Erzeugung der Objekte durch Typangabe mittels Generics *Nicht-generische Erzeugung der Objekte durch explizite (nicht-generische) Typangabe *Explizite Angabe der zu ladenden Assembly oder Auflösung der Assembly-, Namespace- und Objektnamen durch Analyse der Schnittstelle *Pfadauflösung durch Verwendung von Anwendungseinstellungen *Drei Arbeitsmodi (Release, Debug, MockUp), welche die automatische Assemblynamensbestimmung mit beeinflussen *Bereitstellung der Anwendungseinstellungen durch ein Property "Settings" *Die Möglichkeit, die angeforderten Objekte ebenfalls nur als Singleton zu erhalten; hierbei merkt sich der Microkernel die Objekte in einem Dictionary und liefert sie bei wiederholter Anforderung von dort, statt sie neu zu instanzieren

Ein Verwendungsbeispiel liegt ebenfalls bei.

Ich hoffe, er hilft dem einen oder anderen weiter bei seiner CFD-Architektur und ich würde mich natürlich auch über Feedback und Verbesserungsvorschläge freuen.

Verwendungshinweis
Im Testprojekt muss die Einstellung "LibraryPath" auf den Pfad eingestellt werden, wohin Ihr bei Euch die Bibliotheken compiliert.
Viel Spaß damit,
Ron

07.07.2007 - 14:11 Uhr

Haaalllloooo

wollte nochmal an die PoolPosition, weil wir zu dem Problem noch immer keine Lösung haben 🙁

Weiss hier keiner was?

Gruß
Ron

07.07.2007 - 14:00 Uhr

hi fzelle,

Warum benutzt eigentlich niemand den extra für soetwas im FW eingebauten Principal?

Wir erben den Principal nicht, weil wir von einer anderen Klasse (BusinessContext) erben wollen.

Aus meinem Beispiel geht aber nicht hervor, dass der Principal nicht vielleicht ein Property des ApplicationContexts ist... 😉

06.07.2007 - 21:13 Uhr

Hallo Hannes,

da Du den gleichen Terminus (ApplicationContext) verwendet hast, wie wir in unserer Architektur, bin ich auf deine Frage aufmerksam geworden.

Wir haben auch einen ApplicationContext und der Anlass war ziemlich genau der gleiche Grund: wir wollen wissen, welche Rechte der aktuelle Benutzer der Anwendung in der DB hat, was seine letzten Einstellungen und Ansichten waren (das steht bei uns auch in der DB) etc.

Wir haben uns für den Singleton entschieden und aufgrund anderer Architekturmerkmale unseres Frameworks aber kein Problem damit, dass "alle", die etwas vom ApplicationContext "wissen" wollen, diesen ansprechen können:
Unser ApplicationContext implementiert eine Schnittstelle IApplicationContext, damit sind schonmal die Fähigkeiten und Methoden überall "bekannt", denn unsere Contracts (Interfaces) sind in nur wenigen DLL´s zusammengefasst.

Ausserdem haben wir eine Microkernel-Architektur.
Da der Microkernel auch ein Singleton ist und ja ohnehin (als Factory) eine zentrale Rolle in der Anwendung spielt, veröffentlicht er gewisse dezentral nötige Dinge eben als Properties und dazu gehört bei uns eben unter anderem der ApplicationContext.

Daher ist in einem beliebigen Modul folgendes Szenario (kurzgefasst) denkbar und umgesetzt:


public class ContactContext : BusinessContext,  IContactContext
{
   #region Members
      private IMicrokernel   microKernel;
   #endregion

   #region .ctor(s)
      public ContactContext() 
      {
          microKernel = KernelLoader.GetMicrokernel();
          string author = microKernel.ApplicationContext.Login;
          base.CanSave = microKernel.ApplicationContext.HasPermission(eContextPermission.Write);
      }
   #endregion
   
}


Hoffe diese Meinung nützt Dir.

Hält irgendjemand diese Architektur für fragwürdig ? - würde mich über Eure Meinungen ebenfalls fruen.

Gruß
Ron

06.07.2007 - 20:18 Uhr

Hi Tokka,

eigentlich darf man sich eine solch schmutzige Signatur nur erlauben, wenn man solche Fragen ...
naja egal, Spaß beiseite 😉

Meiner Meinung nach würde eine einzige Tabelle mit Selbstreferenz schon genügen:
(s. Bild)
Folgende endlos schachtelbare Struktur käme dabei heraus:
RecordID | ParentLocation | Ort
1 | | Frankfurt
2 | | München
3 | 2 | Hintertupfingen
4 | 3 | Hintertupfingen, Unterstadt

Die eigentliche Herausforderung besteht darin, im Abfragebetrieb der Datenbank möglichst schnell von der Instanz/Lokation in Ebene 42 auf ihre oberste Mutterinstanz zurückzugreifen - so etwas ist nämlich schnell mal im Anforderungskatalog... 😉

Meiner Erfahrung nach empfiehlt sich hier eine benutzerdefinierte Funktion rekursiv aufzurufen; die Mutterinstanz hast Du gefunden, wenn keine ParentLocation-Angabe mehr vorhanden ist.

Im Umkehrschluss will man manchmal auch wissen, wieviele Ebenen einer Instanz untergeordnet sind: Hier bietet sich ebenfalls eine rekursive UDF an, in der solange weitergesucht wird, bis die EXISTS Abfrage nach untergeordneten Instanzen keine Ergebnisse mehr liefert.

Wenn das sehr viele Daten werden und Informationen ständig schnell verfügbar sein müssen, empfehle ich dringend, beim Anlegen einer Instanz in separaten Spalten der Tabelle zu protokollieren, auf der wievielten Ebene sie sich befindet und bei jedem Ausbau der Verschachtelungstiefe der obersten Mutterinstanz in einer ebenfalls separaten Spalte die neue Tiefe einzutragen: diese Angaben sparen dann später bei der Rekursion Zeit.

Viel Spaß
Ron

06.07.2007 - 19:55 Uhr

Hi Iceskaarj,

dazu kannst Du die zugrundeliegende BindingSource verwenden: dort ist Current eine DataRowView mit den gewünschten Spalten:


DataRowView row = ((BindingSource)myDataGridView.DataSource).Current as DataRowView;
int selectedMovieID = (int)row["Movie_ID"];

Man könnte natürlich auch die Zeile des DataGridView direkt ansprechen, aber ich bevorzuge wenn möglich immer die obenstehende Variante:


int selectedMovieID = (int)myDataGridView.CurrentRow.Cells["Movie_ID"].Value;

hth
ron

06.07.2007 - 19:46 Uhr

hi andreas,

Du musst das RowPrePaint-Ereignis verwenden.

Normalerweise musst Du dir ein Kriterium (=Feldinhalt) merken, um die Zeile zu identifizieren, die Du farblich hinterlegen möchtest.

Wir haben bei uns etwas ähnliches gemacht: der Benutzer kann Zeilen markieren.
Wir merken uns dann den Wert des Primärschlüssels (RecordID = Guid) in einer Liste.

Im RowPrePaint-Ereignis wird nachgesehen, ob der Wert der RecordID-Spalte in der Liste enthalten ist und die Hintergrundfarbe ggf. geändert.

Klingt langsam und aufwendig, ist aber pfeilschnell 😉

Anbei beispielhaft und vereinfacht unser RowPrePaint-Ereignis:


private List<Guid>      highlightedItems;
private Color HighlightBackColor = Color.Green;
private Color HighlightForeColor = Color.White;

protected virtual void Internal_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
{/*Handle row highlighting*/

// If row contains the row guid field...
   Guid guid = Guid.Empty;
   try
      { guid = (Guid)Rows[e.RowIndex].Cells["RecordID"].Value; }
   catch { }

// check if row is in highlight list
   if ((guid != Guid.Empty) && (highlightedItems.Contains(guid)))
   {
      Rows[e.RowIndex].DefaultCellStyle.BackColor = HighlightBackColor;
      Rows[e.RowIndex].DefaultCellStyle.ForeColor = HighlightForeColor;
   }
}


hth
ron

06.07.2007 - 19:33 Uhr

Hi tobig,

"Zeile verschwindet" klingt für mich eventuell nach einem Filter auf der zugrundeliegenden BindingSource, dessen Kriterien durch den neuen Datensatz nicht erfüllt werden, kann das sein?

Hast Du per Debugger gecheckt, ob nach der Eingabe bzw. nach dem Verschwinden auch in der BindingSource / DataTable kein neuer Datensatz vorhanden ist?

hth
ron

05.07.2007 - 21:08 Uhr

hi toxick,

einen Instanznamen vergibt man z.B. dann, wenn man nicht der erste ist, der den SQL Server installiert, weil dann die namenlose Instanz schon vergeben ist.

Man macht es z.B. auch, wenn das Berechtigungsmodell völlig separat behandelt werden soll.

In deinem Fall würde ich **für **einen Instanznamen argumentieren, da Du den Benutzern nicht die Möglichkeit nehmen solltest, später noch einen vollwertigen SQL Server ohne Instanznamen zu installieren.

Hierfür spricht z.B. auch, dass SQL Server 2005 Express standardmäßig auch einen Instanznamen vorschlägt (SQLEXPRESS), weil er eben kein vollwertiger SQL Server ist.

hth
ron

01.07.2007 - 10:06 Uhr

hallo zusammen,

sicher ist das ein philosophisches Problem, aber Eure Meinungen bzw. Begründungen zu den beiden Varianten interessieren mich u.a. auch aus didaktischen Gründen 😉

Gegeben ist der Fall, dass in einer Methode eine relativ aufwendige Verarbeitung stattfinden soll. Bereits bei Beginn muss aber eine Bedingung erfüllt sein.

Was ist nun Eurer Meinung nach besser, das hier:


private void MonsterMethode()
{
   if (!BedingungErfuellt)
      return;

// Monstercode
}

oder das hier:


private void MonsterMethode()
{
// Keine Weiterverarbeitung wenn Bedingung nicht erfüllt:
   if (BedingungErfuellt)
   {
   // Monstercode
      ...
   }
}

Dabei gehen wir natürlich davon aus, dass die Bedingung nicht außerhalb der Methode vor deren Aufruf geprüft werden kann, bzw. die Prüfung der Bedingung einfach nicht in den Zuständigkeitsbereich des Aufrufers fällt 😉

Und nicht vergessen: der Monstercode kann natürlich auch jede Menge Bedingungen, switches, Verschachtelungen etc. und damit auch Einrückungen enthalten...

Danke für Eure Meinung und Begründungen!

Schönes Wochenende noch
Ron

29.06.2007 - 16:31 Uhr

So, hallo zusammen

we did it!

Wir haben uns Component One Studio Enterprise angeschafft.

Nicht nur ein gutes Gefühl, andere Softwerker unterstützt zu haben, weil Sie wirklich etwas großartiges gezimmert haben sondern auch den Mut, etwas fertiges zu benutzen und sich zu erarbeiten, statt das Rad neu zu erfinden 😉

Kleiner Tip hier am Rande:
Component One wird auch in deutschen Medien beworben, dort meist mit deutschem Vertriebskanal. Der Preis wird auf diesem Weg mit MwSt. veranschlagt; beim Onlinekauf direkt im US Shop der ComponentOne.com-Seite aber nicht.
Umgerechneter Tageskurs heute waren 742 €, im dt. Vertrieb hätte das (inkl. MwSt.) 880,- € gekostet.

Mag für den einen oder anderen Geldbeutel interessant sein, der seine MwSt. am Jahresende nicht für diese Ausgabe geltend machen kann.

So, und jetzt muss ich dringend zurück zu meinem C1Scheduler 😉

Gruß
Ron

29.06.2007 - 11:07 Uhr

hi mercuer,

beim minimize wird doch das resize ereignis ausgelöst - genügt Dir das nicht?

29.06.2007 - 11:04 Uhr

hallo zusammen,

wie bekommt man zur Laufzeit wieder die Werte der Settings.Default in die ApplicationSettings, wie sie in der Entwicklungsumgebung bzw. damit auch in der app.config angegeben sind?

Bereits bei Anwendungsstart sind die ApplicationSettings immer sofort mitden Werten aus der user.config belegt.

Und warum findet der Computer mit der globalen Suche eigentlich nicht die user.config-Dateien, obwohl versteckte und Systemdateien einbezogen sind?

Thanx
Ron

27.06.2007 - 15:37 Uhr

Anlass
Manchmal will man ja in Listen einen Eintrag direkt anspringen, dessen erste (nicht nur erste++s++!) Zeichen den schnell hintereinander eingegebenen Zeichen entsprechen.

Die Listbox bspw. unterstützt diese Funktion nicht.

Anbei ein KeyRecorder, der sich mehrere Zeichen hintereinander merkt und dessen Timeout für automatische Rücksetzung man angeben kann.

Einsatz & Handhabung
Der Konstruktor erlaubt die Übergabe des Controls, das beobachtet werden soll, die Beobachtungsdauer vor Reset und ein EventHandler, der sich auf das KeyStrokeRecorded-Ereignis einbucht:

Beispielprojekt
... liegt bei.

Viel Spaß

Denkbare Ausbaustufen
Ein Recorder, der zwar nur einmal instanziert wird aber mehrere Controls überwachen kann

27.06.2007 - 12:51 Uhr

hallo

ich versuche mit nachstehender Überschreibung des OnColumnAdded-Ereignisses eine Spalte zur Laufzeit durch eine Hyperlinkspalte zu ersetzen:


protected override void OnColumnAdded(DataGridViewColumnEventArgs e)
{
// Wenn Spalte mit Bool(True) getagt ist, handelt es sich um eine Rekursion:
   if ((e.Column.Tag != null) && ((bool)e.Column.Tag))
   {
      base.OnColumnAdded(e);
      return;
   }

// Hyperlinkspalte identifizieren, löschen und durch neuen Spaltentyp ersetzen
   if ((_LinkColumns != null) && (_LinkColumns.Contains(e.Column.DataPropertyName)))
   {
      DataGridViewLinkColumn column = new DataGridViewLinkColumn();
      column.DisplayIndex = e.Column.DisplayIndex;
      column.Name = e.Column.Name;
      column.DataPropertyName = e.Column.DataPropertyName;
      column.ValueType = typeof(string);
      column.Tag = true;
      column.LinkColor = Color.Blue;
      column.VisitedLinkColor = Color.Blue;
      column.LinkBehavior = LinkBehavior.HoverUnderline;
      column.UseColumnTextForLinkValue = true;
      Columns.Remove(e.Column);
      Columns.Add(column);
   }
   else // Basisverarbeitung
      base.OnColumnAdded(e);
}

Die Spalte kommt an, das DataPropertyName ist auch gesetzt, aber die Spalte liefert IsDataBound=false und zeigt dementsprechend auch keine Daten an.

Weiss jemand warum?

thanx
ron

27.06.2007 - 11:23 Uhr

joo,

hab mir schon sowas gedacht und überschreibe gerade OnColumnAdded - werde mein Ergebnis dann für andere Interessenten posten ...

thanx jedenfalls

26.06.2007 - 20:35 Uhr

Hi,

ist es möglich, den Typ der Spalte im Ereignis ColumnAdded einer DataGridView zu verändern?

Das Datengitter hat AutoGenerateColumns = true und ich möchte bestimmte Spalten im Verlauf dieses Events zu HyperLinkColumns machen.

Mein gescheiterten Versuche:


// geht nicht, weil dies ein Typ ist, keine Variable   
   e.Column.CellTemplate = DataGridViewLinkCell;

// geht nicht, weil GetType() in der Klasse nicht vorhanden ist (hä?)
   e.Column.CellTemplate = DataGridViewLinkCell.GetType();

// Eine implizite Konvertierung vom Typ "System.Type" in "System.Windows.Forms.DataGridViewCell" ist nicht möglich.
e.Column.CellTemplate = typeof(DataGridViewLinkCell)

Thanx vorab
ron

26.06.2007 - 19:45 Uhr

Hallo zusammen,

Situation
Ein DataGridView ist auf FullRowSelect eingestellt und bildet lediglich den Selektor für ein UserControl, in dem dann die eigentlichen Datenfelder einzeln bearbeitet werden; das Datengitter ist also nicht zum Schreiben gedacht.

Ich will manchmal verhindern, dass im Datengitter eine andere Zeile ausgewählt wird (z.B. weil die gemachten Angaben im Unterformular noch nicht vollständig sind.

Problem
Sowohl DataGridView als auch BindingSource bieten nur Ereignisse an, bei denen das Kind schon in den Brunnen gefallen ist:*BindingSource.PositionChanged ist schon zu spät *DataGridView.Validating findet nicht statt, weil im Datengitter nicht geschrieben wird *DataGridView.RowEnter ist zwar rechtzeitig, tritt aber auch auf, wenn man mit dem Fokus ins Gitter zurückkehrt und in die gleiche Zeile klickt und außerdem bietet es kein Cancel an *DataGridView.SelectionChanged ist zu spät: die BindingSource hat hier ihre Position bereits gewechselt *Die Ereignisse SelectionChanging bzw. PositionChanging sind leider nicht vorhande (was ich übrigens ziemlich Banane finde)

Bis jetzt so gelöst
Im RowEnter-Ereignis ist SelectedRows[0] die soeben "betretene" Zeile.
Zu dieser Zeit ist CurrentRow noch die alte Zeile.
Ich klinke mich hier mit einem selbst definierten Ereignishandler ein, der Cancel erlaubt. Wird gecancelt, merke ich mir intern die "alte" BindingSource-Position und verarbeite dann im SelectionChanged-Ereignis die gemerkte Position, indem ich die BindingSource wieder auf die alte Position zurücksetze.

Wie man sich denken kann, hat das aber den Nachteil, dass BindingSource.PositionChanged natürlich trotzdem gefeuert wird (und mit dieser Technik auch noch zweimal) und daher nicht mehr für andere Zwecke vernünftig genutzt werden kann.

Hat jemand von Euch eine Idee, wo man da konzeptionell einsetzt und wie man das besser lösen könnte?

Danke für Eure Meinung
Ron

26.06.2007 - 14:57 Uhr

hi ihr lieben helfer

hab auch nochmal mit den eventnamen herumexperimentiert und tatsächlich: DBValueChanged passt!

Tausend Dank für Eure Unterstützung.

Die Erklärung habe ich allerdings noch nicht so richtig verstanden...?

Gruß
ron

26.06.2007 - 14:18 Uhr

hi programmierhans,

die werte stimmen ja aber überein - das problem scheint irgendwas mit persistenz und validierung zu tun zu haben.

gefunden habe ich schon einige internationale threads dazu, aber keiner hat eine befriedigende antwort; folgende funktioniert bei mir z.B. leider nicht:
http://www.devnewsgroups.net/group/microsoft.public.dotnet.framework.windowsforms/topic36268.aspx

Most likely because there is no similar named Changed event, so the property
value always get's persisted at Control.Validating. And a DataRow doesn't
care if it's the same value, if a field is set then it's marked as changed.

Add a changed event to your UserControl ...

With a Changed event, it will persist the value at Control.Validating but
only if the Changed event has fired before the Validating event.

Manche gehen in der Tat von einem Bug aus und programmieren eigene Prüfmethoden, um auf Tabellenebene ein HasChanges(string Tablename) zu machen, indem Sie in allen Tabellen des DataSets den aktuellen Datensatz und seine RowVersion angucken - das kann ja wohl nicht sein...

Ich suche mich jetzt schon seit dem ersten Post heute morgen durch diesen sch.... und bin schon am Durchdrehen 🙁

26.06.2007 - 11:30 Uhr

Hallo zusammen,

Topic
ich habe ein eigenes datengebundenes Label erstellt, das mir (u.a.) erlauben soll, Werte einer Datenbindung formatiert darzustellen und die Datenbindung auf einen übergeordneten IDataContainer zusetzen, aus dessen ggf. mehreren BindingSources ich über die Properties "TableName" und "ColumnName" den genaue Datenbezug spezifizieren kann:


/*———————————————————————————————————————————————————————————————————————————————————————————————————————————————————*/
/* DBLabel                                                                                                           */
/*———————————————————————————————————————————————————————————————————————————————————————————————————————————————————*/
/* A Label inheritant providing data features for use with the Casa Application Framework (CAF)                      */
/*———————————————————————————————————————————————————————————————————————————————————————————————————————————————————*/
// Created  :  Sept. 2006, cr
// Modified :  
/*———————————————————————————————————————————————————————————————————————————————————————————————————————————————————*/
using System;
using System.Drawing;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;

namespace CCL.Common
{
// DBLabel
   /// <summary>
   /// A Label inheritant providing data features for use with the Casa Application Framework (CAF)
   /// </summary>
   [System.Drawing.ToolboxBitmap(typeof(DBLabel), "Resources.DBLabel.bmp")]
   public class DataLabel : Label
   {

   #region Members
      private IDataContainer     dataContainer;
   #endregion

   #region Property-bound members
      private string     _TableName     = string.Empty;
      private string     _ColumnName    = string.Empty;
      private string     _Format        = string.Empty;
   #endregion

   #region Properties

   // Tablename
      /// <summary>
      /// Gets or sets the data table name when this textbox is data bound 
      /// </summary>
      [Category("Daten")]
      [Description("Defines the underlying data table when this textbox is data bound")]
      public string TableName
      {
         get { return _TableName; }
         set { _TableName = (value == null) ? string.Empty : value;  }
      }

   // ColumnName
      /// <summary>
      /// Gets or sets the data column when this textbox is data bound 
      /// </summary>
      [Category("Daten")]
      [Description("Defines the underlying data column when this textbox is data bound")]
      public string ColumnName
      {
         get { return _ColumnName; }
         set 
         { 
            _ColumnName = (value == null) ? string.Empty : value; 
            if ((DesignMode) && (_ColumnName != null)) Text = "<" + _ColumnName + ">";
         }
      }

   // DBValue
      /// <summary>
      /// Gets or sets the data value of the control
      /// </summary>
      [Category("Daten")]
      [Bindable(true, BindingDirection.OneWay)]
      [Description("Defines the underlying data value of the control")]
      public object DBValue
     {
         get { return base.Text; }
         set 
         { 
				if (value == null || value == DBNull.Value)
               base.Text = string.Empty; 
            else
            {
               if (_Format != string.Empty) 
                  base.Text = String.Format("{0:" + _Format + "}", value);
               else
                  base.Text = value.ToString(); 
            }
         }
     }

   // Format
      /// <summary>
      /// Gets or sets the format string of the displayed value
      /// </summary>
      [Browsable(true)]
      [Category("Daten")]
      [Description("Gets or sets the format string of the displayed value")]
      public string Format
      {
         get { return _Format; }
         set { _Format = value; }
      }

   #endregion

   #region .ctor
      public DataLabel() : base()
      {
         BackColor = Color.Transparent;
         if ((DesignMode) && (_ColumnName != null)) Text = "<" + _ColumnName + ">";
      }
   #endregion

   #region Overrides
   // CreateHandle
      /// <summary>
      /// Creates the control´s handle and connects to microkernel in runtime mode
      /// </summary>
      protected override void CreateHandle()
      {
         base.CreateHandle();
         
         if (!DesignMode) 
         {
            dataContainer = FindDataContainer();
            if (dataContainer != null)
               dataContainer.DataBindingChanged += new EventHandler(OnDataBindingChanged);
         }
      }
   #endregion

   #region Event handling
      void OnDataBindingChanged(object sender, EventArgs e)
      {
      // Relink data bindings after business context has changed
         if ((dataContainer != null) && (_TableName != string.Empty) && (_ColumnName != string.Empty)) try
         { 
            DataBindings.Clear();
            DataBindings.Add(dataContainer.GetBinding("DBValue", _TableName, _ColumnName));
         }
         catch (Exception exc)
            { dataContainer.Throw(exc); }
      }
   #endregion

   #region Methods
      private IDataContainer FindDataContainer()
      {
         Control result = this;
         Form ownerForm = FindForm();
         while (result != ownerForm)
         {
            result = result.Parent;
            if (result is IDataContainer)
               break;
         }
         return result as IDataContainer;
      }
   #endregion
   }
}

Problem
Das Problem ist, dass durch die Bindung an das eigene Property "DBValue" offensichtlich eine Änderung der Daten stattfindet, denn bereits nach einer Navigation der BindingSource zum nächsten Datensatz liefert DataSet.HasChanges() = true.

Meine Tests:
Wenn ich die Bindung auf das Text Property setze, findet diese Änderung nicht statt:


void OnDataBindingChanged(object sender, EventArgs e)
{
// Relink data bindings after business context has changed
   if ((dataContainer != null) && (_TableName != string.Empty) && (_ColumnName != string.Empty)) try
   { 
      DataBindings.Clear();
      DataBindings.Add(dataContainer.GetBinding("Text", _TableName, _ColumnName));
   }
   catch (Exception exc)
      { dataContainer.Throw(exc); }
}

Witzigerweise gilt das auch dann, wenn ich das Property überschreibe und mit dem Code aus meinem eigenen Property "DBValue" fülle:


public override string Text
{
   get
   {
      if ((DesignMode) && (_ColumnName != null))
         return "<" + _ColumnName + ">";
      else
         return base.Text;
   }
   set 
   {
      if ((DesignMode) && (_ColumnName != null))
         base.Text = "<" + _ColumnName + ">";
      else
      { 
         if (_Format != string.Empty) 
            base.Text = String.Format("{0:" + _Format + "}", value);
         else
            base.Text = value.ToString(); 
      }
   }
}

De facto sollte das jetzt identisch sein, außer dass ich ein eigenes Property namens "DBValue" definiert habe, das aber doch exakt das gleiche macht und obendrein die Bindungsrichtung auf "einseitig" festlegt - ich bin ratlos.

**Hintergrund **
Es handelt sich hierbei um nur ein Control unter vielen anderen, die alle eine Schnittstelle namens IDBControl unseres Frameworks implementieren und daher das Property DBValue erforderlich ist.

Bin für jeden Denkanstoß dankbar,
thanx
ron

25.06.2007 - 18:22 Uhr

hi n

SQLExpress = kostenloser SQL Server, passt perfekt für Deine Bedürfnisse 🙂

hth
ron

24.06.2007 - 12:48 Uhr

hi fzelle,

danke für die Info.

stimmt, der Scheduler ist recht neu;

wir haben auch den Scheduler von DevExpress getestet, aber nicht nur optisch sondern auch von der Architektur (und den Rezensionen) her halte ich die ComponentOne Komponenten persönlich für überzeugender - ist aber wahrscheinlich ne Glaubensfrage 😉

thanx
ron

24.06.2007 - 10:16 Uhr

hallo evo2,

ich habe mal unsere Design-Richtlinien als Anhang beigefügt - da Fragen dieser Art ja immer mal wieder kommen, sind ja vielleicht noch andere interessierte Leser im Forum... 😉

hth,
ron

PS:
...und natürlich, wie bei fast allen Themen, ist vieles Geschmackssache und Diskussionsgrundlage 😉

24.06.2007 - 09:29 Uhr

hi sebowitsc,

ach ja, es war ja Access, also, dann halt:

OleDbCommandBuilder !

und ohne geht es natürlich auch: du schreibst die Command-Befehle jeweils komplett selbst 😉

23.06.2007 - 12:13 Uhr

Hallo miteinander,

wir überlegen uns, ComponentOne Studio Enterprise 2007 anzuschaffen.

Wir finden aber nirgendwo einen Hinweis darauf, ob dort die Quelltexte dabei sind. Weiss das jemand von Euch?

Und kennt jemand einen geeigneteren Anbieter von datenbindbaren Terminplanungs- und Kalendersteuerelementen?

Danke für Eure Meinung

ron

23.06.2007 - 10:06 Uhr

hi sebowitsch,

wie die Fehlermeldung schon (fast) sagt, brauchst du 😗zum Ändern der Daten ein UpdateCommand *zum Einfügen ein InsertCommand *zum Löschen ein DeleteCommand.

da du kein typisiertes DataSet zu verwenden scheinst, ist der schnellste Weg, an diese Dinger dranzukommen der CommandBuilder:


SqlCommandBuilder builder = new SqlCommandBuilder(journalTableAdapter);
journalTableAdapter.DeleteCommand = builder.GetDeleteCommand(true);
journalTableAdapter.UpdateCommand = builder.GetUpdateCommand(true);
...

hth
ron

22.06.2007 - 16:06 Uhr

hi demotape,

ich hab vielleicht noch nicht verstanden, wohin die Daten eigentlich gehen.
wenn ich es richtig verstehe, ist ein Datenpartner eine DB/2 auf der AS/400.

Und der andere?

Wenn es ein SQL Server ist, dann empfehle ich die Nutzung der SSIS (SQL Server Integration Services).
Hier kannst Du mittels VS Business Intelligence Projekten Pakete gestalten, die u. a. genau das können, was Du dort machen willst - ohne Code!

hth
ron

20.06.2007 - 08:37 Uhr

hi serglo,

ganz klar lösung c), machen wir auch, gibt keine performance probleme.

kleiner tip noch, wenn guid´s die primärschlüssel sind:
wenn´s geht nimm lieber sql express 2005 statt access und richte zusätzlich ein identity (=zähler) als gruppierten (=clustered) index ein und schalte die gruppierung für den primärschlüssel aus - dadurch beseitigst du dann wirklich das letzte performance problem, das dabei noch auftauchen kann, nämlich das umgruppieren des index beim einfügen einer guid.

gruß
ron

19.06.2007 - 18:02 Uhr

hallo zusammen,

weiss jemand von Euch, woran sich die Größe eines UserControls orientiert, wenn man AutoSize auf true und AutoSizeMode auf GrowAndShrink setzt?

Das UserControl wird bei mir schon im Entwurfsmodus dann so klein, wie in MinimumSize angegeben - es orientiert sich jedenfalls **nicht ** an seinem Inhalt sprich: an den in der UserControl angeordneten Controls.

Mach ich da was falsch?
Ein AutoSize einer PictureBox orientiert sich doch auch an der Größe seines Bildes...?

thanx
Ron

17.06.2007 - 11:22 Uhr

hi sqlneuling,

ergänzend zur erklärung von a957m sei noch gesagt:
die auflösungstabellen bestehen in der minimalen form ja nur aus zwei feldern, nämlich den beiden fremdschlüsseln, die alle möglichen kombinationen der primärschlüssel der beiden anderen tabellen darstellen.

aus diesem grund könnte man den primärschlüssel der auflösungstabelle theoretisch auf die kombination beider fremdschlüssel setzen, denn die aussage, dass der lehrer mit ID=8 den schüler mit ID=15 unterrichtet, ist ja beim ersten eintrag schon ausgedrückt und es sollte daher natürlich verboten sein, genau dieselbe kombination erneut in die tabelle einzutragen.

praktisch werden die auflösungstabellen aber oft verwendet, um weitere sachverhalte der beziehung darzustellen, bspw nicht nur
"Herr Schlaumeier unterrichtet Lieschen Müller"
sondern
"Herr Schlaumeier unterrichtet(e) Lieschen Müller im Zeitraum **von **1.10.2006 bis 30.4.2007"

In diesem Fall kommen also noch die beiden Datumsspalten [von] und [bis] hinzu und damit "verdient" die Auflösungstabelle nun einen vollwertigen eigenen Primärschlüssel (z.B. einen Zähler oder einen GUID).

Allgemeiner gesagt: Auflösungstabellen schildern häufig noch zeitliche Gültigkeiten oder Statusinformationen zur Beziehung, die sie beschreiben.

Gruß

ron

14.06.2007 - 15:31 Uhr

hi marmey

Erklärst du mir bitte mal wie du das meinst. Wo soll ich den die Abfrage sonst machen als im Code? Versteh ich gerade irgendwie nicht.

ich würde lieber die abfrage in der datenbank speichern und per code die abfrage abrufen.
abfragen können auch in access parameter haben: rechte maustaste im abfragefenster, Befehl "Parameter..."

im code rufst du nur den namen der abfrage auf und übergibst trotzdem das kriterium (genau, wie du es jetzt machst)

die vba entsprechung wäre sinngemäß:


Sub kannweg()
  Dim qd As QueryDef
  Dim rs As Recordset
  
  Set qd = CurrentDb.QueryDefs("sq_Adresse")
  qd.Parameters("PLZ") = "65345"
  Set rs = qd.OpenRecordset
  rs.MoveLast
  Debug.Print rs.RecordCount
  set rs=nothing
  set qd = nothing
End Sub


...für eine Abfrage des Namens "sq_Adresse" mit einem benannten Parameter namens "PLZ"

der vorteil ist ganz einfach: brauchst du später andere oder zusätzliche felder im ergebnis, brauchst du nur die datenbank anzufassen und kein neuen Build deiner anwendung anzufertigen.

gruß
ron

ps:
...und ich habe gelernt, dass das c#-Command-Objekt mitseiner Methode AddWithValue anscheinend auch mit Access Abfragen funktioniert! 😉

14.06.2007 - 09:27 Uhr

hi marmey,

kann sein, dass ich mich irre, aber soweit ich weiss, ist das Command-Objekt und dessen Methode AddWithValue nicht dafür gedacht, SQL-Zeichenketten, dessen Parameter nur als "?" gekennzeichnet sind, mit Werten zu bedienen.

Die Methode füllt eher die benannten Argumente einer gespeicherten Prozedur in bspw. einem SQL-Server; dort haben die Argumente nämlich Namen.

Die Fehlermeldung dürfte auch daher rühren, dass dem Datenprovider die Beschreibung des Parameters fehlt - er findet ja nur "?" und sucht aber nach "@datum".

Wenn du sowieso die Abfrage im Code zusammenbaust (was ich übrigens für wartbare Projekte nicht empfehle), kannst Du ja auch die komplette Zeichenkette samt Datumseinschränkung zusammenbauen.

hth
ron

11.06.2007 - 22:29 Uhr

hi pro

zitat ms help:

AFTER
Gibt an, dass der DML-Trigger nur dann ausgelöst wird, wenn alle Vorgänge, die in der den Trigger auslösenden SQL-Anweisung festgelegt sind, erfolgreich ausgeführt wurden. Alle referenziellen CASCADE-Aktionen und Einschränkungsüberprüfungen müssen ebenfalls erfolgreich ausgeführt worden sein, bevor dieser Trigger ausgelöst wird.

AFTER ist die Standardeinstellung, wenn FOR das einzige angegebene Schlüsselwort ist.

Es gibt nur noch den instead of, der dann eben "stattdessen" ausgeführt wird.

Solltest du im rahmen des triggers aber noch einfluss auf die zu verarbeitenden daten nehmen wollen, könnte ich mir vorstellen, das über die dort implizit bekannten "tabellen" inserted und deleted zu tun.

willst du also bspw. verhindern, dass zeilen mit dem wert 42 in spalte [dieAntwort] in die tabelle [Anhalter] eingefügt werden, könnte ich mir sowas vorstellen:


Delete from inserted
where ([dieAntwort] = 42)

ist zwar auf die schnelle jetzt nicht getestet, ich glaube aber, dass die tabellen inserted und deleted deinem einfluss unterliegen.

hth
ron

11.06.2007 - 22:18 Uhr

hi bibi,

wir haben auch ein paar eigene toolstrips bauen wollen.

der trick besteht darin, dem controlhost ein containercontrol zu geben, in dem dann die "mehreren" anderen controls zu liegen kommen können - wir haben hier immer ein FlowLayoutPanel genommen.

beispielhaft nachstehend ein ToolStripControlHost-Erbe, der einen DateTimePicker in den ToolStrip packt und einen Label davorsetzt, dessen Text im Konstruktor mit übergeben wird:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

namespace CCL.Common
{
   public partial class ToolStripDateTimeBox : ToolStripControlHost
   {
   #region Members
      private FlowLayoutPanel       controlPanel;
   #endregion

   #region Property-bound Members
      private Label                 _Label = new Label();
      private DBDateTimePicker      _DateTimeBox = new DBDateTimePicker();
   #endregion

   #region Properties

      public Label Label
      {
         get { return _Label; }
         set { _Label = value; }
      }

      public DBDateTimePicker DateTimeBox
      {
         get { return _DateTimeBox; }
         set { _DateTimeBox = value; }
      }         

   #endregion
   
   #region .ctor
      /// <summary>
      /// Provides a ToolStripMenu with a labeled DateTimePicker
      /// </summary>
      /// <param name="labelText"></param>
      public ToolStripDateTimeBox(string labelText) : base(new FlowLayoutPanel())
      {
      // Set up the FlowLayouPanel.         
         controlPanel = (FlowLayoutPanel)base.Control;
         controlPanel.BackColor = Color.Transparent;             
         
      // Set up child controls
         _Label.Text = labelText;
         _Label.Padding = new Padding(0, 4, 1, 1);
         _DateTimeBox.Size = new Size(100, 20);
         _DateTimeBox.NullText = "k.A.";
         _DateTimeBox.DBValue = DBNull.Value;

      // Add two child controls.         
         controlPanel.Controls.Add(_Label);
         controlPanel.Controls.Add(_DateTimeBox);

         InitializeComponent();
      }
   #endregion

   }
}

Angewendet wird es dann z.B. so:


ContextMenuStrip cms = new ContextMenuStrip();
ToolStripDateTimeBox tsdtb = new ToolStripDateTimeBox("  Bitte geben Sie ein Datum ein:");
cms.Items.AddRange(new ToolStripItem[] { tsdtb });

hth
ron

08.06.2007 - 19:56 Uhr

hallo bibi,

wir haben ebenfalls eine ListViewdie man umschalten kann und ich kann deine erfahrung nur bestätigen: richtig rund läuft die auch unserer erfahrung nach echt nicht.

was ber das problem auf jeden fall "behebt", ist, nach solchen view-umschaltungen die methode redrawitems() aufzurufen: das erzwingt die neuzeichnung der elemente und räumt damit zumindest solche überlagerungen aus der welt.

hth
ron

04.06.2007 - 12:06 Uhr

hi zusammen,

ich versuche einen Zellbereich von Excel in meine Anwendung zu ziehen.

Wie ermittele ich, ob das gezogene Objekt eine Excel-Range ist und wie weise ich das einer entsprechenden Variable zu?

Die definierten DataFormats bieten ja kein Excel an und ich weiss nicht, welches andere Format ich nehmen soll.

Folgendes geht jedenfalls nicht:


private void btnObjects_DragDrop(object sender, DragEventArgs e)
{
   try
   {
      Range subject = (e.Data as Range);
   // oder anderer Ansatz:
      Range subject = (e.Data.GetDataPresent("Excel.Range", true) as Range);
   }
   catch { }
}

danke für eure Hilfe,
Ron