Wo merkt sich der/das DataGridView die Anzahl den DataSource-Zuweisungen, bzw. wie kann ich das umgehen?
Das DatagridView merkt sich gar nichts - du musst nichts umgehen.
Welchen Formulartyp Du öffnest, hängt von der BindingSource (also: Name der Tabelle) ab.
Ob der Doppelklick in die Row dann jedesmal eine neue Instanz des passenden Forms öffnet, kannst du ja durch den Gültigkeitsbereich der Variable steuern bzw. indem du die BindingSource der Tabelle an das Formular weiterreichst - das Property myBindingSource.Current ist automatisch das, was deine Form-Controls mit Daten "füttert"
ich habe aus aktuellem anlass ein bisschen mit dragons code herumgebastelt und folgende änderungen/erweiterungen vorgenommen:
Die Methode heisst ein bissi anders ;-)
Sie erhält das Control Objekt, dessen Region zu ändern ist, komplett, statt nur seine Dimension
Die Radien von oberen und unteren Ecken können separat angegeben werden
Folgendes ist mir aufgefallen:
Wenn diese Methode auf ein Control (UserControl, Form, etc.) angewendet werden soll, ist es dringend erforderlich, das nach dem Zeichnen zu tun.
Ist das Control bspw. mit Dock.Top in einem Panel, dann darf die Methode erst nach dem myPanel.Controls.Add(rundeEckenDings) abgearbeitet werden.
Da mein UserControl selbst die Sache mit dem Skin in die Hand nehmen soll, habe ich einfach die Anwendung des Skins in das Paint-Ereignis gepackt
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (_SkinType != eSkinType.None)
{
Skin skin = new Skin(this, _SkinType);
}
}
...und der Konstruktor des Skins übernimmt die Arbeit schon bei der Initialisierung mit dem Control, auf dem es zur Anwendung kommen soll:
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace CCL.Common
{
[Flags]
public enum eSkinType
{
None = 0,
RoundedEdges = 1,
Shadowed = 2
}
public class Skin
{
#region .ctor
public Skin(Control control, eSkinType skin)
{
if ((skin & eSkinType.RoundedEdges) == eSkinType.RoundedEdges)
control.Region = RoundRegionOf(control, 9, 5);
}
#endregion
#region Methods
public Region RoundRegionOf(Control control, int upperRadius, int lowerRadius)
{
// If corner radius is less than or equal to zero, return the original rectangle
if ((lowerRadius ≤ 0) || (upperRadius ≤ 0))
return new Region(control.ClientRectangle);
// If corner radius is greater than or equal to half the width or height (whichever is shorter) then return a capsule instead of a lozenge
double limitVal = (Math.Min(control.ClientRectangle.Width, control.ClientRectangle.Height) / 2.0);
if ((lowerRadius ≥ limitVal) || (upperRadius ≥ limitVal))
return GetCapsule(control.ClientRectangle);
GraphicsPath gp = new GraphicsPath();
Rectangle rect = new Rectangle(control.ClientRectangle.Location, new Size((2 * upperRadius), (2 * upperRadius)));
// top left arc
gp.AddArc(rect, 180, 90);
// top right arc
rect.X = control.ClientRectangle.Right - (2 * upperRadius);
gp.AddArc(rect, 270, 90);
// bottom right arc
rect = new Rectangle(rect.X + (2 * (upperRadius - lowerRadius)), rect.Y, (2 * lowerRadius), (2 * lowerRadius));
rect.Y = control.ClientRectangle.Bottom - (2 * lowerRadius);
gp.AddArc(rect, 0, 90);
// bottom left arc
rect.X = control.ClientRectangle.Left;
gp.AddArc(rect, 90, 90);
gp.CloseFigure();
return new Region(gp);
}
#endregion
}
}
ich habe eine klasse von Form geerbt, die in der toolbox angezeigt werden soll.
offensichtlich werden von Form geerbte Klassen aber nicht ohne weiteres vom VS2005 akzeptiert; es wird in der Liste meiner Controls aus der Assembly nicht angeboten.
du stellst der klassendeklaration den verweis auf die bitmap voran, hier ein beispiel:
[System.Drawing.ToolboxBitmap(typeof(myListBox), "Resources.myListBox.bmp")]
public class myListBox : ListBox
...
natürlich musst du dem projekt diese bitmap auch hinzufügen.
sie liegen bei uns im (angegebenen verzeichnis "Resources" mit Buildvorgang "Eingebettete Ressource" und "Nicht kopieren".
jeder tableadapter (oder SqlDataAdapter) hat die commandobjekte SelectCommand, UpdateCommand, InsertCommand, DeleteCommand.
wenn dein (offensichtlich typisiertes) dataset nur select- bzw. insert commands kann, beim update aber einen fehler wirft, ist dein updatecommand objekt entweder nicht definiert oder reflektiert nicht mehr die aktuelle tabellenstruktur.
guck mal in der cs-datei deines datset designers nach.
gruß
ron
ps: und arbeite dich lieber ins thema ein bisschen tiefer ein und verwende dann untypisierte datasets
und schon dann als verweis im dataset zu benutzen, noch bevor der datensatz physikalisch in der DB vorhanden ist.
deine lösung hat ja außerdem den Performance-Nachteil, dass du ja eigentlich "nur schonmal speicherst", um die ID überhaupt erst zu bekommen, die du dann zur Weiterverarbeitung brauchst.
um das streamen muss man sich eigentlich nicht explizit kümmern: datengitter können bei einstellung autogeneratecolumns die typen eigenständig erkennen.
sie ist für meine zwecke ein bisschen unelegant, weil die besitzer des kontextmenüs in unterschiedlichen dll´s liegen, die erst zur laufzeit geladen werden.
ich möchte eigentlich vermeiden, dass irgendein knoten meines treeviews auf verdacht mal ein menuitem einses bestimmten namens sucht, das von einem datengitter einer anderen dll eventuell hinzugefügt worden sein könnte...
noch immer nicht der eleganteste (weil bspw. ToolStripSeperators keine ToolStripMenuItems sind und daher noch eine switch anweisung in die verarbeitung müsste), aber es ist eine möglichkeit.
falls es aber noch etwas eleganteres gibt, bitte sagt mir bescheid!
folgendes geht auch nicht, weil toolstripmenuItems nur einem toolstrip angehören können und dazu führt, dass das kontextmenü des ersten controls anschliessend leer ist:
ContextMenuStrip cms = new ContextMenuStrip();
cms.Items.AddRange(myControl.ContextMenuStrip.Items);
myOtherControl.ContextMenuStrip = cms;
also wie zum kuckuck "klont" man alle items des einen menüs inklusive bereits zugewiesenem eventhandler, ohne dass dem "original" dabei ein unglück geschieht?
ich möchte, dass jede Zeile eines DataGridView ein eigenes Kontextmenü hat. Dabei zeigen die meisten Einträge ins Menü aber grundsätzlich auf den gleichen EventHandler.
Das Tag des Kontextmenüs speichert dabei momentan die DatGridViewRow, zu der sie gehört, damit ich beim Verarbeiten im EventHandler herausfinden kann, welche Zeile betroffen ist.
Derzeit verwende ich zur Zuweisung das RowPrePaint-Ereignis, um das Kontextmenü zuzuweisen.
protected virtual void DataGrid_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
{
// Allow row to get highlighted
ToolStripMenuItem miHighlight;
// If row contains the row guid field...
Guid guid = Guid.Empty;
try
{ guid = (Guid)Rows[e.RowIndex].Cells[RowGuidColumnName].Value; }
catch { }
// check if row is in highlight list
if (guid != Guid.Empty)
{
ContextMenuStrip cms = new ContextMenuStrip();
if (_HighlightedRows.Contains(guid))
{
miHighlight = new ToolStripMenuItem("Markierung entfernen", null, tsiHighlight_Click);
}
else
miHighlight = new ToolStripMenuItem("Eintrag markieren", null, tsiHighlight_Click);
miHighlight.Tag = Rows[e.RowIndex];
miHighlight.Name = "miHighlight";
cms.Items.AddRange(new ToolStripMenuItem[] { miHighlight });
Rows[e.RowIndex].ContextMenuStrip = cms;
}
}
Frage 1:
Sollte der gesamte Code in eine Prüfung gewickelt werden, die zuerst prüft, ob das Kontextmenü nicht sowieso schon zugewiesen ist?
Das RowPrePaint-Ereignis greift ja nur für die zu zeichnenden Zeilen (=aktuell sichtbaren Zeilen) und wird doch also schlimmstenfalls für die gleichen Zeilen mehrmals aufgerufen, oder?
Frage 2:
Wie man sieht, geht es primär im obigen Beispiel darum, dass eine Zeilenmarkierung besteht und der Text sich danach richten muss.
Wäre es ein besserer Ansatz, auf das Ereignis RowContextMenuStripNeeded zu reagieren und das Menü dort erst zuzuweisen?
In diesem Fall "hätte" also die Zeile nicht ihr eigenes Kontextmenü, sondern bei Rechtsklick würde das einzige bestehende Kontextmenü mit ggf. angepasstem Text einfach angezeigt.
Jedoch kann ich nicht einfach bei einem AppFocusChanged das Element geöffnet behalten.
Doch.
Du kannst dann in dem einzelnen ItemClick Ereignis das ContextMenu per Codeanweisung schliessen.
Der Default wäre dann also, dass dein Kontextmenü bei AppFocusChanged immer aufbleibt und nur ausgewählte Klickereignisse das Schliessen selbst übernehmen.
Eine neue Datetime kann man nicht wieder zusammenbauen?!
doch, mit
DateTime d = new DateTime(jahr, monat, tag, std, min, 0)
übrigens hatte ich in meiner gruppierung die stunde vergessen, also:
select
datepart(year, Beginn) as Jahr,
datepart(month, Beginn) as Monat,
datepart(day, Beginn) as Tag,
datepart(hour, Beginn) as Std,
datepart(minute, Beginn) as [Min],
avg([die wertespalte])
from
meineTabelle
where
(irgendwelche sonstige kriterien)
group by
datepart(year, Beginn),
datepart(month, Beginn),
datepart(day, Beginn),
datepart(hour, Beginn)
datepart(minute, Beginn)
da SelectedRows keine Schreibeigenschaft ist bzw. nicht wie andere Kollektionen die Methode Add() anbietet, kannst du "analog dazu" nur für einzelne Zeilen beim Laden die Eigenschaft Selected bestimmter Zeilen festlegen:
dataGrid.Rows[6].Selected = true;
die betreffende zeile wird dann automatisch "mitglied" der SelectedRows-Kollektion.
mein ansatz ist halt zum einen, wenn mich mein kunde anruft und sagt: "Dies oder jenes funktioniert nicht", ist die Antwort "Seltsam, bei mir funktioniert es" für ihn nicht der Hinweis darauf, an dieser Stelle nicht "weiter zu forschen"...
Zum anderen ist es so, dass ich zum Beispiel in diesem Forum in den Bereichen, in denen ich mich fit glaube, aus Zeitgründen nur durch die Liste der offenen Fragen gehe (also: Antworten = 0), um zu sehen, ob ich da helfen kann.
Sehe ich aber, dass da schon jemand geantwortet hat, und dann auch noch ein Name da steht, der üblicherweise für hochqualifizierte Antworten steht (und da gibt es eben so ein paar Namen im Forum, zu denen eben imho auch Noodles gehört...), dann mache ich mir natürlich nicht mehr die Mühe, mich auch noch "einzumischen"...
Ich glaube, ich bin nicht der einzige, der so vorgeht.
Daher finde ich halt, dass mit "Seltsam, bei mir funktioniert es" dem Fragenden nicht nur wahrscheinlich nicht weitergeholfen wurde, sondern im schlimmsten Fall er so auch um weitere qualifizierte Antworten gebracht wird.
Wie gesagt, ist erstens ja nicht persönlich gemeint und zweitens nur meine bescheidene Meinung ;-)
primärschlüssel sollten nicht über mehrere informationen "breitgetreten" werden.
es ist vielleicht noch legitim, redundant spalten zu sprechenden merkmalen zusammenzusetzen, sie aber zur erkennung zu verwenden ist, wie du ja jetzt selber siehst, bedenklich.
wenn du selbst der datenarchitekt bist, dann nimm eine zählerspalte.
Zitat
Wie löst man das Problem, das eine Zahl nur einmal vergeben werden darf, auch wenn diese gelöscht wird?
ermittele einfach das maximum der spalte und addiere 1.
sql beispiel:
declare
@neuerWert int
SELECT @neuerWert = Max(meineSpalte) +1 FROM [meineTabelle]
Grundidee war, dass wir in fortgeschrittenen Programmiertechniken (das hiess fuer mich: Pattern, Design, Tipps rund um trickreichere Dinge wie Multithreading etc.) geschult werden.
Als ich in das Thema C# und .Net eingestiegen bin, habe ich ein einwöchiges sogenanntes "Camp" bei einer nicht näher genannten Firma besucht. Abgesehen von der inhaltlich eher oberflächlichen bis minderen Gesamtqualität ist mir davon nachhaltig folgende Situation im Gedächtnis geblieben:
Einer der (15) Schulungsteilnehmer fragte einen der über die Woche eingesetzten wechselnden drei Trainer, ob wir denn hier auch "best practices" (also: Tipps rund um trickreichere Dinge) vermittelt bekommen würden.
Die Antwort des Trainers war:
"Nun, das werden Sie hier natürlich nicht lernen, denn damit verdienen wir uns in den Projekten unser tägliches Brot".
Es gibt also tatsächlich die Einstellung von sogenannten "Seminarleitern", die wirklich aus der Praxis verwendbaren Kenntnisse aus Konkurrenzangst gar nicht vermitteln zu wollen.
Nachfrage
Ich bin selbst Trainer und Ausbilder von Fachinformatikern in freiberuflicher Kooperation.
In dem betreffenden Unternehmen haben wir selbst vor oben genanntem Hintergrund mehrfach versucht, einwöchige hochwertige C# Architect Camps zu einem echt guten Preis angeboten, die auch entsprechend beworben wurden, also: Einsatz von Entwurfsmustern, MVP, CFD und Microkernelarchitektur, uvm.
Die Nachfrage nach solch "Eingemachtem" als offenes Seminar scheint aber leider nicht dazusein; jedenfalls haben wir das Camp bis heute mangels Nachfrage nicht ein einziges Mal durchgeführt.
Mein Tip
Da mir die Vorträge von Ralf Westphal auf der Prio gut gefallen haben, habe ich kurzerhand im Dezember für einen unserer Auszubildenden Anwendungsentwickler und mich selbst einen eintägigen Workshop bei ihm gebucht.
Von diesem intensiven Arbeitstag zu dritt profitieren wir noch heute.
Ich kann also jedem Lernwilligen (und auch Arbeitgeber ebensolcher) empfehlen, sich eine Kapazität des gewünschten Fachs einfach ganz dediziert für einen festgelegten Zeitraum mit vorher abgestimmten Inhalten zu buchen - das bringt im Zweifelsfall (für übrigens nicht wesentlich mehr Geld) mehr Fachwissen ans Ziel.
ich würde mal tippen, der zeitpunkt der kontextmenüvervollständigung liegt nach der erstellung des datagrids, bzw. dessen füllung (RowsAdded-Ereignis), denn die row templates werden schon beim anlegen der zeilen verwendet.