Laden...

Forenbeiträge von typhos Ingesamt 243 Beiträge

21.11.2010 - 14:39 Uhr

Hallo,
mit "new" geht es natürlich. Aber dann hast du ja das Problem, dass die Eigenschaft nicht verwendet wird, wenn du irgendwas mit allen Controls machen willst (z.B. über die Controls-Collection eines Fensters) - dann wird ja die Standard-Enabled-Eigenschaft verwendet. Daher kam das für mich hier nicht infrage.

21.11.2010 - 12:25 Uhr

@ Björn: Ich habe jetzt noch die Behandlung des VisibleChanged-Events eingebaut.

@ chilic: Ein Ausblenden der Buttons kam in diesem Fall leider nicht infrage, weil der Nutzer sehen soll, dass es in bestimmten Modi noch weitere Funktionen gibt. Auch das Überschreiben bzw. Ändern der Enabled-Eigenschaft war nicht wirklich attraktiv, da diese Eigenschaft leider nicht überschrieben werden kann (zumindest nicht im Framework 2.0).

20.11.2010 - 12:04 Uhr

Danke für den Hinweis, das klingt logisch. Ich werde das so bald wie möglich noch nachrüsten 😃

20.11.2010 - 11:49 Uhr

Nachdem in einem Projekt die Anforderung auftauchte, auch bei deaktivierten Buttons Tooltips anzuzeigen, da man ja trotzdem gern wissen möchte, was der Button machen würde bzw. warum er im Moment deaktiviert ist, habe ich mich im guten alten Internet auf die Suche nach einer Lösung gemacht.

Das Problem ist ja, dass deaktivierte Controls keinerlei Mausereignisse auslösen bzw. behandeln und damit das Anzeigen eines Tooltips in diesem Zustand nicht möglich oder vorgesehen ist. Bei meiner Suche nach einer Lösung habe ich durchgängig nur einen Ansatz gefunden: Im Fenster (bzw. Parent-Control des Buttons) soll das MouseMove-Ereignis behandelt und damit ein Tooltip angezeigt werden, sobald der Cursor über den deaktivierten Button fährt.

Die Lösung erschien mir aber aus zwei Gründen nicht ideal:

  1. In dem Projekt, in dem die Anforderung aufgetaucht ist, gibt es etliche Fensterklassen ohne gemeinsame Basisklasse und die Lösung müsste daher in mehrere Klassen eingebunden werden.
  2. Mir erscheint der Ansatz auch wenig performant, bei jeder noch so irrelevanten Mausbewegung zu prüfen, ob sich der Cursor gerade über dem deaktivierten Button befindet.

Da es (glücklicherweise) nur eine Basisklasse für alle Buttons in dem Projekt gibt, habe ich im besten Fall also nach einer schnell zu implementierenden Lösung gesucht, die ich nur in dieser einen Klasse umsetzen bzw. einbinden muss.

Ich habe mir also überlegt, beim Deaktivieren eines Buttons ein transparentes Panel über den Knopf zu legen, welches den gleichen Tooltip erhält wie der Button selbst. Beim Aktivieren des Buttons wird das Panel wieder entfernt, sodass der Button auch wieder angeklickt werden kann.

Der Reihe nach:
Wie schon erwähnt, gibt es in dem Projekt bereits eine Basisklasse für alle Buttons, die unter anderem die Möglichkeit bereitstellt, einfach Tooltips anzuzeigen. Die (auf das Wesentliche reduzierte) Klasse sah dafür so aus:


public class MyTooltipButton : Button
{
	private Tooltip tt;

	/// <summary>
	/// Ermittelt den Text, der im Tooltip angezeigt werden soll, oder legt diesen fest
	/// </summary>
	[DefaultValue("")]
	public string Tooltip
	{
		get { return tt.GetToolTip(this); }
		set { tt.SetToolTip(this, value); }
	}
}

Um nun den Code der Klasse nicht unnötig mit Tooltip-bezogenen Dingen aufzublähen, habe ich eine Manager-Klasse erstellt, die sich um alle Dinge für das Anzeigen der Tooltips kümmert.
Wie bereits erwähnt, wird in dieser Lösung ein transparentes Panel verwendet, welches über den Knopf gelegt wird. Die Implementierung der Klasse für unsichtbare bzw. transparente Panels sieht dabei wie folgt aus:


class TransparentPanel : Panel
{
	public TransparentPanel()
	{
		this.SetStyle(ControlStyles.Opaque, true); // keinen Hintergrund zeichnen
	}

	protected override CreateParams CreateParams
	{
		get
		{
			CreateParams cp = base.CreateParams;
			cp.Style |= 0x20; // transparent
			return cp;
		}
	}
}

In der Manager-Klasse (im Beispiel: MyTooltipManager) brauchen wir nun 3 Objekte, um das Vorhaben umzusetzen: die Instanz des Buttons, eine Instanz des transparenten Panels und natürlich eine ToolTip-Instanz. Die Klasse bekommt also 3 Instanzvariablen, um diese Objekte zu halten, sowie einen Konstruktor, der die Instanz des Buttons entgegennimmt:


public class MyTooltipManager : IDisposable
{
	private Control ctrl;
	private ToolTip tooltip = new ToolTip();
	private TransparentPanel panel;

