BigBasti's Blog About Me & my Digital Lifestyle

19Aug/101

HowTo: Bilder als Links benutzen in ASP.NET MVC

In diesem Artikel geht es um eine eigentlich ganz simple Angelegenheit, nämlich Bilder-Links in ASP.NET MVC.  Um Links zu generieren wird hier eine HtmlHelper Klasse bereitgestellt, die die Links abhängig von der gewünschten Action und dem gewünschten Controller generiert, das ist eigentlich eine feine Sache, nur lassen sich damit leider keine Bilder-Links generieren.

Das Problem an der Sache ist, dass der HtmlHelper seine Ausgabe für HTML formatiert und somit einer Übergabe von "<img src="..." alt="..." />" als Linkname nicht verarbeitet werden würde, sondern direkt so ausgegeben.

Ich habe mich dann an Google gewendet und viele verschiedene Ansätze gefunden um das Problem zu lösen oder wenigstens zu umgehen. Hier gibt es allgemein gesagt zwei Lösungsansätze und man muss wohl selber entscheiden welches einem mehr Vorteile bietet und einem persönlich zusagt.

Ansatz 1: Den a-Tag und den img-Tag selber anlegen und die Route mit der UrlHelper-Klasse generieren. Hier ein paar Beispiele:


<a href="<%= Url.RouteUrl(">">
   put in <span>whatever</span> you want, also <img src="a.gif" alt="images" />.
</a>

<a href="<%= Url.Action(">">
   <img src="../../Content/Images/add_48.png" alt="" />
</a>

<%= Html.ActionLink("__IMAGE_PLACEHOLDER__", "Products")
.Replace("__IMAGE_PLACEHOLDER__", "<img src="\" alt="" />")%>

Alle diese Methoden funktionieren und erzeugen einen Link der ein Bild umschießt, doch in meinen Augen ist das eine nicht so schöne Methode, denn solche Links werden doch ziemlich oft generiert und da fände ich eine schöne Methode wie Html.ActionLinkWithImage schon angenehmer und lesbarer.

Ansatz 2: Eine Eigene Helper Methode erstellen die die Generierung für uns übernimmt:

Nach etwas mehr Suchen habe ich auch eine Extension Method in Stephen Walthers Blog gefunden. Diese sieht wie folgt aus (habe die Funktion noch um den Parameter Controller ergänzt):


public static string ImageLink(this HtmlHelper helper, string actionName,
    string controllerName, string imageUrl, string alternateText, object routeValues,
    object linkHtmlAttributes, object imageHtmlAttributes) {

    var urlHelper = new UrlHelper(helper.ViewContext.RequestContext);
    var url = urlHelper.Action(actionName, controllerName, routeValues);

    // Create link
    var linkTagBuilder = new TagBuilder("a");
    linkTagBuilder.MergeAttribute("href", url);
    linkTagBuilder.MergeAttributes(new RouteValueDictionary(linkHtmlAttributes));

    // Create image
    var imageTagBuilder = new TagBuilder("img");
    imageTagBuilder.MergeAttribute("src", urlHelper.Content(imageUrl));
    imageTagBuilder.MergeAttribute("alt", urlHelper.Encode(alternateText));
    imageTagBuilder.MergeAttributes(new RouteValueDictionary(imageHtmlAttributes));

    // Add image to link
    linkTagBuilder.InnerHtml = imageTagBuilder.ToString(TagRenderMode.SelfClosing);

    return linkTagBuilder.ToString();
}

//Benutzung:
<%= Html.ImageLink("Action", "Controller", "Pfad_zum_Bild", "alternativText", new { id = e.Id }, null, new { border = "0" })%>

Diese Funktion erledigt genau das was ich brauchte, sie generiert den benötigten Link und auch den IMG-Tag aus meinen übergebenen Informationen und sieht der Html.ActionLink() Methode dabei auch noch so ähnlich dass man gar nicht darauf kommt, dass es eine nachträglich eingefügte Extension ist ;-)

Falls ihr noch nach einer Möglichkeit nutzt das ganze auch mit streng typisierten Links zu nutzen solltet ihr in Mirkos Blog vorbeischauen, er hat auch dafür eine Extension Method gebastelt.

Ich bin mit dieser Lösung ganz zufrieden, doch interessiert es mich trotzdem, wie ihr das in euren Projekten handhabt und eure Links erstellt. Vielleicht habt ihr ja eine bessere Methode auf Lager.

17Aug/102

