Laden...

Wie kann ich im im DataGridView eine Doppel-Linien-Umrandung zeichnen?

Erstellt von OXO vor 3 Jahren Letzter Beitrag vor 3 Jahren 769 Views
O
OXO Themenstarter:in
86 Beiträge seit 2020
vor 3 Jahren
Wie kann ich im im DataGridView eine Doppel-Linien-Umrandung zeichnen?

Hallo,

ich würde gerne im DataGridView eine Doppel-Linien-Umrandung, wie im Screenshot in der aktuell selektierten Zelle zeichnen.

An sich dachte ich, dass ich das über einen Hatch-Brush realisieren kann, diesen dann dem Pen übergeben, aber das hat leider nicht so hingehauen, daher erst einmal wieder raus genommen.

Was mach ich denn beim Zeichnen falsch, dass das nur ein dicker Rahmen, statt Doppel-Linie ist?


private void dataGridView_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
	if (e.ColumnIndex == dataGridView.CurrentCell.ColumnIndex && e.RowIndex == dataGridView.CurrentCell.RowIndex)
	{                
		// Painting for selected Cells
		e.Paint(e.CellBounds, DataGridViewPaintParts.All & ~DataGridViewPaintParts.Border);

		using (Pen pen = new Pen(System.Drawing.Color.Red, 4))
		{
			Rectangle rect = e.CellBounds;
			rect.Width -= 2;
			rect.Height -= 2;
			e.Graphics.DrawRectangle(pen, rect);
		}

		e.Handled = true;
	}
}

J
61 Beiträge seit 2020
vor 3 Jahren

Benutzt du die korrekten Koordinaten?

Malst du mit einem dicken Stift?

O
OXO Themenstarter:in
86 Beiträge seit 2020
vor 3 Jahren

Die Koordinaten und die Dicke passen prinzipiell glaub. Nur, das Problem ist, dass im Screenshot in der Mitte ein weißer Strich/Bereich frei liegt und das bekomme ich irgendwie nicht hin.

Welchen Brush müsste ich denn dazu verwenden? Der Effekt beim Hatch-Brush war nur, dass meine ganze Linie innen gestrichelt war, aber nicht so in dem Effekt "Aussen-/Innen-Linie"


// Painting for selected Cells
e.Paint(e.CellBounds, DataGridViewPaintParts.All & ~DataGridViewPaintParts.Border);

using (Pen pen = new Pen(System.Drawing.Color.Black, 4))
{
	Rectangle rect = e.CellBounds;
	rect.Width -= 2;
	rect.Height -= 2;
	e.Graphics.DrawRectangle(pen, rect);
}

using (Pen pen = new Pen(System.Drawing.Color.White, 2))
{
	Rectangle rect = e.CellBounds;
	rect.Width -= 2;
	rect.Height -= 2;
	e.Graphics.DrawRectangle(pen, rect);
}

e.Handled = true;

Also irgendwie rechts drüben und unten will es nicht in die anderen Zellen rüber ragen.

Ein rect.Width += 2; rect.Height += 2; scheint es aber auch nicht wirklich zu bringen.

J
61 Beiträge seit 2020
vor 3 Jahren

Aus deinem Bild entnehme ich, dass die Startkoordinate (X,Y) nicht passt.

Ein bisschen Verschieben und die Größe anpassen, dann sollte es gut sein.

O
OXO Themenstarter:in
86 Beiträge seit 2020
vor 3 Jahren

Aus deinem Bild entnehme ich, dass die Startkoordinate (X,Y) nicht passt.

Ein bisschen Verschieben und die Größe anpassen, dann sollte es gut sein.

Das dachte ich auch, aber leider nicht ganz. Denn ändere ich mal nur beim äußeren Rechteck die Y-Koordinate ab, dass es nach unten geht und belasse das Rechteck bei, schneidet der das am unteren Rand der Zelle einfach ab, als ob die Zelle selbst der Begrenzer ist und es da dann gekürzt wird:


// Painting for selected Cells
e.Paint(e.CellBounds, DataGridViewPaintParts.All & ~DataGridViewPaintParts.Border);