	public MyTooltipManager(Control ctrl)
	{
		this.ctrl = ctrl;
		// Benötigte Events des Controls registrieren
		ctrl.EnabledChanged += new EventHandler(ctrl_EnabledChanged);
		ctrl.VisibleChanged += new EventHandler(ctrl_VisibleChanged);
		ctrl.LocationChanged += new EventHandler(ctrl_LocationChanged);
		ctrl.SizeChanged += new EventHandler(ctrl_SizeChanged);
	}
}

Um das Ganze später bei Bedarf auch für andere Controls einsetzen zu können, habe ich hier gleich Control als Typ verwendet und nicht Button.
Wie im Code auch zu sehen ist, werden im Konstruktor diverse Ereignisse des Controls registriert. Einmal brauchen wir die Information, wenn das Control deaktiviert bzw. aktiviert wird, um das Panel einzufügen bzw. zu entfernen. Andererseits müssen wir wissen, wenn sich die Größe oder die Position des controls ändert, um das Panel dann ebenfalls zu skalieren oder eben zu verschieben. Außerdem müssen wir noch wissen, wenn das Control sichtbar wird, um dann ggf. im deaktivierten Zustand das Panel hinzuzufügen.
Die EventHandler dafür sehen so aus:


private void ctrl_EnabledChanged(object sender, EventArgs e)
{
	if (ctrl.Enabled)
	{
		RemovePanel();
	}
	else
	{
		// Panel nur hinzufügen, wenn das Control auch sichtbar ist
		if (ctrl.Visible)
		{
			AttachPanel();
		}
	}
}

private void ctrl_VisibleChanged(object sender, EventArgs e)
{
	// Panel einfügen, wenn noch nicht geschehen
	if (ctrl.Visible && !ctrl.Enabled && (this.panel == null || this.panel.Parent != this.ctrl.Parent))
	{
		AttachPanel();
	}
}

private void ctrl_LocationChanged(object sender, EventArgs e)
{
	if (this.panel != null)
	{
		this.panel.Location = this.ctrl.Location;
	}
}

private void ctrl_SizeChanged(object sender, EventArgs e)
{
	if (this.panel != null)
	{
		this.panel.Size = this.ctrl.Size;
	}
}

Ich denke, der Code bedarf keiner weiteren Erklärung. Die im EnabledChanged-Handler verwendeten Methoden AttachPanel() und RemovePanel() sehen folgendermaßen aus:


/// <summary>
/// Erstellt das Panel, falls noch nicht vorhanden, und legt es über das Control
/// </summary>
private void AttachPanel()
{
	if (this.panel == null)
	{
		this.panel = new TransparentPanel();
	}
	this.panel.Location = this.ctrl.Location;
	this.panel.Size = this.ctrl.Size;
	this.tooltip.SetToolTip(this.panel, this.tooltip.GetToolTip(this.ctrl));
	this.panel.Parent = this.ctrl.Parent;
	this.panel.BringToFront();
}

/// <summary>
/// Entfernt das Panel
/// </summary>
private void RemovePanel()
{
	if (this.panel != null)
	{
		this.panel.Parent = null;
	}
}

In der Methode AttachPanel wird das transparente Panel also erstellt (falls noch nicht vorhanden) und anschließend in Größe und Postion dem Control angepasst. Dann wird noch der Tooltip des Controls übernommen und das Panel in den Vordergrund geschoben, sodass es auch in jedem Fall vor dem Control platziert wird.
Wie im bisher gezeigten Quellcode schon ersichtlich, bekommt die Manager-Klasse noch eine Dispose()-Methode verpasst:


#region IDisposable Member
public void Dispose()
{
	Dispose(true);
}
#endregion

protected virtual void Dispose(bool disposing)
{
	if (disposing)
	{
		ctrl.EnabledChanged -= ctrl_EnabledChanged;

		ctrl.VisibleChanged -= ctrl_VisibleChanged;
		ctrl.LocationChanged -= ctrl_LocationChanged;
		ctrl.SizeChanged -= ctrl_SizeChanged;

		if (this.panel != null)
		{
			this.panel.Dispose();
		}
		this.tooltip.Dispose();
	}
}

Jetzt benötigen wir nur noch eine Möglichkeit, um den Text des Tooltips festzulegen, und schon haben wir alles, was wir brauchen:


/// <summary>
/// Ermittelt den Text, der im Tooltip angezeigt werden soll, oder legt diesen fest
/// </summary>
public string Tooltip
{
	get { return this.tooltip.GetToolTip(this.ctrl); }
	set 
	{ 
		this.tooltip.SetToolTip(this.ctrl, value);
		if (this.panel != null)
		{
			this.tooltip.SetToolTip(this.panel, value);
		}
	}
}

Damit ist die Manager-Klasse schon komplett. Jetzt muss diese nur noch in die am Anfang gezeigte Button-Klasse eingebunden werden.
Die "neue" Basisklasse für die Buttons des Projekts sieht dann so aus:


public class MyTooltipButton : Button
{
	private MyTooltipManager ttManager;

	public MyTooltipButton()
	{
		ttManager = new MyTooltipManager(this);
	}

	/// <summary>
	/// Ermittelt den Text, der im Tooltip angezeigt werden soll, oder legt diesen fest
	/// </summary>
	[DefaultValue("")]
	public string Tooltip
	{
		get { return ttManager.Tooltip; }
		set { ttManager.Tooltip = value; }
	}
	
