Archiv der Kategorie 'c#'

Hey, Hey, Wiki – welches Wiki paßt zu mir?

Ich will jetzt endlich auch einmal ein Wiki haben. Eines für mich und meine Kollegen.

Ein bissl rumgesucht und schon gefunden: ProntoWiki. Weil’s in C# geschrieben ist, eine gscheide SQL-Datenbank unterstützt und vor allem weil das Programm sehr übersichtlich ausschaut, so daß ich mir Änderungen und Erweiterungen selbst zutraue.

Hätte ich also nicht schon ein passendes Wiki gefunden – tja, dann müßte ich wohl bei WikiMatrix vorbeischauen. Hier kann man 88 Wikis miteinander vergleichen. Von SocialText bis TikiWiki (was für ein Name!). Und man kann suchen: will man eines in C# oder eines in Ruby? Ganz interessant ist hier die frei zusammenklickbare Suche über viele Kriterien.

wiki1.jpg

Naja, vielleicht schau’ ich doch nochmal vorbei und finde ein noch passenderes??
Mal schauen…

NULL-Werte in DropDownList

Eine DropDownList soll dynamisch mit Inhalten aus einer Tabelle (B) gefüllt werden. Der ausgewählte Index soll als Schlüssel in Tabelle (A) eingefügt werden.

Dies realisiert man relativ einfach durch Datenbindung. Dabei wird der SelectedValue des DropDownfeldes mit der Spalte in Tabelle (A) verknüpft:

dropdownlist1.jpg

Als Datenquelle für die Liste im DropDownList wird eine entsprechende DataSource gewählt:

dropdownlist2.jpg

Und schon klappts – Naja fast.

Will man nämlich auch „keinen Wert“ auswählen hat man ein kleines Problem. Denn der Wert „nichts“ (oder NULL) ist in der Tabelle (B) nicht enthalten. Versucht man nun einen Datensatz anzuzeigen, der in Tabelle (A) im Fremdschlüsselfeld den Wert NULL enthält, bekommt man folgenden Fehler:

selectedvalue, das ungültig ist, weil es nicht in der Elementliste vorhanden ist

Da in Tabelle (B) der Wert NULL nicht vorhanden ist, weiß das Programm nicht, welchen Wert es in der DropDownList anzeigen soll (weil es nicht in der Elementliste vorhanden ist). Um dennoch NULL-Werte (also nix) auswählen zu können ist folgende simple Erweiterung des DropDownList erforderlich:

Die Eigenschaft „AppendDataBoundItems“ des DropDownList wird auf True gesetzt. Damit „mischt“ man die statisch eingegebenen Einträge mit denen, die aus der DataSource kommen.

dropdownlist4.jpg

Für den NULL-Wert fügt man nun unter ITEMS einen Leer-Wert hinzu – und fertig ist das Ganze.

dropdownlist5.jpg

Nun besteht die Liste im DropDownList aus den Werten aus der Datenbank und einem einzelnen leeren Wert, den wir manuell hinzugefügt haben.

Wer braucht schon GridView.RenderControl() ?

Da habe ich mich stundenlang durchs Internet gequält um herauszufinden, dass GridView.RenderControl() nicht richtig funktioniert – und dabei ist es wieder mal relativ einfach. Wenn man’s denn selber macht!

Also „rendere“ ich mein GridView doch gleich selber – ich durchlaufe alle Zeilen und Spalten und bastle mir daraus eine kleine HTML-Tabelle. Fertig. Excel versteht das! Und das Ganze hat noch den Vorteil: ich weiß was da passiert – und kann meine HTML-Tabelle so anpassen wie ich will! Also z.B. jede zweite Zeile farbig markieren und ähnliche Scherze.
Warum eigentlich nicht gleich so?


    
public static string GetGridViewAsHTML(GridView gv)
    
/// Wandelt ein Gridview in eine HTML-Tabelle um
    {
        
int Spalten = gv.Columns.Count;
        
int Zeilen = gv.Rows.Count;
        
string ausgabe = „<table border=1><tr style=\“color:blue\“>“;
        
string wert = „“;
        
        
for (int s = 0; s < Spalten; s++)
        {
            ausgabe += 
„<th>“+gv.Columns[s].HeaderText + „</th>“;
        }
        ausgabe += 
„</tr><tr>“;

        for (int z = 0; z < Zeilen; z++)
        {
            
for (int s = 0; s < Spalten; s++)
            {
                wert = gv.Rows[z].Cells[s].Text;
                ausgabe += 
„<td>“ + wert + „</td>“;
            }
            ausgabe += 
„</tr><tr>“
        }
        ausgabe += 
„</tr></table>“;
        
return ausgabe;
    }

GridView.RenderControl() – oder wie ich lernte, Microsoft zu hassen…

Update: Problem umgangen – hier nachzulesen...

Eigentlich wollte ich nur ein GridView aus meiner ASP.NET-Anwendung nach Excel exportieren. Mehr nicht. Aber aus diesem Vorhaben wurde ein Unterfangen das mich lehrte, Microsoft zu hassen…