using (Pen pen = new Pen(System.Drawing.Color.Black, 4))
{
	Rectangle rect = e.CellBounds;
	rect.Y += 2;
	rect.Width -= 2;
	rect.Height -= 2;
	e.Graphics.DrawRectangle(pen, rect);
}

//using (Pen pen = new Pen(System.Drawing.Color.White, 2))
//{
//    Rectangle rect = e.CellBounds;
//    //rect.X += 2;
//    //rect.Y += 2;
//    rect.Width -= 1;
//    rect.Height -= 1;
//    e.Graphics.DrawRectangle(pen, rect);
//}

e.Handled = true;

Erwartet hätte ich, dass sich das ganze Rechteck über die Zelle drüber legt.

F
10.010 Beiträge seit 2004
vor 3 Jahren

Wenn Du Y verschiebst, musst du natürlich die höhe um diesen Betrag zusätzlich ändern, also -4

O
OXO Themenstarter:in
86 Beiträge seit 2020
vor 3 Jahren

Das ist zwar richtig, aber das war erst mal Absicht und mich wundert es, dass es nicht nach unten raus gezeichnet wird. Es müsste ja unten über die Bottom-Linie raus laufen.

Die ersten Versuche mit DrawLine sind zwar besser, aber auch rechts raus wird die untere Linie nicht über den Rand in die Zelle rechts rein gezeichnet, obwohl ich da mal mit + 100 nen richtig langen Strich rein gezeichnet hab (hier mal für den Test mit roter Linie)


// Painting for selected Cells
e.Paint(e.CellBounds, DataGridViewPaintParts.All & ~DataGridViewPaintParts.Border);

// Top-Line
using (Pen pen = new Pen(System.Drawing.Color.Black, 3))
{
	int offset_X = 3;
	int offset_Y = -2;
	e.Graphics.DrawLine(pen, e.CellBounds.X + offset_X, e.CellBounds.Y + offset_Y, e.CellBounds.X - offset_X + e.CellBounds.Width, e.CellBounds.Y + offset_Y);                    
}

// Bottom-Line
using (Pen pen = new Pen(System.Drawing.Color.Black, 3))
{
	int offset_X = 3;
	int offset_Y = -2;
	e.Graphics.DrawLine(pen, e.CellBounds.X + offset_X, e.CellBounds.Y + offset_Y + e.CellBounds.Height, e.CellBounds.X + offset_X + e.CellBounds.Width, e.CellBounds.Y + offset_Y + e.CellBounds.Height);
}

using (Pen pen = new Pen(System.Drawing.Color.Black, 2))
{
	int offset_X = 3;
	int offset_Y = -2;
	e.Graphics.DrawLine(pen, e.CellBounds.X + offset_X, e.CellBounds.Y + offset_Y + e.CellBounds.Height, e.CellBounds.X + offset_X + e.CellBounds.Width, e.CellBounds.Y + offset_Y + e.CellBounds.Height);

	e.Graphics.DrawLine(pen, e.CellBounds.X + 1, e.CellBounds.Y - 2, e.CellBounds.X + 1, e.CellBounds.Y + e.CellBounds.Height + 2);
	e.Graphics.DrawLine(pen, e.CellBounds.X + e.CellBounds.Width - 2, e.CellBounds.Y - 2, e.CellBounds.X + e.CellBounds.Width - 2, e.CellBounds.Y + e.CellBounds.Height + 2);
}

using (Pen pen = new Pen(System.Drawing.Color.Red, 1))
{
	int offset_X = -3;
	int offset_Y = -1;
	// Top, Bottom
	e.Graphics.DrawLine(pen, e.CellBounds.X + offset_X, e.CellBounds.Y + offset_Y, e.CellBounds.X + e.CellBounds.Width + 2, e.CellBounds.Y + offset_Y);
	e.Graphics.DrawLine(pen, e.CellBounds.X + offset_X, e.CellBounds.Y + offset_Y + e.CellBounds.Height, e.CellBounds.X + e.CellBounds.Width + 100, e.CellBounds.Y + offset_Y + e.CellBounds.Height);
}