	protected override void Dispose(bool disposing)
	{		
		if (disposing)
		{
			ttManager.Dispose();
		}
		base.Dispose(disposing);
	}
}

Das war's dann auch schon. Ein fertiges Beispiel-Projekt ist im Anhang zu finden. Über Meinungen und Verbesserungsvorschläge würde ich mich natürlich freuen!

edit: Behandlung des VisibleChanged-Ereignisses hinzugefügt

Schlagwörter: Tooltip, deaktiviert, disabled

18.06.2009 - 11:10 Uhr

Hallo,
ich habe eine Word-Vorlage, die Makros enthält. Diese nehme ich, um dann per MailMerge einen Serienbrief zu erstellen (per MailMerge.Execute()). Dann speichere ich das entstandene Zieldokument ab. Leider sind in dem Zieldokument die Makros aus der Vorlage nicht mehr drin.

Gibt es einen Weg, die Makros der Vorlage in das Zieldokument zu übernehmen? Oder kann ich per Interop die Makros aus der Vorlage auslesen und in das Zieldokument einfügen?

Vielen Dank für jede Hilfe!

19.05.2009 - 10:50 Uhr

Hi,
ich habe die Situation, dass ich ein Serienbriefdokument habe. Mithilfe der Methoden MailMerge.OpenDataSource(...) und MailMerge.Execute() wird die Datenquelle angebunden und die Seriendruckfelder werden aufgefüllt/ersetzt. Klappt auch bis hierher aller wunderbar.

Nun soll das Programm aber erweitert werden, sodass auch formatierter Text als Inhalt für die Seriendruckfelder dienen soll. Dazu gibt es im Programm RichTextBoxen zur Definition der formatierten Texte. Die RTF-Daten werden in der Datenquelle gespeichert.
Naiv wie ich war, dachte ich natürlich "Word kann doch mit RTF gut umgehen, das geht auch bei Seriendruckfeldern". Aber leider Fehlanzeige: Im "fertigen" Word-Dokument wird der RTF-Code als Klartext angezeigt.

Hat jemand eine Idee, wie ich RTF-Text per MailMerge einfügen kann, sodass die Formatierung auch richtig von Word übernommen wird?

Vielen Dank!

30.03.2009 - 11:44 Uhr

Hab ich mir fast gedacht. Dann muss ich wohl doch ein zweiteiliges AddIn basteln...

Danke für die Antworten!

29.03.2009 - 17:34 Uhr

Danke, ich hab einige interessante Dinge gelesen, die mir bestimmt auch weiterhelfen. Aber eins vermisse ich (vielleicht geht es ja auch gar nicht?):
Ist es möglich, mit .NET ein richtiges AddIn zu schreiben, was ein Menü oder einen Button in Notes einfügt - so, wie es mit Microsoft Office möglich ist?
Weiß dazu jemand was?

Ich hatte mit Notes noch nicht wirklich was zu tun, hab aber gelesen, dass man dort mit JavaScript oder einer anderen Sprache (ich glaub "Lotus Notes Script" heißt sie) so etwas machen kann. Damit könnte ich ja dann eine von mir erstellte .NET-Anwendung mit Parametern oder so aufrufen, die dann irgendwas macht. Lieber wäre mir aber, wenn ich "nur" eine Anwendung/DLL erstellen und installieren müsste statt eine Anwendung und ein Script in Notes.

Vielleicht ist ja sowas möglich. Wäre schön, wenn sich da jemand näher auskennt.

Danke!

28.03.2009 - 13:58 Uhr

Hi,
ich muss demnächst - falls möglich - ein AddIn für Lotus Notes erstellen, das eine gerade geöffnete E-Mail an ein externes Programm übergibt oder - besser noch - die E-Mail selbst in eine andere Datenbank (SQL Server) schreibt.

Ich habe schon im Netz gesucht und bin auf die interop.lotus.dll und interop.domino.dll gestoßen. Diese hab ich auch schon in eine Testprojekt eingefügt und ein wenig erkundet. Allerdings weiß ich nicht so wirklich weiter.
Hat denn schon mal jemand mit .NET für Lotus Notes entwickelt? Hat jemand Erfahrung mit AddIns bzw. der AddIn-Entwicklung für Lotus Notes? Geht das überhaupt mit den Interop-Assemblies?

Bin für jeden Tipp/Hinweis dankbar!

Grüße
typhos

26.02.2009 - 09:34 Uhr

Danke, das löst mein Problem.

25.02.2009 - 17:57 Uhr

Hallo,
ist es irgendwie möglich, die Non-Client-Area (in meinem Fall um Textfelder) komplett zu entfernen?

Ich hätte gern eine TextBox, die wirklich nur die ClientArea hat. Gibts da vielleicht eine Möglichkeit, evtl. mit CreateParams überschreiben oder so?

Vielen Dank schon mal im Voraus!

10.06.2008 - 14:48 Uhr
  1. Für jedes einzelne Objekt in dieser Gruppe ein einzelnes Move-Command,
    diese dann aber in einem Makro-Command kapseln. (schließlich soll mein Rückgängig machen jetzt nicht erst eins nach dem andern zurückhüpfen, sondern wieder alle als Gruppe)
    (Und das Makro-Command sorgt natürlich dafür, dass die Unter-Commands alle ausgrührt werden, also sogesehen mehr ein Command-Group-Command)