Add-On Perle: Visual Studio Productivity Power Tools

Wer mit Visual Studio 2010 arbeitet und Visual Studio Productivity Power Tools noch nicht kennt sollte schnellst möglich handeln und sich dieses Add-On installieren, denn es macht die Arbeit mit Visual Studio sehr viel angenehmer (kaum zu glauben dass das eigentlich möglich ist ;-) )

Diese Power Tools verbessern hierbei viele Kleinigkeiten, die den Arbeitsprozess angenehmer machen. Hier ein paar Beispiele:

  • STRG+Mausklick auf eine Variable befördert euch zu der Klasse
  • STRG+1/2/3 Bringen bequeme Sprungmöglichkeiten innerhalb der markierten Klasse
  • ALT+Pfeil hoch/runter verschiebt den markierten Text
  • Ein neuer Solution navigator
  • Ein verbesserter "Verweis hinzufügen" Dialog mit Suchfunktion
  • Farbige und pinnbare Tabs
  • und und und

Schnell laden, installieren und genießen! Ich kann schon jetzt nicht mehr ohne! :-)

16Aug/101

.NET: Mit Extension Methods arbeiten

Aus gegebenen Anlass möchte ich heute einen kleinen Artikel zu dem Thema Extension Methods in .NET schreiben, einfach nur weil es eine sehr simple Möglichkeit bietet sich das Leben zu erleichtern. Falls es euch nichts sagt, mit Extension Methods, die  es seit C# 3.0 gibt ist es möglich bestehende Klassen, sogar interne Core-Klassen wie Integer oder String mit eigenen Methoden zu erweitern.

Wieso das nützlich ist fragst du dich? Na ganz einfach, habt ihr schon mal die Methode String.toInt32() vermisst? Diese ist nur eine (sehr simple) Methode, die man häufiger gebrauchen könnte, die es aber nicht gibt. Diese könnte man sehr einfach mit einer Extension Method erweitern.

Als Beispiel möchte ich hier aber den Artikel von vor ein paar Tagen nehmen, wo wir eine Methode erstellt haben mit der man ein XmlElement in einem XmlDocument umbenennen konnte. Dies mussten wir machen, da die Klasse XmlDocument keine Methode dafür anbietet. Nun wollen wir mal die XmlDocument Klasse um diese Methode erweitern.

Das ganze funktioniert sehr einfach:


    public static class XmlDocumentExtension
    {
        public static bool RenameXmlElement(this XmlDocument doc,
                                            XmlElement oldElement,
                                            string newName) {
            try {
                //Neues XmlElement mit neuem namen anlegen
                XmlElement newElement = oldElement.OwnerDocument.CreateElement(newName);

                //Dem neuen XmlElement alle Attribute des alten Elements übergeben
                foreach (XmlAttribute a in oldElement.Attributes) {
                    newElement.SetAttributeNode((XmlAttribute)a);
                }

                //Dem neuen XmlElement alle Kinder Elemente des alten Elements anhängen
                foreach (XmlNode n in oldElement.ChildNodes) {
                    newElement.AppendChild(n.Clone());
                }

                oldElement.ParentNode.ReplaceChild(newElement, oldElement);
            } catch {
                return false;
            }

        return true;
        }
    }

Wir legen eine ganz normale Klasse an, diese kann heißen wie man will, ich habe sie hier nur zum besseren Verständnis so benannt. In der klasse legen wir nun die Funktion an um die wir unsere Klasse erweitern wollen. Hierbei ist wichtig, dass sowohl die Klasse als auch die Funktion als public und static markiert wird. Des Weiteren sollte man einen Verweis auf System.Code.dll setzen.

Bei der Deklaration der Funktion muss man dann angeben welche Klasse erweitert werden soll. Hier erweitern wir die Klasse XmlDocument weswegen vor diesem Parameter noch ein this steht. Dieser Parameter wird nur dazu benötigt und muss dann später bei dem Aufruf der Funktion nicht gesetzt werden.

Bild 1: Auch IntelliSense erkennt unsere Erweiterung an und bietet diese an

Natürlich bleibt die "original" Klasse XmlDocument unberührt von dieser Aktion und wird nur virtuell erweitert. Diese Erweiterung ist natürlich auch nur für das Aktuelle Projekt nutzbar.

Ich finde dieses Feature wirklich sehr nützlich und kann es euch deswegen auch nur empfehlen.