using (Pen pen = new Pen(System.Drawing.Color.Red, 1))
{
	int offset_X = -3;
	int offset_Y = -2;
	// Left, Right
	e.Graphics.DrawLine(pen, e.CellBounds.X, e.CellBounds.Y + offset_Y, e.CellBounds.X, e.CellBounds.Y - offset_Y + e.CellBounds.Height);
	e.Graphics.DrawLine(pen, e.CellBounds.X + e.CellBounds.Width - 2, e.CellBounds.Y + offset_Y, e.CellBounds.X + e.CellBounds.Width - 2, e.CellBounds.Y + e.CellBounds.Height + 2);
}

e.Handled = true;

Gibt es dafür eine Erklärung, dass das abgeschnitten wird? Liegt das zufällig daran, weil die nachfolgenden Zellen rechts und dann nach unten hin, alle ja auch durch das CellPainting laufen und damit dann irgendwas über meine Styles überschrieben wird?

O
OXO Themenstarter:in
86 Beiträge seit 2020
vor 3 Jahren

Hier der Effekt, wenn man die Zellen rechts daneben und darunter zeichnen lässt.
Das einzige was da noch fehlt, sind praktisch die Punkte der Dicke 1 in der rechten/linken ecke der Zelle, die links bzw. rechts unterhalb der Spalte vor der selektierten Spalte gezeichnet werden.

Also schon lustig das alles und ich glaube aktuell, dass mit meiner Vermutung richtig liege, dass das Grid von links oben nach rechts unten gezeichnet wird, und dass es daher bei den Zellen oberhalb bzw. links davon bis zur selben Row möglich war in diese Zellen rein zu malen und bei denen rechts bzw. darunter das Gemalte einfach später dann wieder übermalt wird, wenn diese Zellen gezeichnet werden.


if (e.ColumnIndex == dataGridView.CurrentCell.ColumnIndex + 1 && e.RowIndex == dataGridView.CurrentCell.RowIndex)
{
	// Painting for Cell right next to the selected cell
	e.Paint(e.CellBounds, DataGridViewPaintParts.All & ~DataGridViewPaintParts.Border);

	using (Pen pen = new Pen(System.Drawing.Color.Red, 2))
	{
		e.Graphics.DrawLine(pen, e.CellBounds.X, e.CellBounds.Y, e.CellBounds.X, e.CellBounds.Y + +e.CellBounds.Height);
	}

	e.Handled = true;
}
else if (e.ColumnIndex == dataGridView.CurrentCell.ColumnIndex && e.RowIndex == dataGridView.CurrentCell.RowIndex)
{
	// Painting for selected Cell
	e.Paint(e.CellBounds, DataGridViewPaintParts.All & ~DataGridViewPaintParts.Border);

	using (Pen pen = new Pen(System.Drawing.Color.Red, 3))
	{
		Rectangle rect = e.CellBounds;
		rect.X -= 1;
		rect.Y -= 1;
		e.Graphics.DrawRectangle(pen, rect);
	}

	e.Handled = true;
}
else if (e.ColumnIndex == dataGridView.CurrentCell.ColumnIndex && e.RowIndex == dataGridView.CurrentCell.RowIndex + 1)
{
	// Painting for cell below selected Cell
	e.Paint(e.CellBounds, DataGridViewPaintParts.All & ~DataGridViewPaintParts.Border);

	using (Pen pen = new Pen(System.Drawing.Color.Red, 2))
	{
		e.Graphics.DrawLine(pen, e.CellBounds.X, e.CellBounds.Y, e.CellBounds.X + e.CellBounds.Width, e.CellBounds.Y);
	}

	e.Handled = true;
}

4.931 Beiträge seit 2008
vor 3 Jahren

Gibt es dafür eine Erklärung, dass das abgeschnitten wird? Liegt das zufällig daran, weil die nachfolgenden Zellen rechts und dann nach unten hin, alle ja auch durch das CellPainting laufen und damit dann irgendwas über meine Styles überschrieben wird?

Ja genau, mittels CellPainting solltest du nur innerhalb der durch die DataGridViewCellPaintingEventArgs übergebenen Zelle zeichnen (da diese bei einem Refresh/Update intern für alle sichtbaren Zellen aufgerufen wird).

Du müßtest also je angrenzende Zelle unterschiedlich das Zeichnen durchführen (das ich persönlich jedoch vermeiden würde - falls beim Update doch nur einzelne Zellen neugezeichnet werden, so bleiben evtl. Reste vom Rahmen sichtbar).