Hi,
ich würde diese erste Variante bevorzugen, weil du dieses Command-Group-Command dann nicht nur verwenden könntest, um die gleiche Aktion für mehrere Objekte zu gruppieren, sondern evtl. auch, um verschiedene Aktionen für ein Objekt zu kapseln, die in einem Command ausgeführt werden sollen, also eben so wie ein Makro.

16.05.2008 - 14:57 Uhr

Ich hatte gerade ein ähnliches Problem: den umgekehrten Weg von System.Type zu DbType. Der Vollständigkeit halber und falls es jemanden interessiert, hier die Methode die ich dafür erstellt habe:

public static DbType ConvertToDbType(Type type)
{
        string name = type.Name;
        DbType val = DbType.String; // Standard

        try
        {
            val = (DbType)Enum.Parse(typeof(DbType), name, true);
        }
        catch 
        { } // wenn keine Konvertierung möglich -> Standard zurückgeben

        return val;
}

Die Methode (zumindest so ähnlich) hab ich übrigens im MSDN-Forum gefunden. Sie sollte eigentlich bei den meisten Standardtypen funktionieren...

14.05.2008 - 16:14 Uhr

OK, das beruhigt mich. Und du hast mich verwirrt:

auch ganz ohne Overloading.

Wie denn? Müsste man denn nicht die ConvertFrom() bzw ConvertTo()-Methoden überladen, um von/zu mehreren Typen zu konvertieren?

14.05.2008 - 15:50 Uhr

Ja, stimmt natürlich. Es gibt ja Overloading 😁
OK, aber trotzdem müsste ich für alle Typen eine Methode schreiben, was ich ursprünglich eigentlich nicht wollte... Was Allgemeingültiges gibt es nicht? Warum ist Convert.ChangeType() nicht gut (vorausgesetzt, man behandelt die Ausnahmen angemessen)?

14.05.2008 - 14:56 Uhr

Danke für den Tipp und den Link.
Allerdings sehe ich den Nutzen (für mich) nicht. Der TypeConverter kann doch immer noch von einem Typ zu einem anderen konvertieren, oder nicht? Da bräuchte ich ja etliche Converter-Klassen, um meine Umwandlungen zu machen... das möchte ich nur sehr ungern.

Die Methode Convert.ChangeType scheint übrigens genau die zu sein, die ich gesucht habe... ich muss mich aber noch ein wenig mit den FormatProvidern rumschlagen, damit Datumsangaben und Zahlen richtig konvertiert werden können.

14.05.2008 - 12:09 Uhr

Warum willst Du überhaupt so verfahren?

Ich lese aus einer Datenbank Standardwerte verschiedenster (Basis-)Typen aus. Und die sind immer eine Zeichenkette - ist halt so gespeichert...

Nach dem Auslesen sollen diese Standardwerte natürlich bei Bedarf zugewiesen werden können. Und dazu muss ich sie konvertieren oder von mir aus auch parsen.
Ich wollte mir eben nur ersparen, eine lange if-else if-else Anweisung (oder auch switch) zu schreiben, um letztendlich doch irgendeinen Typen zu vergessen...

Daher hätte ich gern eine Methode, die "alle" Typen konvertieren kann.

14.05.2008 - 11:57 Uhr

Danke, das habe ich noch nicht probiert, weil ich dachte, die Methode führt nur einen Cast durch. Und ich kann ja String nicht in z.B. int casten...

Aber ich probier die Methode einfach mal...

14.05.2008 - 11:48 Uhr

Hallo,
ich möchte einen String in einen anderen Typ konvertieren. Ich habe den Zieltyp und man kann davon ausgehen, dass der String einen "passenden" Wert enthält.

Es kann sein, dass der String "100" ist und der Zieltyp int. Andererseits könnte der String "false" enthalten und der Zieltyp könnte in dem Fall boolean sein.

Gibt es vielleicht im Framework schon eine Methode, die so das kann oder fällt jemandem eine hübsche kleine Methode ein?

Oder gibt es wirklich keine andere Möglichkeit als so etwas:

public static object ConvertToType(string value, Type type)
{
    if (type.Equals(typeof(int)))
        return Convert.ToInt32(value, formatprovider);
    else if (type.Equals(typeof(bool)))
        return Convert.ToBoolean(value, formatprovider);
    ...
}
14.05.2008 - 11:33 Uhr

ja, es ist ganz offensichtlich, dass da einer oder einzelne am Werk sind, die einseitig die Einwohnerzahl vorantreiben. Ich weiß leider nicht so recht, was ich davon halten soll.

Mittlerweile glaube ich, dass da ein Bot geschrieben wurde oder zumindest was ähnliches. So schnell die Einwohnerzahl jetzt steigt (undNUR die Einwohnerzahl), kann es ja schon nicht mehr mit rechten Dingen zugehen...

02.05.2008 - 10:57 Uhr

Ich danke auch Dir, herbivore. Wenigstens hast Du konstistente Ergebnisse erhalten 🙂

Danke auch für die weiteren Varianten. Interessant, wie viele Wege (und das waren bestimmt noch nicht alle) es für so eine doch relativ simple Aufgabe gibt 👍

02.05.2008 - 08:38 Uhr

