Laden...
O
onlinegurke myCSharp.de - Member
Student/Hilfswissenschaftler Dresdner in Karlsruhe Dabei seit 15.01.2007 778 Beiträge
Benutzerbeschreibung

Forenbeiträge von onlinegurke Ingesamt 778 Beiträge

29.03.2007 - 15:15 Uhr

Hallo,

ich wollte mal das Berichtsystem ausprobieren und bin dabei auf folgendes gestoßen

Mein Testbericht beinhaltet 6 Tabellen (Benutzer, Rollen, Rechte, und paarweise Kombinationstabellen). Da wollt ich mir mal zu jedem Benutzer die Rechte anzeigen lassen. Jeder Benutzer kann dabei mehrere Rollen und mehrere Sonderrechte haben, die Rollen bestehen wiederum aus mehreren Rechten. Mein Testbericht Report1 enthält nun für jeden Benutzer einen Unterbericht Report2, der wiederum ein Unterbericht Report3 für die Profile und einen Unterbericht Report4 für die Sonderrechte. Report3 enthält ebenfalls Unterberichte (Report4). Nu wollt ich meinen Testreport lokal laden.

Das hat auch erstmal gut funktioniert, aber er kann bereits den Report2 nicht laden, stattdessen steht da nur "Unterbericht kann nicht angezeigt werden".

Alle Tabellen hab ich dem ReportViewer schon gefüllt mitgegeben, und die Unterberichte per ReportViewer.LocalReport.LoadSubReportDefinition bekannt gemacht.

Woran kann das liegen?

Bin über jeden Tip dankbar...

29.03.2007 - 11:17 Uhr

nein

Environment.Exit(int)
29.03.2007 - 11:13 Uhr

Achso, Creator<T> ist ein Delegate, dass eine Instanz vom Typ T zurückgibt...

29.03.2007 - 11:11 Uhr

nein, die Seite kannt ich nicht. Danke für den Link.