O
OXO Themenstarter:in
86 Beiträge seit 2020
vor 3 Jahren

In der Zwischenzeit hatte ich das Malen schon mal fertig gemacht, aber ja, es gibt komische Effekte, wie Du sie beschrieben hast.

Im Screenshot sieht man links wie der Effekt ist, wenn ich auf eine Zelle klicke. Schaut alles sauber aus soweit. Rechts sieht man, was passiert, wenn ich mit den Cursor-Tasten herum navigiere.

Kann man diesen von Dir beschriebenen Effekt nicht los werden?
Auch beim ersten Laden des DataGridViews sind Zellen noch nicht gemalt und etwas zerhexelt. Denke mir immer, die Profi-Tools (wie z.B. Excel) müssen es ja auch irgendwie sauber zeichnen.


if (e.ColumnIndex == dataGridView.CurrentCell.ColumnIndex - 1 && e.RowIndex == dataGridView.CurrentCell.RowIndex - 1)
{
	// Cell left to selected cell row above
	e.Paint(e.CellBounds, DataGridViewPaintParts.All & ~DataGridViewPaintParts.Border);

	using (SolidBrush solidBrush = new SolidBrush(System.Drawing.Color.Red))
	{
		e.Graphics.FillRectangle(solidBrush, e.CellBounds.X + e.CellBounds.Width - 2, e.CellBounds.Y + e.CellBounds.Height - 2, 1, 1);
	}

	e.Handled = true;
}
else if (e.ColumnIndex == dataGridView.CurrentCell.ColumnIndex && e.RowIndex == dataGridView.CurrentCell.RowIndex)
{
	// Selected Cell
	e.Paint(e.CellBounds, DataGridViewPaintParts.All & ~DataGridViewPaintParts.Border);

	using (Pen pen = new Pen(System.Drawing.Color.Red, 3))
	{
		Rectangle rect = e.CellBounds;
		rect.X -= 1;
		rect.Y -= 1;
		e.Graphics.DrawRectangle(pen, rect);
	}

	using (Pen pen = new Pen(System.Drawing.Color.White, 1))
	{
		// Top, Bottom
		e.Graphics.DrawLine(pen, e.CellBounds.X - 2, e.CellBounds.Y - 1, e.CellBounds.X + e.CellBounds.Width, e.CellBounds.Y - 1);
		e.Graphics.DrawLine(pen, e.CellBounds.X - 2, e.CellBounds.Y + e.CellBounds.Height - 1, e.CellBounds.X + e.CellBounds.Width, e.CellBounds.Y + e.CellBounds.Height - 1);
	}

	using (Pen pen = new Pen(System.Drawing.Color.White, 1))
	{
		// Left
		e.Graphics.DrawLine(pen, e.CellBounds.X - 1, e.CellBounds.Y - 2, e.CellBounds.X - 1, e.CellBounds.Y + e.CellBounds.Height);
	}

	using (Pen pen = new Pen(System.Drawing.Color.White, 1))
	{
		// Right
		e.Graphics.DrawLine(pen, e.CellBounds.X + e.CellBounds.Width - 1, e.CellBounds.Y - 2, e.CellBounds.X + e.CellBounds.Width - 1, e.CellBounds.Y + e.CellBounds.Height);
	}

	e.Handled = true;
}
else if (e.ColumnIndex == dataGridView.CurrentCell.ColumnIndex + 1 && e.RowIndex == dataGridView.CurrentCell.RowIndex)
{
	// Cell right to selected cell, same row
	e.Paint(e.CellBounds, DataGridViewPaintParts.All & ~DataGridViewPaintParts.Border);

	using (Pen pen = new Pen(System.Drawing.Color.Red, 2))
	{
		e.Graphics.DrawLine(pen, e.CellBounds.X, e.CellBounds.Y, e.CellBounds.X, e.CellBounds.Y + +e.CellBounds.Height);
	}

	e.Handled = true;
}
else if (e.ColumnIndex == dataGridView.CurrentCell.ColumnIndex - 1 && e.RowIndex == dataGridView.CurrentCell.RowIndex + 1)
{
	// Cell left to selected cell, row below
	e.Paint(e.CellBounds, DataGridViewPaintParts.All & ~DataGridViewPaintParts.Border);

	using (SolidBrush solidBrush = new SolidBrush(System.Drawing.Color.Red))
	{
		e.Graphics.FillRectangle(solidBrush, e.CellBounds.X + e.CellBounds.Width - 2, e.CellBounds.Y, 1, 1);
	}

	e.Handled = true;
}
else if (e.ColumnIndex == dataGridView.CurrentCell.ColumnIndex && e.RowIndex == dataGridView.CurrentCell.RowIndex + 1)
{
	// Cell below selected cell, same column
	e.Paint(e.CellBounds, DataGridViewPaintParts.All & ~DataGridViewPaintParts.Border);

	using (Pen pen = new Pen(System.Drawing.Color.Red, 2))
	{
		e.Graphics.DrawLine(pen, e.CellBounds.X, e.CellBounds.Y, e.CellBounds.X + e.CellBounds.Width, e.CellBounds.Y);
	}

	e.Handled = true;
}
else if (e.ColumnIndex == dataGridView.CurrentCell.ColumnIndex + 1 && e.RowIndex == dataGridView.CurrentCell.RowIndex + 1)
{
	// Cell right to selected cell, row below
	e.Paint(e.CellBounds, DataGridViewPaintParts.All & ~DataGridViewPaintParts.Border);

	using (SolidBrush solidBrush = new SolidBrush(System.Drawing.Color.Red))
	{
		e.Graphics.FillRectangle(solidBrush, e.CellBounds.X, e.CellBounds.Y, 1, 1);
	}

	using (SolidBrush solidBrush = new SolidBrush(System.Drawing.Color.White))
	{
		e.Graphics.FillRectangle(solidBrush, e.CellBounds.X - 1, e.CellBounds.Y, 1, 1);
	}

	using (SolidBrush solidBrush = new SolidBrush(System.Drawing.Color.White))
	{
		e.Graphics.FillRectangle(solidBrush, e.CellBounds.X, e.CellBounds.Y - 1, 1, 1);
	}

	e.Handled = true;
}