So, jetzt hab ich auch mal die Zeit gemessen und die Variante mit Replace und Längenvergleich von Golo noch dazugenommen:

Bei 1.000 Schleifendurchläufen

Split:

  • gefunden: 22000
  • Millisekunden: 45

Schleife:

  • gefunden: 22000
  • Millisekunden: 18

RegEx:

  • gefunden: 22000
  • Millisekunden: 60

Replace:

  • gefunden: 22000
  • Millisekunden: 33

Regex deutlich langsamer als die anderen...

Bei 10.000 Durchläufen:

Split:

  • gefunden: 220000
  • Millisekunden: 622

Schleife:

  • gefunden: 220000
  • Millisekunden: 238

RegEx:

  • gefunden: 220000
  • Millisekunden: 478

Replace:

  • gefunden: 220000
  • Millisekunden: 334

Hier ist Split erheblich langsamer, Regex bewegt sich im unteren Mittelfeld.

Bei 100.000 Durchläufen sieht es schon wieder anders aus:

Split:

  • gefunden: 2200000
  • Millisekunden: 2821

Schleife:

  • gefunden: 2200000
  • Millisekunden: 1996

RegEx:

  • gefunden: 2200000
  • Millisekunden: 4487

Replace:

  • gefunden: 2200000
  • Millisekunden: 6404

Hier ist plötzlich Replace viel langsamer und Split auf dem zweiten Platz.

Warum diese Schwankungen? Liegt es vielleicht nur an der wahrscheinlich unterschiedlichen Systemauslastung zum Zeitpunkt der Messung? Oder hat es wirklich mit der Anzahl der Durchläufe zu tun?
Jedenfalls war in meinen Tests die Schleifenvariante immer die schnellste. Die Methode mit unsicherem Code hab ich jetzt nicht probiert 😁

30.04.2008 - 15:05 Uhr

Wow! Danke für die ausführliche Erörterung 😁

Ein toller Service hier, wie immer 👍

Nochmals Danke!!

30.04.2008 - 13:36 Uhr

Hi,
ich habe Strings, in denen Punkte (".") vorkommen. Ich möchte wissen, wie viele Punkte im String enthalten sind, und das möglichst effizient, da das sehr oft gebraucht wird.

Meine Quick&Dirty-Methode macht Folgendes:

int count = meinString.Split('.').Length - 1

Ich denke mal, dass es wohl effizientere Möglichkeiten gibt, da hier ja erst ein Array erzeugt wird.

Ich bin mir nicht sicher, ob reguläre Ausdrücke effizienter sind oder ob es vielleicht irgendwas superschneller gibt, dass ich nur übersehen habe.

Danke für jeden Tipp!!

13.03.2008 - 10:13 Uhr

Ja, aber genau das wollte ich nicht... Aber ich habe nun eine andere Lösung gefunden: TemplateField. Das nutze ich dann in der Art:

<asp:TemplateField HeaderText="Bankleitzahl">  
                    <ItemTemplate>  
                     <asp:Label ID="Label1" runat="server" Text='<%# Eval("Bank.Blz") %>' />
                    </ItemTemplate>
                </asp:TemplateField>
12.03.2008 - 15:33 Uhr

Hi,
ich habe ein GridView, in dem ich mir automatisch die Eigenschaften einer Liste mit Bankverbindungsdaten anzeigen lasse.
Die Klasse hat die Eigenschaften KtoNr, KtoName, KtoOrt (die drei sind vom Typ String) und Bank (ist ne eigene Klasse mit den Eigenschaften Name, Blz usw.).

Gibt es eine einfache Möglichkeit, wie ich mir in der Liste auch den Namen und die Blz der Bank anzeigen lassen kann?
Ich dachte erst, es würde vielleicht so gehen:

 <asp:GridView ID="gvBankverbindungen" runat="server" AutoGenerateColumns="False">
            <Columns>
                <asp:BoundField DataField="KtoName" HeaderText="Konto Name" />
                <asp:BoundField DataField="KtoOrt" HeaderText="Konto Ort" />
                <asp:BoundField DataField="KtoNr" HeaderText="Konto Nummer" />
                <asp:BoundField DataField="Bank.Blz" HeaderText="Bankleitzahl" />
                <asp:BoundField DataField="Bank.Name" HeaderText="Name der Bank" />
            </Columns>
    </asp:GridView>

Aber so geht es leider nicht. Dann dachte ich an eine ToString()-Methode in Bank, die mir den Namen ausgibt. Dann könnte ich mit DataField="Bank" zumindest den Namen anzeigen. Aber dann habe ich immer noch nicht die Blz...

Kann mir bitte jemand dabei helfen?

13.12.2006 - 11:58 Uhr

OK, Danke. Und wie dann weiter?
OtherClass soll sowas wie eine Liste darstellen (nach außen). Das DataSet ist dabei die Datenquelle.
Wenn ich nun also MyClass.MyProperty[5].Test eingebe, dann passiert intern folgendes:

MyClass hat ein Property mit dem sinnvollen Namen MyProperty:

public MyProperty 
{
    get { return new OtherClass(ref myDataSet); }
}

Hier hab ich das ref schon mal mit eingebaut. Hiermit wird also der Konstruktor von OtherClass aufgerufen.
OtherClass besitzt dann auch einen Indexer, mit dem ich auf die Zeilen des DataSets zugreifen kann. Der Indexer gibt mir dann ein Objekt der Klasse ThirdClass zurück, welche ebenfalls das DataSet als Parameter erhält:


public this[int index]
{
    return new ThirdClass(myDataSet, index);
}

ThirdClass wiederum greift dann auf die ihr übergebene Zeile des DataSets zu und gibt durch ihre Properties die Zellen/Spalten der Zeile im DataSet zurück.

Das funktioniert wie schon gesagt auch alles. Dur wenn ich über die ebenfalls in der Klasse OtherClass bereitgestellten Methoden Add(), Remove() etc. das DataSet verändere, ändert es sich nicht in MyClass, wo es eigentlich gehalten werden soll.

Wenn ich dann also wie von Dir vorgeschlagen im Konstruktor ref verwende, gringt mir das also was? Am Ende des Konstruktors ist mit dem DataSet doch noch nichts passiert?!

13.12.2006 - 11:03 Uhr

Seltsamerweise funktioniert der ganze Spaß, wenn ich das DataSet schon in der ersten Klasse befülle und das befüllte DataSet an die 2. Klasse übergebe. In der 2. Klasse (OtherClass im obigen Beispiel) kann ich dann auch neue Zeilen hinzufügen, ändern oder löschen - funktioniert alles wunderbar: Es wird auch in der ersten Klasse entsprechend geändert.
Warum funktioniert es nicht, wenn ich ein leeres DataSet übergebe (also nicht null, sondern new DataSet()) ? Selbst, wenn ich in das DataSet eine Tabelle packe (egal, ob die leer ist oder die Struktur der Datenbanktabelle besitzt), funktioniert es nicht.

Weiß denn niemand, was hier schief läuft?

12.12.2006 - 12:08 Uhr

Ja, OK. Die Idee hatte ich auch schon, aber auch damit hat es nicht funktioniert 🙁

Das kommt mir sehr seltsam vor... oder/und ich hab ein Brett vorm Kopf 🤔

12.12.2006 - 11:45 Uhr

Hi,
Objekte - also auch DataSets - werden in C# ja soweit ich weiß per Referenz übergeben (genauer: die Referenz auf das Objekt wird als Wert übergeben).

Nun habe ich folgende Situation:
Ich habe eine Klasse, die eine Reihe von DataSets hält. Diese sind anfangs NULL.
Nun erzeuge ich aus dieser Klasse heraus Objekte anderer Klassen. Dabei übergebe ich eines der DataSets dem Konstruktor als Parameter. Ungefähr so:

private DataSet myDataSet;

public OtherClass MyMethod()
{
    return new OtherClass(myDataSet);
}

In der Klasse OtherClass nehme ich also das DataSet entgegen und fülle es mit Daten aus einer Datenbank:

public class OtherClass
{
    private DataSet myDataSet;

    public OtherClass(DataSet paramDataSet)
    {
        myDataSet = paramDataSet;
        // DataSet 'myDataSet' mit Daten befüllen
        FillDataSet();
    }
}

Funktioniert ja im Prinzip auch wunderbar. Nur leider ist myDataSet in der ersten Klasse danach immer noch NULL. Da nur die Referenz auf das DataSet übergeben wird, müsste doch myDataSet in beiden Klassen den gleichen Inhalt haben, weil sie beide auf das gleiche DataSet-Objekt zeigen, oder nicht?

Wo ist mein Denkfehler bzw. welche Lösungen gibt es?

Übrigens: Übergabe per ref oder out geht ja nicht, da ich in der Klasse OtherClass noch mehr Logik habe. ref und out würden ja bedeuten, dass ich am Ende des Konstruktors die geänderten DataSets für die Rückgabe fertig haben müsste...

28.11.2006 - 11:20 Uhr

Lass doch einfach mal das DataBind() weg...

24.11.2006 - 16:29 Uhr

Ja, danke für die Antworten. Durch Experimentieren habe ich das auch gerade herausgefunden. Ich habe die Button-Erzeugung ins Page_Init verschoben - nun geht es...

Schönes WE!

24.11.2006 - 15:43 Uhr

Oh, hier gibt es ja schon einen Thread mit dem gleichen Thema - hab ich wohl nicht ausreichend gesucht - SORRY, dass ich schon einen neuen Thread ersteltl hab!!

Ich habe genau das gleiche Problem. Kennt denn jemand eine Lösung?

24.11.2006 - 15:07 Uhr

Hallo!

Ich erzeuge im Page_Load verschiedene LinkButtons und registriere die Methode lnkBtn_Click für jeden:

LinkButton lnkBtn = new LinkButton();
lnkBtn.Text = "Test";
lnkBtn.ID = "lnkBtnTest";
lnkBtn.Click += new EventHandler(lnkBtn_Click);

In der Methode lnkBtn_Click lass ich mir zum Test nur eine MessageBox anzeigen. Aber beim Klick auf einen LinkButton geht er nicht in die Methode. Ein Postback wird zwar ausgelöst, aber mehr auch nicht.

Hab ich irgendwas vergessen oder falsch gemacht?

23.11.2006 - 10:18 Uhr

Original von Chris06
Laufen tut das sogar, nur geändert hat sich überhaupt nichts...

Was ich rausgefunden habe
(aus Artikel
>
)
Das kann so wohl nicht funktionieren, da ich ja viele verschiedene aspx Sites habe.
Und jede dieser Sites läd die masterpage neu.

