Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Portal
  • |
  • Mitglieder
Beiträge von citizen.ron
Thema: Akzeptables Klassendesign?
Am im Forum: Rund um die Programmierung

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

Thema: Aktualisieren mehrerer Access Tabellen
Am im Forum: Datentechnologien

hi twin,

jede Tabelle benötigt ihren eigenen DataAdapter.

Gruß´
Ron

Thema: Akzeptables Klassendesign?
Am im Forum: Rund um die Programmierung

Hallo Katja,

Zitat
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

Thema: Microkernel
Am im Forum: .NET-Komponenten und C#-Snippets

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

Thema: DataGridView: In OnColumnAdded hinzugefügte Spalte hat keine Datenbindung?
Am im Forum: GUI: Windows-Forms

Haaalllloooo

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

Weiss hier keiner was?

Gruß
Ron

Thema: Application Context verwenden?
Am im Forum: Rund um die Programmierung

hi fzelle,

Zitat
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... ;-)

Thema: Application Context verwenden?
Am im Forum: Rund um die Programmierung

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

Thema: Suche Datenstruktur zur Speicherung von Organigrammen in einer DB
Am im Forum: Datentechnologien

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

Thema: DataGridView - Reihe markieren, dabei soll aus MySQL die ID abgerufen werden
Am im Forum: Datentechnologien

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

Thema: DataGridView + Formatierung
Am im Forum: GUI: Windows-Forms

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

Thema: DatagridView übernimmt Eingaben nicht
Am im Forum: Datentechnologien

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

Thema: SQL-Server...wann Instanz? Wann nicht?!
Am im Forum: Datentechnologien

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

Thema: return oder erfülltes if?
Am im Forum: Rund um die Programmierung

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

Thema: ComponentOne Studio Enterprise 2007 SourceCodes / Komponenten zur datengebundenen Terminplanung
Am im Forum: Smalltalk

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

Thema: IMessageFilter
Am im Forum: GUI: Windows-Forms

hi mercuer,

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

Thema: Anwendungseinstellungen: Settings wieder mit Defaultwerten belegen
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

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

Thema: KeyRecorder für Listensuchfunktionen über mehrere Zeichen
Am im Forum: .NET-Komponenten und C#-Snippets

Anlass
Manchmal will man ja in Listen einen Eintrag direkt anspringen, dessen erste (nicht nur erstes!) 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

Thema: DataGridView: In OnColumnAdded hinzugefügte Spalte hat keine Datenbindung?
Am im Forum: GUI: Windows-Forms

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

Thema: Ändern des Spaltentyps einer DataGridView-Column
Am im Forum: GUI: Windows-Forms

joo,

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

thanx jedenfalls

Thema: Ändern des Spaltentyps einer DataGridView-Column
Am im Forum: GUI: Windows-Forms

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

Thema: DataGridView.SelectionChanging oder BindingSource.PositionChanging abfangen
Am im Forum: GUI: Windows-Forms

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

Thema: Warum wird DataSet.HasChanges() = true von DataBinding auf eigenem Property
Am im Forum: Datentechnologien

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

Thema: Warum wird DataSet.HasChanges() = true von DataBinding auf eigenem Property
Am im Forum: Datentechnologien

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

Zitat
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

Thema: Warum wird DataSet.HasChanges() = true von DataBinding auf eigenem Property
Am im Forum: Datentechnologien

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

Thema: Welche Datenquelle?
Am im Forum: Datentechnologien

hi n

SQLExpress = kostenloser SQL Server, passt perfekt für Deine Bedürfnisse :-)

hth
ron

Thema: ComponentOne Studio Enterprise 2007 SourceCodes / Komponenten zur datengebundenen Terminplanung
Am im Forum: Smalltalk

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

Thema: Datenbank Design
Am im Forum: Datentechnologien

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 ;-)

Thema: Löschen einer Zeile aus einer Datenbank
Am im Forum: Datentechnologien

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 ;-)

Thema: ComponentOne Studio Enterprise 2007 SourceCodes / Komponenten zur datengebundenen Terminplanung
Am im Forum: Smalltalk

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

Thema: Löschen einer Zeile aus einer Datenbank
Am im Forum: Datentechnologien

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