Machs jetzt selber:
(Der Code ist orginal in VB.NET geschrieben, aber SharpDevelop hat's freundlicherweise übersettzt 🙂 )

using Microsoft.Reporting.WinForms;
using Microsoft.Reporting;
using System.Xml;
public class ReportManager : System.ComponentModel.Component
{

	public void Load(string ReportPath)
	{
		Viewer.LocalReport.ReportPath = ReportPath;

		IO.FileStream fs = new IO.FileStream(ReportPath, IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read);
		XmlReader xr = XmlReader.Create(fs);
		Dictionary<string, IDbConnection> conns = this.ReadConnections(xr);
		Dictionary<string, DataTable> tables = this.ReadQuerys(xr, conns);
		foreach (IDbConnection conn in conns.Values) {
			conn.Close();
			conn.Dispose();
		}
		xr.Close();
		fs.Dispose();

		foreach (KeyValuePair<string, DataTable> kv in tables) {
			Viewer.LocalReport.DataSources.Add(new ReportDataSource(kv.Key, kv.Value));
		}

		Viewer.RefreshReport();
	}

	public ReportManager()
	{
		conn_creates = new Dictionary<string, Creator<IDbConnection>>();
		conn_creates.Add("SQL", SQLKonstruktor);
	}

	private ReportViewer _viewer;
	private Dictionary<string, Creator<IDbConnection>> conn_creates;

	public ReportViewer Viewer {
		get { return _viewer; }
		set { _viewer = value; }
	}

	public Creator<IDbConnection> ConnectionCreator {
		get {
			if (conn_creates.ContainsKey(ProviderName))
			{
				return conn_creates(ProviderName);
			}
			else
			{
				return null;
			}
		}
		set {
			if (conn_creates.ContainsKey(ProviderName))
			{
				conn_creates(ProviderName) = value;
			}
			else
			{
				conn_creates.Add(ProviderName, value);
			}
		}
	}

	private Dictionary<string, IDbConnection> ReadConnections(XmlReader xr)
	{
		Dictionary<string, IDbConnection> functionReturnValue = null;
		functionReturnValue = new Dictionary<string, IDbConnection>();
		if (xr.ReadToFollowing("DataSources"))
		{
			while (xr.Read) {
				if (xr.NodeType == XmlNodeType.EndElement && xr.Name == "DataSources") break; // TODO: might not be correct. Was : Exit While
 
				((IDictionary<string, IDbConnection>)functionReturnValue).Add(ReadConnection(xr));
			}
		}
		return functionReturnValue;
		return functionReturnValue;
	}

	private KeyValuePair<string, IDbConnection> ReadConnection(XmlReader xr)
	{
		xr.ReadStartElement("DataSource");
		string key = xr.GetAttribute("Name");
		string prov = string.Empty;
		string connstr = string.Empty;
		while (xr.Read) {
			if (xr.NodeType == XmlNodeType.Element)
			{
				if (xr.Name == "ConnectionString")
				{
					connstr = xr.ReadElementString;
				}
else if (xr.Name == "DataProvider") {
					prov = xr.ReadElementString;
				}
			}
			if (xr.NodeType == XmlNodeType.EndElement && xr.Name == "DataSource")
			{
				if (this.conn_creates.ContainsKey(prov))
				{
					IDbConnection conn = this.conn_creates(prov).Invoke;
					conn.ConnectionString = connstr;
					return new KeyValuePair<string, IDbConnection>(key, conn);
				}
				else
				{
					return new KeyValuePair<string, IDbConnection>(key, null);
				}
			}
		}
		return null;
	}

	private Dictionary<string, DataTable> ReadQuerys(XmlReader xr, Dictionary<string, IDbConnection> Conns)
	{
		Dictionary<string, DataTable> functionReturnValue = null;
		functionReturnValue = new Dictionary<string, DataTable>();
		if (xr.ReadToFollowing("DataSets"))
		{
			while (xr.Read) {
				if (xr.NodeType == XmlNodeType.EndElement && xr.Name == "DataSets") break; // TODO: might not be correct. Was : Exit While
 
				((IDictionary<string, DataTable>)functionReturnValue).Add(ReadQuery(xr, Conns));
			}
		}
		return functionReturnValue;
		return functionReturnValue;
	}

	private KeyValuePair<string, DataTable> ReadQuery(XmlReader xr, Dictionary<string, IDbConnection> Conns)
	{
		xr.ReadStartElement("DataSet");
		string key = xr.GetAttribute("Name");
		xr.ReadStartElement("Query");
		string cmd = string.Empty;
		string ds = string.Empty;
		while (xr.Read) {
			if (xr.NodeType == XmlNodeType.Element)
			{
				if (xr.Name == "CommandText")
				{
					cmd = xr.ReadElementString;
				}
else if (xr.Name == "DataSourceName") {
					ds = xr.ReadElementString;
				}
			}
			if (xr.NodeType == XmlNodeType.EndElement && xr.Name == "DataSet")
			{
				if (Conns.ContainsKey(ds))
				{
					return new KeyValuePair<string, DataTable>(key, GetDataTable(Conns(ds), cmd));
				}
				else
				{
					return new KeyValuePair<string, DataTable>(key, new DataTable());
				}
			}
		}
		return null;
	}

	private DataTable GetDataTable(IDbConnection Connection, string Command)
	{
		DataTable functionReturnValue = null;
		functionReturnValue = new DataTable();
		IDbCommand cmd = null;
		try {
			if (!(Connection.State == ConnectionState.Open)) Connection.Open(); 
			cmd = Connection.CreateCommand;
			cmd.CommandText = Command;
			using (IDataReader dr = cmd.ExecuteReader) {
				functionReturnValue.Load(dr);
			}
			cmd.Dispose();
		}
		catch (Exception ex) {
			if ((cmd != null)) cmd.Dispose(); 
		}
		return functionReturnValue;
	}

	private IDbConnection SQLKonstruktor()
	{
		return new Data.SqlClient.SqlConnection();
	}
}

29.03.2007 - 10:59 Uhr

Ja, aber es gibt einen Performancegewinn > 0 und als Mathematiker bin ich glücklich damit, auch wenn der so im Bereich von Epsilon liegen dürfte. 🙂

29.03.2007 - 09:44 Uhr

Der ReportViewer wurde geschaffen, nachdem ein Haufen von Entwicklern
eine locale Version des ReportService gefordert hatten, und MS sich dann
entschieden hat, diese Version komplett von Datenbanken zu trennen.

Hm, nagut, dann ist klar, warum Microsoft das nicht implementiert hat, aber es ist nunmal so, dass man durch dieses Feature die Reporting Services auch in Verbindung mit anderen Datenbanken verwenden könnte (lokal). Das Design des ReportViewers lässt das auf jeden Fall zu, deswegen hab ich mich gewundert, warum das nicht geht. Es ist mir klar, dass MS diese Lücke dann offen lässt, aber es hätte ja sein können, dass andere mittlerweile diese Lücke geschlossen haben.

29.03.2007 - 09:26 Uhr

Das was du meinst sind reguläre Ausdrücke und die dazugehörigen Klassen sind dementsprechend im Namensraum System.Text.RegularExpressions und heißen Regex und Match 🙂

29.03.2007 - 09:24 Uhr

i=index (wie smilebey schon sagte)

j eigentlich aus mathematischer Sicht gar nicht, wegen verwechslungsgefahr zu i, was bei Handschrift schon mal vorkommen kann. Da eine Verwechslung aber aus informatischer Sicht ausgeschlossen werden kann (weil die Schrift auf dem Computer nun mal nicht so unleserlich ist), erfreut es sich bei Informatikern doch großer Beliebtheit

k weil es der nächste Buchstabe nach i ist, wenn man das j rauslässt

29.03.2007 - 09:15 Uhr

Das mit dem Namen hat ne andere, eigene Geschichte

Das Problem ist, so wie ich das sehe ist die ReportDefinitionLanguage auch für andere Datenbanksysteme als auschließlich für den MS SQL Server gedacht zu sein, jedenfalls würd ich vermuten, dass in der Zeile

<DataProvider>SQL</DataProvider>

auch was anderes stehen könnte, z.B.,

<DataProvider>Oracle</DataProvider>

dann ist der ConnectionString aber eben halt auch anders. Und wenn ich meinem SQL Server sage, er soll mir mal den Bericht öffnen wird wahrscheinlich wenig bei rauskommen. Was ich suche, ist eine Möglichkeit den Bericht lokal auszuführen und dabei die im Bericht definierten Abfragen zu verwenden

//edit: In der MSDN-Doku ist auch ausdrücklich erwähnt, dass man einen SQL Server 2005-Instanz verwenden muss

29.03.2007 - 08:59 Uhr

Ich weiss, dass ich das kann, ich hatte aber gehofft, dass es schon was vorhandenes gibt, was genau das macht, weil das nun mal eine absolut logische Aufgabe ist, die sich aus dem Design der ReportDefinitionLanguage ergibt. Das ist sowas von der Kategorie "Hätte der Logik nach im Framework enthalten sein müssen". Warum in aller Welt lädt der ReportViewer nicht einfach die Daten? Ist das ein Versionsproblem? Kann das vielleicht erst die nächste Version?

29.03.2007 - 08:51 Uhr

Aber um mit der Diskussion mit "" und String.Empty ein Ende zu setzen:
Es gibt einen unterschied, der liegt aber nicht in der Performance, sondern im Speicherverbrauch. String ist irgendwo auch ein stinknormales Objekt mit stinknormalen Referenzeigenschaften, d.h.,

String s = "";

erzeugt eine neue String-Instanz und referenziert diese, während

String s = String.Empty;

eine vorhandene Instanz referenziert.

Da Strings sowieso Immutable sind, gibt es also schlicht nur Vorteile (performancemäßig) von String.Empty
Aber: Der Compiler ist ja auch nicht doof, sodass alle Strings erstmal gepoolt werden, was folgendes verursacht:


String s1 = "";
String s2 = "";
String s3 = String.Empty;
Object.ReferenceEquals(s1,s2) //True
Object.ReferenceEquals(s1,s3) //False
Object.ReferenceEquals(s1,String.Empty) //False
Object.ReferenceEquals(s3,String.Empty) //True

29.03.2007 - 08:12 Uhr

Hallo,

Theoretisch steht in einem Reporting-Services-Report (*.rdlc) ja nicht nur das Layout des Reports, sondern da stehen ja eben halt auch alle Informationen drin, wie die Daten geladen werden sollen. Gibt es irgendein Steuerelemnt oder einen Wrapper für den ReportViewer, o.ä., der/das einen Report nicht nur Laden kann kann, sondern ihn auch mit seinen Daten verbindet

Schon mal Danke im vorraus

28.03.2007 - 15:39 Uhr

oder du lädst die Graphiken und setzt bei jedem einzelnen Button


            Button.BackgroundImage = <Image>;
            Button.BackgroundImageLayout = ImageLayout.Stretch;
            Button.FlatStyle = FlatStyle.Flat;
            Button.FlatAppearance.BorderSize = 0;

//edit: Aber letztendlich kommt's drauf an, wieviele derartige Buttons du hast und natürlich wie immer was genau du haben willst...

28.03.2007 - 08:57 Uhr

Also mit

Microsoft.VisualBasic.Split(String,Delemiter).Length-1

geht das auch für für Teilstrings, die Länger sind, als ein Zeichen...

//edit: Code-Tags vergessen

28.03.2007 - 08:29 Uhr

Wenn du Eigenschaften auswerten willst, die du zur Entwurfszeit nicht kennst (was weiss ich warum), dann mach das mit Reflection. Ist wahrscheinlich immernoch ineffizient aber allemal effizienter, als ein Script zu hosten. Und wenn du unbedingt Code kompilieren willst, dann mach das über CodeDom und über einen der Sprachkompiler (in C# Microsoft.CSharp.CSharpCodeProvider-Klasse)

27.03.2007 - 17:10 Uhr
  1. Musst du selber wissen, aber anders wird's kaum gehen. Bzw. musst mal probieren, bis zu welchem Laufindex du gehen musst...

  2. Bei ex ist die Ableitung ja wieder ex, sodass man, wenn man die Gleichung nach ex umstellt eine ziemlich gute Näherungsgleichung für ex rauskriegt:

ex~(Summe von i=0 bis sonstwohin)(<xi/i!)

Bei Sin(x) ist die Ableitung ja Cos(x), davon wieder -Sin(x) und so weiter, wenn du also eine Näherungsformel für die Umgebung von 0 berechnest hast du keine Probleme mit der Ableitung, weil die Periodisch ist (0;1;0;-1;0;1;-1;0...)

Mit einem Taylorpolynom 8. Grades kannst du so die Sinusfunktion auf

Sin(x)~x-1/6x^3+1/120x5-1/5720*x7 nähern können

//edit: 9 Minuten eher? 🤔

27.03.2007 - 16:02 Uhr

Die Lösung ist tatsächlich System.ComponentModel.Component, aber du hast wahrscheinlich die Option abgestellt, dass selbsterstellte Komponenten automatisch in der Toolbox zu sehen sind. Die beste Variante ist aber das manuell hinzuzufügen, dann kannst du auch den Platz ändern (Toolboxelemente auswählen-Dialog und dann Durchsuchen). Intern wird die generelle Sichtbarkeit in der Toolbox durch das ToolBoxItemAttribute gesteuert. Wenn du eine neue Komponente erstellst und diese von Component ableistest brauchst du dir allerdings keine Gedanken darüber zu machen, da Component bereits mit diesem Attribut gekennzeichnet ist. Bei bestimmten Komponenten ist der Wert dieses Attributes jedoch verstellt (z.B. TabPage), dann müsstest du das neu einstellen.

27.03.2007 - 15:08 Uhr

1/11 = 0 Rest 1 => 1 kenn ich nicht, also weiter
10/11 = 0 Rest 10 => 10 kenn ich nicht, also weiter
100/11 = 9 Rest 1 => 1 kenn ich, also ist die Periode 09

27.03.2007 - 12:40 Uhr

Ja, sollte die bessere Variante sein, zumal man sich damit auch die hässlichen komplexen Zahlen spart

Aber Taylor-Reihen sind im Allgemeinen sehr genau (um genau zu sein, beliebig genau, je nach dem, wie groß man den Parameter werden lässt), und absolute Genauigkeit kann man mit Decimal sowieso nicht erreichen...

27.03.2007 - 12:21 Uhr

@talla: "genauere Math. Methoden" schließen ja wohl die Exponentialfunktion mit ein. Die kann man aber allerdings wirklich auch wieder nur mit der Reihe nähern

27.03.2007 - 08:19 Uhr

Hier kannst du dir aber mit Mathematik aushelfen,

Sin(x)=(e^(ix)-e^(-ix))/2i; Cos(x)=(e^(ix)+e^(-ix))/2

//edit: i ist die imaginäre Einheit i der komplexen Zahlen, wenn du nichts über komplexe Zahlen weißt dann ist die Möglichkeit für dich wahrscheinlich nicht das richtige, dann nimm die Taylor-Polynome, ansonsten ist e^(ix) ist ein Punkt im Einheitskreis der Gaußschen Zahlenebene, der der Bogenlänge x zugeordnet ist

oder eine allgemeine Näherungsformel:

f(x)=(Das ist ein Summenzeichen von i=1 bis Unendlich)*(f i mal abgeleitet von x)/i!

oder schau mal unter
http://de.wikipedia.org/wiki/Taylor-Formel

26.03.2007 - 15:41 Uhr

Es geht, auch mit der Expressedition (weil der gesamte Code dafür im Framework enthalten ist)

Am einfachsten ist es, du erstellt eine Form, gehst dann in die Designerdatei (Form1.Designer.cs) und änderst die Vereerbung auf UserControl, fertig

26.03.2007 - 09:49 Uhr

Unter CodeProject gibts irgendwo so eine Komponente (such mal unter TallComponents.NET), die Thumbnailkomponente ist glaub ich sogar kostenlos..

23.03.2007 - 12:53 Uhr

Ich würds so machen wie alle Hierarchien im Framework gemacht sind, nämlich das jedes Element der Hierarchie sein übergeordnetes Element und seine untergeordneten Elemente kennt, also eine Eigenschaft Parent und eine Eigenschaft Childs als eigens definierte ChildCollection.

23.03.2007 - 12:22 Uhr

Seit Net 2.0 gibt es die SuppressIldasmAttribute Klasse, die ein disassemblieren eines Assembly verhindert!

Aber verhindert das wirklich, das das Disassemblieren gar nicht mehr geht? Mit den Bordmitteln geht's nicht mehr, ja. Und wenn es gehen sollte, dann ist es definitiv verdammt schwer, aber gar nicht?

23.03.2007 - 09:15 Uhr

Würd aber statt der 10000000 Timespan.TicksPerMilliSecond nehmen, das ist ne Konstante und damit sowieso schon gecacht (außerdem sowieso nur 10000, es war ja nach Millisekunden gefragt)

23.03.2007 - 09:11 Uhr

Danke!

23.03.2007 - 07:47 Uhr

Wenn man aber auch Benutzereingaben machen will, dann kann man nunmal nicht einmal eine generelle Einstellung treffen. Dann muss man jedes mal neu überlegen, was man braucht. Woher soll die CLR auch wissen, was eine Benutzereingabe ist?

22.03.2007 - 12:12 Uhr

Die Lösung ist allerdings trivial. Es geht nicht. Nur für Werttypen. Aber myClass ist kein Werttyp. Aber du kannst natürlich mit einer Schleife das Array durchlaufen und deinen Konstruktor jeweils aufrufen

22.03.2007 - 08:19 Uhr

10 Jahre akustische Gitarre, hab aber in letzter Zeit keine Zeit mehr, schade eigentlich

21.03.2007 - 16:40 Uhr

Es gibt auch zweidimensionale Arrays, aber die lassen sich nicht über Zeichenketten indizieren, sondern über Integer.

21.03.2007 - 16:35 Uhr

vorher
String.Replace(text,"&","(hier sollte ein Kaufmannsund stehen)")?

oder liest du aus einer Datei?

In dem Fall kannst du zur Not noch einen eigenen Stream dazwischenlegen

21.03.2007 - 16:32 Uhr

Du könntest auch eine Einzelinstanzanwendung machen, anschließend abfangen, wenn eine neue Instanz gestartet werden soll und da die Kommandozeile auslesen

21.03.2007 - 16:24 Uhr

oder
TextBox ableiten und IsInputChar überschreiben

21.03.2007 - 15:36 Uhr

Erg.ToString("#,##0.#")

21.03.2007 - 15:34 Uhr

Vielen Dank!

21.03.2007 - 08:38 Uhr

Naja, man kann ab und zu mal was vermuten und die Lösung erraten, was dann kein exponentieller Aufwand wäre

Allgemein kann man das nicht berechnen, weil die Zahlen mit denen man es bei der Entschlüsselung zu tun hat nicht normalverteilt sind (Bei normalverteilten Zahlen ist jede zweite Zahl durch 2 teilbar, bei der Faktorisierung von Zahlen, die bei einer Verschlüsselung verwendet werden wird das nicht so sein.), allein deshalb ist es ausgeschlossen, darüber Betrachtungen anstellen zu können

20.03.2007 - 16:36 Uhr

Wenn ich mal so frei sein darf, würd ich doch mal vermuten, hinter den Instanzen der Klasse Month stecken Monate. Warum in aller Welt sollte man dann den ==-Operator mit Object.ReferenceEquals() implementieren, das wär doch sowas von unintuitiv. Dezember ist nicht Dezember weil ist andere Instanz von Dezember...

20.03.2007 - 16:33 Uhr

@marsgk

An dieser Stelle kann ich nicht mit Source dienen, weil das eine Feinheit von C# ist, die ich nicht kenne (ich programmiere VB.NET). Aber der Tatsache geschuldet, dass C# und VB.NET vom Funktionsumfang immer mindestens identisch sind, gehe ich einfach mal davon aus, dass man das, was man in VB.NET umsetzen kann auch in C# umsetzen kann und die Programmiertechniken nicht so unterschiedlich sind. In VB.NET würde ich in etwa sowas schreiben:


Public Shared Overloads Operator =(arg1 as Month,arg2 as Month) as Boolean
  If arg1 [B]is[/B] Nothing Then return arg2 is Nothing
  Return arg1.equals(arg2)
End Operator

Public Overloads Function Equals(other as Month) as Boolean implements IEquatable(of Month).Equals
if other is nothing then return False
return Value.equals(other.Value)
End Function

20.03.2007 - 16:15 Uhr

object.ReferenceEquals()

Meiner Meinung nach dann aber lieber IEquatable<Month> implementieren und .equals() aufrufen, aber vorher testen wegen Null...

//edit: Verbessert auch die Datenverarbeitung der Klasse m.E. immens

20.03.2007 - 16:13 Uhr

wird schlecht gehen, das man Zahlen mit einer Genauigkeit weit über der von Double einliest, jedenfalls nicht ohne Verlust.

Mein Vorschlag wäre: Eigene Struktur schreiben, die überhaupt erstmal Zahlen dieser Komplexität aufnehmen kann, dann die Operatoren, dann die Parser usw. Gibt einen höchstwahrscheinlich ziemlich gigantischen Haufen Arbeit...

20.03.2007 - 16:07 Uhr

oder ArgumentNullException, hängt davon ab, wie du's haben willst...

20.03.2007 - 15:43 Uhr

@knub: Überschreiben ist an der Stelle m.E. das falsche Wort, du schreibst ja einen komplett neuen Konstruktor, der mit dem alten nichts zu tun hat, außer einem Aufruf...

20.03.2007 - 15:40 Uhr

hätt ich auch gedacht, ich kann mir beides vorstellen. Variante a wäre, es wird eine Instanz der Basisklasse erstellt, die dann irgendwo verkümmert und Variante b wäre, dass sämtlicher Speicher des unfertigen Objektes sofort wieder freigegeben wird...

20.03.2007 - 15:04 Uhr

Hallo,
mal ne technische Frage: Was passiert mit einer Instanz, deren Konstruktor einen Fehler auslöst? Wird sie entfernt? Hängt das damit zusammen, ob die Klasse IDisposable implementiert? Hab bisher nix gefunden...

20.03.2007 - 14:19 Uhr

...und ein damaliger IBM-Chef (hab den Namen vergessen) hat den weltweiten Markt für Computer auf "etwa 7" geschätzt, in der IT-Branche hat's schon ne Menge gewaltige Fehleinschätzungen gegeben...

20.03.2007 - 13:57 Uhr

PictureBox.SizeMode=Zoom bedeuted, dass das Bild in der PictureBox unter Beibehaltung der Seitenverhältnisse gestreckt wird (ohne Beibehaltung StretchImage), d.h, wenn du die PictureBox vergrößerst, vergrößert sich auch das darin befindliche Bild.

20.03.2007 - 13:08 Uhr
  1. PictureBox.SizeMode=Zoom
  2. Ich würd dir dringend empfehlen RoBitmaps von Robertico zu benutzen (hier)
20.03.2007 - 12:57 Uhr

Screen 96 und Drucker 75? Ist das immer so?

20.03.2007 - 10:16 Uhr

Hallo,
wie kann man die DPI-Einstellungen eines Rechners abfragen?

Hintergrund: Ich will eine Bitmap erstellen, die ausgedruckt genau die Größe eines A4-Blattes hat. Nu ist ein A4-Blatt 8,2*11,6 Inch groß, ich würde nur noch die DPI brauchen, um das in Pixel umzurechnen...

//edit: Ohne dabei ein Graphics-Objekt zu benötigen (woher kriegen wenn nicht stehlen)