Ich meinte damit ja auch, dass Du nur eine aspx Seite haben solltest, in der dann nur der Inhalt (im UpdatePanel) geändert wird, wenn Du auf eine andere Seite springst, wird natürlich die Masterpage auch neu geladen...

22.11.2006 - 08:39 Uhr

Um einen Teil/nur den Inhalt der Seite neu zu laden, musst du AJAX/ATLAS verwenden. Das mache ich auch und es funktioniert super. Stichwort: UpdatePanel

21.11.2006 - 11:55 Uhr

Wie gesagt, weiß ich es nicht genau. Aber der oben genannte Link ist nicht die einzige Progressbar bei codeproject. Ich hab dort auch schon eine gesehen, die noch viel mehr konnte (auch style-mäßig), aber die finde ich leider momentan nicht. Such dort mal ein bisschen...

21.11.2006 - 09:22 Uhr

Also ich habe mir die Seite "Syntax" bei dir angesehen. Und einige Sachen wie z.B. "var x as string" oder "if (var = xyz)" oder "for (i = 0 to 10)" erinnern weniger an Java/PHP/C# 😉

Aber ich finde das Projekt trotzdem interessant, werde mir das sicher noch genauer ansehen!

21.11.2006 - 09:12 Uhr

Weiß nicht, ob es mit der Standard-Progressbar geht, aber bei www.codeproject.com hab ich mal eine gesehen, die unter anderem auch das konnte.

edit:
Hier der Link: http://www.codeproject.com/cs/miscctrl/verticalprogressbar.asp

21.11.2006 - 08:09 Uhr

Interessantes Projekt!

Die Syntax ist an Java/PHP/c# angelehnt.

Die Syntax sieht mir aber eher nach VB aus, oder irre ich mich 🤔

16.11.2006 - 15:01 Uhr

Ich habe gerade meine Sortiermethode geändert. Und zwar habe ich das ebene.Sort() an das Ende der Methode verschoben:

private void SortiereEbene(List<MyTreeNode> ebene)
{
for (int i = 0; i < ebene.Count; ++i)
{
if (ebene[i].Children.Count > 1)
SortiereEbene(ebene[i].Children);
}
ebene.Sort();
}

Damit wird nun jede Ebene falsch herum sortiert.

String.Compare für sich genommen funktioniert natürlich richtig und wenn ich zwei Objekte vom Typ MyTreeNode vergleiche, bekomme ich auch das richtige Ergebnis.
Deshalb wundert es mich wirklich, dass das über die rekursive Methode oben nicht funktioniert.

Vorübergehend habe ich es so gelöst, dass ich das Ergebnis von MyTreeNode.CompareTo() einfach umkehre (-1 -> 1, 0 -> 0, 1 -> -1). Damit wird der Baum erstmal richtig dargestellt. Natürlich klappt das Vergleichen von zwei einzelnen MyTreeNode-Objekten nun nicht mehr richtig (umgekehrtes Ergebnis). Daher ist es für mich keine endgültige Lösung.

Weiß vielleicht jemand, warum die rekursive Methode Probleme macht?

16.11.2006 - 11:03 Uhr

Hallo,
ich habe mir mit Hilfe von List<> und einem eigenen Typ einen Baum gebastelt.
Der eigene Typ MyTreeNode ist wie folgt implementiert:

public class MyTreeNode
{
private MyTreeNode _parent = null;
private List<MyTreeNode> _children = new List<MyTreeNode>();
private string _name;

public MyTreeNode Parent
{
get { return _parent; }
set 
{ 
_parent = value;
if (value != null)
value.AppendChild(this);
}
}

public List<MyTreeNode> Children
{
get { return _children; }
set { _children = value; }
}

public string Name
{
get { return _name; }
set { _name = value; }
}

public void AppendChild(MyTreeNode newChild)
{
if (!_children.Contains(newChild))
_children.Add(newChild);
}

public int CompareTo(object treeNode)
{
if (treeNode == null)
return 1;
else
return String.Compare(((MyTreeNode)treeNode).Name, this.Name, StringComparison.CurrentCultureIgnoreCase);
}
}

So, nun fülle ich die Liste bzw. den Baum:

List<MyTreeNode> myTree = new List<MyTreeNode>();
MyTreeNode rootNode1 = new MyTreeNode();
rootNode1.Name = "2099";
myTree.Add(rootNode1);

MyTreeNode rootNode2 = new MyTreeNode();
rootNode1.Name = "2006";
myTree.Add(rootNode2);

Nach dieser Art und Weise baue ich mir folgenden Baum auf:

2099
----- Klasse 10
----- Klasse 06
---------- NH-KL-06-02
---------- NH-KL-06-01
----- Klasse 12
----- Klasse 11
---------- NH-KL-10-05
---------- NH-KL-10-02
2006
----- Klasse 04
----- Klasse 02
---------- NH-KL-02-07
---------- NH-KL-02-01
---------- NH-KL-02-02

So weit, so gut.
Nun möchte ich jede Ebene sortieren. Dafür gehe ich den Baum Ebene für Ebene durch und wende List<>.Sort() an, welche meine CompareTo()-Methode verwendet, also nach dem Namen sortiert.

Ich erwarte also das Ergebnis:

2006
----- Klasse 02
---------- NH-KL-02-01
---------- NH-KL-02-02
---------- NH-KL-02-07
----- Klasse 04
2099
----- Klasse 06
---------- NH-KL-06-01
---------- NH-KL-06-02
----- Klasse 10
----- Klasse 11
---------- NH-KL-10-02
---------- NH-KL-10-05
----- Klasse 12

Seltsamerweise erhalte ich aber das Folgende als Ergebnis:

2099
----- Klasse 12
----- Klasse 11
---------- NH-KL-10-02
---------- NH-KL-10-05
----- Klasse 10
----- Klasse 06
---------- NH-KL-06-01
---------- NH-KL-06-02
2006
----- Klasse 04
----- Klasse 02
---------- NH-KL-02-01
---------- NH-KL-02-02
---------- NH-KL-02-07

Das heißt also, dass nur die letzte (unterste) Ebene richtig sortiert wird, alle darüberliegenden genau falsch herum. Kann sich das jemand erklären?

Falls es von Interesse ist, hier noch meine Sortiermethode:

private void SortiereEbene(List<MyTreeNode> ebene)
{
ebene.Sort();
for (int i = 0; i < ebene.Count; ++i)
{
if (ebene[i].Children.Count > 1)
SortiereEbene(ebene[i].Children);
}
}

Sorry für den langen Beitrag!!

16.11.2006 - 08:09 Uhr

Hmm, auch wenn ich mir das schon fast gedacht habe, ist die Antwort nicht unbedingt die, die ich hören/lesen wollte X(
Gibt es vielleicht eine Möglichkeit, die DLL "anders" zu kompilieren bzw. zu konvertieren? Die DLL in C# neu zu erstellen wäre prinzipiell zwar möglich, aber ein riesiger (unerwünschter) Berg Arbeit 🙁

15.11.2006 - 14:00 Uhr

Hat denn wirklich niemand eine Idee, woran es liegen könnte? Ist die DLL fehlerhaft oder gar nicht zu gebrauchen oder kann der Fehler auch am Aufruf der Methode liegen?
Vielleicht noch ein paar Einzelheiten:
Die DLL, um die es geht, wurde mit Gupta/Centura frisch erstellt. Damit kenne ich mich zwar nicht aus, aber anscheinend werkelt beim Kompilieren auch irgendein C/C++ Compiler - zumindest stand da irgendetwas von "C++ Compiler".

Wenn ich die DLL im DependencyWalker öffne, wird mir die gewünschte Funktion auch in der "Export Function List" angezeigt. Weiterhin kenn ich die Parameter, die diese Funktion benötigt:

BOOL Funktion(HSTRING, BOOL, BOOL, LPHSTRING)

In meinem Projekt binde ich die Funktion so ein:

[DllImport("NAME.DLL")]
public static extern bool Funktion(string prm1, bool prm2, bool prm3, ref string prm4);

Beim Aufruf dieser Methode erhalte ich dann den besagten Fehler:

HRESULT: 0x8007045A Eine Initialisierungsroutine ist fehlgeschlagen.

Wäre wirklich toll, wenn mir doch noch jemand helfen könnte.

15.11.2006 - 10:37 Uhr

Das ist natürlich auch wieder wahr 😁

15.11.2006 - 10:29 Uhr

Original von herbivore
Ansonsten bin ich eh der Meinung, dass Ausdrucken in den meisten Fällen einen Nachteil bedeutet.
Kein Copy&Paste mehr (z.B. für Codebeispiele)

Keine Suchfunktion mehr

gedruckt = toter Text

Aber das wäre bei PDF ja noch gegeben.

15.11.2006 - 08:23 Uhr

Hi,
ich habe die DLL nun mal mit DependencyWalker geöffnet und festgestellt, dass sie noch von zig anderen DLLs abhängig ist. Gut, also habe ich mir die anderen DLLs auch besorgt und in das bin-Verzeichnis kopiert.
Anscheinend wird nun alles gefunden. Allerdings bekomme ich nun einen anderen Fehler:

"Eine DLL-Initialisierungsroutine ist fehlgeschlagen"

Was bedeutet das jetzt? Ist mein Aufruf der Funktion falsch oder stimmt etwas anderes nicht?
Wenn ich die DLL nun mit DependencyWalker öffne, fehlt zumindest keine DLL mehr, aber er markiert die MPR.DLL rot und gibt mir folgende Meldung:
"Warning: At least one module has an unresolved import due to a missing export function in a delay-load dependent module."
Die MPR.DLL ist doch eine Systemdatei, richtig? Die muss doch also in Ordnung sein 🤔

14.11.2006 - 16:07 Uhr

Hi,
ich versuche eine unmanaged DLL per DLLImport einzubinden. Beim Aufruf der eingebundenen Methode erhalte ich aber eine DllNotFoundException "Das angegebene Modul kann nicht gefunden werden".
Die DLL liegt aber im gleichen Verzeichnis wie die DLLs des Projekts (also im bin-Verzeichnis).
Kann er wirklich die DLL nicht finden oder liegt das an was anderem?

Vielen Dank schon mal!

13.11.2006 - 09:28 Uhr

Hmm, ja 😁

13.11.2006 - 09:14 Uhr

was man so gesehen auch als "designfehler" schon fast beschreiben könnte

Findest Du? Ich hab aber keine Ahnung, wie ich das anders lösen könnte?