Aus ASP.NET kann man relativ leicht Daten nach Excel exportieren. Man muß nur die zu übertragenden Daten als HTML-Tabelle an Excel senden. Excel versteht diese HTMl-Tabelle und kann sie problemlos als Quasi-Excel-Sheet laden.

Und es ist auch ganz einfach ein Control – wie etwa ein GridView oder DataGrid – in HTML-Code umzuwandeln. Dazu gibt es in ASP.NET den Befehl RenderControl(StringWriter).

Such man im Internet nach Excel-Export und GridView bzw. DataGrid, findet man immer wieder Code-Beispiele, die diese beiden einfachen Dinge zusammenführen. Ein Grid wird nach HTML gerendert und als Excel-Anwendungsdaten zurückgeschickt.

Response.ClearContent();
Response.AddHeader(„content-disposition“, „attachment;
filename=MyExcelFile.xls“);
Response.ContentType = „application/excel“;
StringWriter sw = new StringWriter();
HtmlTextWriter htw = new HtmlTextWriter(sw);
TestGrid.RenderControl(htw);
Response.Write(sw.ToString());
Response.End();

Diese Code funktioniert einwandfrei – sofern man ein DataGrid verwendet. Dieses alte Grid wurde in Visual Studio 2005 bekanntermaßen durch das neue GridView abgelöst.

Wendet man nun den obigen Code auf ein GridView an – das ja sooo viel besser, genialer, revolutionärer ist als das DataGrid – erhält man diese Fehlermeldung:

Das Steuerelement ctl00_ContentPlaceholder1_TestGrid vom Typ GridView muss in einem Formulartag mit runat=server positioniert werden

Häähhh??
Natürlich befindet sich das GridView automatisch innerhalb eines Formulartags mit runat=“Server“ – schließlich hat VS 2005 den Code für mich generiert. Was bedeutet also diese sinnlose Fehlermeldung? Ich weiß es nicht.

Nach einigem suchen im Internet findet man dann heraus, dass diese Fehlermeldung ein Bug in VS 2005 ist, den man umgehen kann, wenn man folgenden, wunderbaren, logischen, selbsterklärenden und einfachen Code in seine aspx-Seite mit aufnimmt:

public override void VerifyRenderingInServerForm(Control control)
{

}

Jeder vernünftige Compiler den ich kenne würde solchen Code automatisch herauscompilieren. Nutzloser Code. Ohne Funktionalität. Ohne Sinn.

Und doch – läßt man das Programm mit dieser leeren Funktion laufen erhält man tatsächlich eine Excel-Tabelle, ohne jede weitere Fehlermeldung.

Naja, zumindest meistens. Nicht immer. Denn wenn das GridView weitere Controls enthält, wie z.B. Editierbuttons, Spalten mit Checkboxen, oder das Grid ganz einfach Sortierung und Paging erlaubt – dann kracht es erneut:

RegisterForEventValidation kann nur während Render() aufgerufen werden;

Aha. Logisch. Oder? Oder etwas nicht?
Ich kapiere es nicht – und suche mir wieder einen Wolf im Internet. Und finde heraus, dass diese Fehlermeldung umgangen werden kann, wenn man in die Seitendirektive folgenden Wert eingibt:

EnableEventValidation=“false“

Also:

<%@ Page Language=“C#“ EnableEventValidation=“false“ AutoEventWireup=“true“ CodeFile=“Default.aspx.cs“ Inherits=“_Default“ %>

Jetzt aber! Nun funktioniert der Export eines GridViews nach Excel. Hurra!

Ich habe ja auch nur gut 4 Stunden gebraucht, um all das herauszufinden.

Das regt mich an Visual Studio 2005 so unendlich auf. Man will was machen und findet sehr schnell im Internet entsprechende Lösungen bzw. Beispielcodes, wie etwas gehen könnte. Doch geht man dann in die Tiefe, taucht ein Problem nach dem anderen auf. Wie ein Dominoeffekt.
Nach dem Motto: „Hurra – ich bin eine Fehlermeldung weiter“ – nächster Level!! Yeahhh.

Um so ärgerlicher ist es, wenn man dann auch noch an Bugs von Microsoft scheitert. Wenn man einen Workaround für einen Fehler braucht, und wenn er nur aus einer leeren Routine besteht.

Doch manchmal habe ich den Verdacht, das sind gar keine Bugs. Das ist pure Absicht! Microsoft will ganz einfach in möglichst vielen Blogs von verzweifelten Entwicklern auftauchen! Das ist Microschufts Art, den Goolge-Page-Rank zu erhöhen! Jawohl! SEO (search engine optimization)) der ganz besonderen Art!

Jetzt klappts auch mit dem GridView

Vielleicht habe ich es jetzt kapiert. Zumindest tut mein Grid was es tun soll. Und alles ohne eine einzige Zeile Code….

Wie alles zusammenhängt – das habe ich mir mal aufgezeichnet. Auf die altmodische Art :-)

VS DataSet

Hoffentlich hat keiner meinen letzten Beitrag gelesen…

Es ist ja fast schon peinlich – aber die ganze Sortiererei-Geschichte hätte ich mir sparen können! Es geht ja doch ganz einfach! Und zwar so:

Man habe einen TableAdapter. Außerdem ein WebForm mit einem DataGrid. Nun füge man zum WebForm (neben das DataGrid) ein ObjectDataSource hinzu. Dieses verbinde man mit dem TableAdapter (das sich im DataSet befindet).

Hierauf verbinde man das GridView mit der ObjectDataSource (über die Eigenschaft DataSourceID des GridView) und lasse das Ganze mit mittlerer Hitze compilieren und laufen.

Und siehe da: plötzlich kann das Ding sortieren – und wie!

Und: plötzlich ist es auch wieder möglich per Klick-klick-Programmierung dem Grid eine Editierfunktion zu geben! Es klappt sogar – nur kommen die Daten noch nicht in der Datenbank an. Aber das werde ich auch noch kriegen…

Kann denn sortieren so schwer sein?

Mit VisualStudio ist alles ganz einfach. Man muß nur noch klicken. Nix mehr programmieren. Soll etwa ein GridView Daten sortieren muß man nur noch „AllowSorting“ anklicken – fertig!

Oder etwa doch nicht? Nunja, das „Programming by clicking“ funktinoiert unbestritten – aber nur, wenn man sich haargenau an die Vorgaben hält. So funktioniert das Sortieren nur dann, wenn das Grid mit der „richtigen“ Datenquelle verbunden ist. Holt man sich die Daten aber (wie ich) über die DataSource-Eigenschaft (z.B. mit einem TableAdapter), dann zerbricht die schöne heile Klicky-Welt.

Dann geht die Suche los: wie muß ich das jetzt programmieren? Was? Etwa mit der Tastatur? Nicht mit der Maus? Neeein!

Es ist gar nicht so einfach, hier mit der Hilfe und dem Web eine Lösung zu finden. Man darf nämlich nicht einfach einen TableAdapter verwenden – nein, es muß schon eine DataView sein. Denn nur die hat eine Sortierfunktion, der TableAdapter nicht!

Und es reicht auch nicht, diesem DataView zu sagen, was es wie sortieren soll:

(GridView2.DataSource as DataView).Sort = e.SortExpression+" "+Sort;

man muß dem Grid auch jedes Mal auf’s neue erklären, dass es sich an diese DataView binden soll!

GridView2.DataBind();

Dafür sortiert das Ding dann aber auch – doch nur in eine Richtung. Nämlich aufsteigend. Will man bei erneutem klicken der Spalte absteigend sortieren, dann wird’s schon wieder komplizierter. Denn dann muß man sich den aktuellen Sortierstatus im ViewState merken!

Ahhhh….

So hechelt man von einem Problem zum anderen. Und immer wieder stolpert man über so wunderschöne Fußangeln wie z.B. mit der SortDirection! Die hat den Wert „ascending“ und „descending“. Wunderbar! Logisch!

Aber die DataView.Sort – Methode kennt so was natürlich nicht, die braucht ein ASC bzw. ein DESC als Stringwert. Also muß man das wieder manuell umwandeln..

string Sort;
if (e.SortDirection == SortDirection.Ascending)
Sort = "ASC";
else Sort = "Desc";

Ach, ich weiß nicht. Mit .NET wird alles so kompliziert und umständlich. Was mit einer gscheiden Programmiersprache (Delphi !!) mit einem Objekt erledigen kann, muß man in .NET mit mindestens 3 Objekten und über 5 Ecken machen!! So unschön…

Aber dafür kann mein Grid jetzt auch sortieren. Ich habe ja nur gut 4 Stunden gebraucht um das alles herauszufinden.

Aber vielleicht liegt das ja auch nicht am .NET – vielleicht bin ich einfach nicht fürs Programmieren geschaffen und zu dämlich dafür…

protected void GridView2_Sorting(object sender, GridViewSortEventArgs e)
{
// Erst mal prüfen, ob ich mir schon eine SortExpression gemerkt habe
if (ViewState["SortExpression"] != null)
{
if (((string)ViewState["SortExpression"] == e.SortExpression) &
((SortDirection)ViewState["SortDirection"] == e.SortDirection))
//wenn ich mir die gleiche Sortierung schon gemerkt habe, dann muß
//ich die Sortierrichtung ändern
{
if (e.SortDirection == SortDirection.Ascending)
e.SortDirection = SortDirection.Descending;
else e.SortDirection = SortDirection.Ascending;
}
}
 
// Da das DataView mit "Ascending" und "Descending" nichts anfangen kann
// sondern ein ASC oder DESC braucht, muß man das erst noch umwandeln.
string Sort;
if (e.SortDirection == SortDirection.Ascending)
Sort = "ASC";
else Sort = "Desc";
 
//Endlich kann ich sortieren!
(GridView2.DataSource as DataView).Sort = e.SortExpression+" "+Sort;
GridView2.DataBind();
 
//Und hier noch die aktuelle Sortierung merken, fürs nächstemal
ViewState.Add("SortExpression", e.SortExpression);
ViewState.Add("SortDirection", e.SortDirection);
}


 

November 2009
M D M D F S S
« Jul    
 1
2345678
9101112131415
16171819202122
23242526272829
30  

Kategorien