public static bool RenameXmlElement(this XmlDocument doc,
XmlElement oldElement,
string newName) {
try {
//Neues XmlElement mit neuem namen anlegen
XmlElement newElement = oldElement.OwnerDocument.CreateElement(newName);

//Dem neuen XmlElement alle Attribute des alten Elements übergeben
foreach (XmlAttribute a in oldElement.Attributes) {
newElement.SetAttributeNode((XmlAttribute)a);
}

//Dem neuen XmlElement alle Kinder Elemente des alten Elements anhängen
foreach (XmlNode n in oldElement.ChildNodes) {
newElement.AppendChild(n.Clone());
}

oldElement.ParentNode.ReplaceChild(newElement, oldElement);
} catch {
return false;
}

return true;
}

12Aug/107

Tod den Modulen in VB.NET

In diesem Beitrag möchte ich ein paar Worte über Module unter VB.NET verlieren. Wie ihr dem Titel vielleicht auch schon entnehmen könnt steh ich diesen nicht allzu freundschaftlich gegenüber. Deswegen möchte ich in diesem Artikel erklären warum man keine Module benutzen sollte.

Wenn man Module nicht benutzen sollte warum gibt es sie dann?

Module gibt es in VB.NET nur aus einem Grund, nämlich um VB6 Programmierern den Umstieg auf die .NET Plattform zu erleichtern. Denn .NET ist komplett Objektorientiert und hier haben Module keinen Platz. Aber um es den Entwicklern einfacher zu machen bestehende Projekte auf die .NET Plattform zu porten wurden die Module mitgenommen.

Modul, Klasse wo ist eigentlich der Unterschied?

Wenn man sich so ein Modul anschaut hat es eine Enorme Ähnlichkeit mit einer gewöhnlichen Klasse, unterscheidet sich aber dennoch gewaltig von ihr.

Im Prinzip sind Module auch Klassen, die aber vielen Beschränkungen unterliegen. Hier die Hauptpunkte:

  • Alle Methoden und Variablen eines Moduls sind automatisch Shared, was bedeutet, dass man auf diese Methoden/Variablen zugreifen kann ohne eine Instanz der Klasse bilden zu müssen.
  • Alle Methoden und Variablen eines Moduls sind in dem gesamten Projekt verfügbar und sind somit Global - was nicht im Sinne von OOP ist. Der Programmierer kann dabei direkt auf die Methoden und Variablen zugreifen, dies erzeugt das Bild von Globalen Objekten und steht dabei im Gegensatz zu dem Klassischen Objektzugriff Object.Member.
  • Module sind automatisch NonInheritable, was die Instanzierung verhindert, desweiteren kann ein Modul auch nicht mit weiteren Schnittstellen wie z.B.: Interfaces erweitert werden.
  • Module sind zur Laufzeit einzigartig. Das bedeutet, dass alle Programmteile immer auf die selben Werte zugreifen, anders als bei einer Klasse wo jede Instanz eigene Werte hat.
  • Ein weiterer Punkt ist, dass Module nicht nach Außen hin sichtbar sind und somit eine Wiederverwendung ausschließen, was im totalen Gegensatz der OOP ist.

Warum werden Module dann so häufig benutzt?

Im Normalfall ist es entweder Unwissenheit oder Faulheit, oder beides. Denn viele Einsteiger (und auch alte VB6 Hasen) haben Probleme damit das Objektorientierte Prinzip zu verstehen, und da kommen die Module wie gerufen, denn diese ersparen die korrekte Deklarierung, man muss keine Namespaces beachten, die Instanzierung kann man sich auch sparen und man muss sich nicht mit Properties herumschlagen! Also geht im Endeffekt alles schneller aber dafür wird lauter Spaghetticode erzeugt!

Schlusswort

Wenn du noch relativ neu in der Objektorientierten Programmierung bist oder ein umsteiger von VB6, lass dich nicht davon verleiten schnellen unsauberen Code zu schreiben. Lass dir lieber etwas mehr Zeit um das OOP Konzept zu verstehen und mach es dann richtig. Je länger man diesen Pakt mit dem Teufel eingeht, desto schwieriger wird es dann später die alten Gewohnheiten los zulassen.

Ein weiterer Punkt ist, dass es unter C# keine Module gibt, daher wird man spätestens dann Probleme bekommen wenn man an einem C# Projekt mitarbeitet und dann gezwungen ist sauberer zu programmieren!

   
Get Adobe Flash playerPlugin by wpburn.com wordpress themes