4.931 Beiträge seit 2008
vor 3 Jahren

Zeichne doch besser den Doppel-Rahmen nur innerhalb einer Zelle (an Excel solltest du dich nicht 1:1 orientieren).

Hast du dir denn jetzt schon mal das SourceGrid angeschaut?

O
OXO Themenstarter:in
86 Beiträge seit 2020
vor 3 Jahren

Zeichne doch besser den Doppel-Rahmen nur innerhalb einer Zelle (an Excel solltest du dich nicht 1:1 orientieren).

Also Du meinst, die Zelle nach innen verkleinern? Aktuell lasse ich ja den Innenraum der Zelle gleich groß und male die Linien nach außen hin

Hast du dir denn jetzt schon mal das SourceGrid angeschaut?

Ja, auf die Seite bin ich gegangen und habe es mir auch mal heruntergeladen, aber war ehrlich gesagt nicht in der Lage, das zum Laufen zu bringen (https://archive.codeplex.com/?p=sourcegrid). Fertig gebaute Releases habe ich nicht gesehen, um es gleich zu benutzen. Dann wollte ich das über die *.sln öffnen (mit VS 2017 und auch VS 2019), aber da kommen Fehler.

Wie hast Du das gebaut bzw. zum Laufen bekommen?

4.931 Beiträge seit 2008
vor 3 Jahren

Das kannst du über NuGet zu deinem Projekt hinzufügen: SourceGrid 4.4.0.

PS: Ja, ich meinte nach innen verkleinert zeichnen.

W
955 Beiträge seit 2010
vor 3 Jahren

Das Originalbild sieht eher so aus dass eine dicke Linie gezeichnet wird die den Hintergrund invertiert. Man könnte vielleicht auch mal schauen ob man über das Grid ein extra "Selektierungs-Control" legt, aber es wird mgl. mühselig die Positionierung hinzubekommen.

O
OXO Themenstarter:in
86 Beiträge seit 2020
vor 3 Jahren

Das kannst du über NuGet zu deinem Projekt hinzufügen:
>

Ahh, danke für den Hinweis! Da hatte ich noch gar nicht geschaut.