Events in eigene WebUserControls (.ascx) einzubauen ist im Prinzip ganz einfach: 1: public event ClickEventHandler Clicked; 2: public delegate void ClickEventHandler(object sender, EventArgs e); 3: protected virtual void OnClicked(EventArgs e) 4: { 5: if (Clicked != null) 6: Clicked(this, e); 7: }
Man deviniert ein Event mit einem Eventhandler-Typ (Zeile1), definiert einen Delegaten für den Eventhandler (Zeile 2) und kann dann eine Methode definieren, die den Event auslöst. Diese Methode ruft man dann auf, wenn das Event ausgelöst werden soll.
Wenn man das UserControl in eine Seite einbaut kann man jetzt im CodeBehind ganz einfach einen Eventhandler auf den Event registrieren und fertig:
this.ucButton.Clicked += new ClickEventHandler(ucButton_Clicked);
Auch im Markup kann man den Event angeben, vorausgesetzt man hat den entsprechenden Eventhandler angelegt.
<uc3:ucButton ID="ucButton" runat="server" Text="Gross" ImageURL="~/Images/Status/GreenBox.png" OnClicked="ucButton_Clicked" /> Was bei mir aber nicht funktioniert, ist der Designtime-Support. Bei anderen Controls kann ich die Events im Property-Grid sehen und ich kann per Doppelclick auch einen Standard-Eventhandler einrichten und registrieren. Das geht bei mir nicht. Hat jemand dafür eine Lösung? Wenn ja, dann bitte her damit.
Sicher ein alter Hut, aber für mich war's gerade neu und ich finde das echt klasse. Mit CSS kann man Elemente auch mit einem Abstand zum rechten Rand positionieren. <DIV style="position:absolute; right:20px; top:350px; width:300px; height:150px;"></DIV> erzeugt ein DIV das immer exakt 20px vom Rechten Rand entfernt ist, auch nach einem Resize des Fensters. Genauc das was ich gerade brauche. Man muss dabei nur beschten, dass right offensichtlich die schwächste Einstellung ist, d.h. wenn left und width ebenfalls angegeben sind, wird right ignoriert. Wenn aber nur zwei der Werte angegeben sind, wird der dritte automatisch ermittelt, also z.B. bei left und right wird die Breite automatisch angepasst. Das selbe funktioniert natürlich auch mit top, bottom und height.
Im TFS 2008 hat Microsoft endlich die Lizenzbedingungen angepasst. Für folgende Aktionen wird nun keine CAL mehr benötigt: - Anlegen eines Workitems
- Anzeigen der Workitems, die ein Benutzer selbst angelegt hat
- Bearbeiten der Workitems außer Änderung des Status des Workitems
Damit ist es nun endlich möglich, Kunden etc. in das Projekt besser einzubinden, ohne dafür Unsummen für CALs auszugeben. adamga's WebLog : TFS for Defect Tracking! Licensing Change!!!
Bei unserem heutigen Treffen der .Net Developer-Group Ulm hatten wir einen Vortrag zum Thema SQL-Projekte. Dabei kam die Frage auf, ob man Daten einer Datenbank nicht in ein SQL-Skript exportieren kann, das dann alle Daten über Insert-Statements einfügen kann. Ich habe hierzu eine Lösung in Visual Studio 2008 gefunden und das geht so:
1.) Server Explorer öffnen und die entsprechende Verbindung rechts anklicken, dann "Publish to provider" auswählen.
2.) Dann die Datebank auswählen und darunter die Checkbox disablen (außer man will wirklich die Datenbank komplett scripten).
3.) Die nächsten Schritte sind dann soweit selbsterklären. In dieser Maske kann man dann auswählen, ob man Daten, Schema oder beides scripten möchte:
4. In dem erzeugten Script steht dan z.B. so etwas:
INSERT [dbo].[Customers] ([CustomerID], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax])
VALUES (N'ALFKI', N'Alfreds Futterkiste', N'Maria Anders', N'Sales Representative', N'Obere Str. 57', N'Berlin', NULL, N'12209', N'Germany', N'030-0074321', N'030-0076545')
INSERT [dbo].[Customers] ([CustomerID], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax])
VALUES (N'ANATR', N'Ana Trujillo Emparedados y helados', N'Ana Trujillo', N'Owner', N'Avda. de la Constitución 2222', N'México D.F.', NULL, N'05021', N'Mexico', N'(5) 555-4729', N'(5) 555-3745')
INSERT [dbo].[Customers] ([CustomerID], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax])
VALUES (N'ANTON', N'Antonio Moreno Taquería', N'Antonio Moreno', N'Owner', N'Mataderos 2312', N'México D.F.', NULL, N'05023', N'Mexico', N'(5) 555-3932', NULL)
INSERT [dbo].[Customers] ([CustomerID], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax])
VALUES (N'AROUT', N'Around the Horn', N'Thomas Hardy', N'Sales Representative', N'120 Hanover Sq.', N'London', NULL, N'WA1 1DP', N'UK', N'(171) 555-7788', N'(171) 555-6750')
INSERT [dbo].[Customers] ([CustomerID], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax])
VALUES (N'BERGS', N'Berglunds snabbköp', N'Christina Berglund', N'Order Administrator', N'Berguvsvägen 8', N'Luleå', NULL, N'S-958 22', N'Sweden', N'0921-12 34 65', N'0921-12 34 67')
INSERT [dbo].[Customers] ([CustomerID], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax])
VALUES (N'BLAUS', N'Blauer See Delikatessen', N'Hanna Moos', N'Sales Representative', N'Forsterstr. 57', N'Mannheim', NULL, N'68306', N'Germany', N'0621-08460', N'0621-08924')
INSERT [dbo].[Customers] ([CustomerID], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax])
VALUES (N'BLONP', N'Blondesddsl père et fils', N'Frédérique Citeaux', N'Marketing Manager', N'24, place Kléber', N'Strasbourg', NULL, N'67000', N'France', N'88.60.15.31', N'88.60.15.32')
INSERT [dbo].[Customers] ([CustomerID], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax])
VALUES (N'BOLID', N'Bólido Comidas preparadas', N'Martín Sommer', N'Owner', N'C/ Araquil, 67', N'Madrid', NULL, N'28023', N'Spain', N'(91) 555 22 82', N'(91) 555 91 99')
INSERT [dbo].[Customers] ([CustomerID], [CompanyName], [ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax])
VALUES (N'BONAP', N'Bon app''', N'Laurence Lebihan', N'Owner', N'12, rue des Bouchers', N'Marseille', NULL, N'13008', N'France', N'91.24.45.40', N'91.24.45.41')
Das Script lässt sich dann wunderbar in Datenbankprojekte einbauen und in der Quellcode verwqlten. Dies bietet z.B. eine gute Möglichkeit, um Testdaten für die Durchführung von Tests mit der jeweiligen Anwendungs-Version in der Quellcode-Verwaltung zu verwalten.
In Visual Studio 2005 funktioniert das leider nicht. Dort muss auf entsprechende Tools zurückgegriffen werden, z.B. den kostenlosen Oracle SQL Developer http://www.oracle.com/technology/products/database/sql_developer/index.html der übrigens auch mit SQL-Server funktioniert 
Das Problem:
Ich habe in C# ein Objekt vom Typ System.Drawing.Color. Dieses möchte ich in einen String-Konvertieren, den ich im HTML verwenden kann. Das funktioniert gut bei benannten Farben wie z.B. "red". Dort kann man Color.Name verwenden. Aber bei nicht benannten Farben liefert dies einen ARGB-Wert mit dem HTML nichts anfangen kann. Dehalb habe ich diese kleine Mthode geschrieben:
private string GetColorString(Color color)
{
if (color.ToKnownColor() != 0)
return color.Name;
else
return "#" + color.Name.Substring(2);
}
Wenn jemand eine einfachere Lösung weiss, einfach her damit!
Update:
Jürgen hat noch eine viel einfacher Lösung (siehe Kommentar) mit string htmlcolor = ColorTranslator.ToHtml(Color.Bisque) Kannte ich bisher noch nicht, aber man lernt ja nie aus!
Ein weniger bekannter Operator in C# ist der Operator ??. Damit kann ein Objekt auf null geprüft werden und wenn dies der Fall ist ein Alternativwert verwendet werden. Ein Beispiel kann das verdeutlichen: 1: object a = null; 2: object b = 5; 3: 4: object c = a ?? b;
In dem Beispiel gilt c = b. Würde in der Zeile 3 a noch entsprechend inizialisiert, dass dieses nut mehr null ist, dann würde gelten c = a.
Visual Studio 2008 liegt nun als RTM-Version zum Downloadf bereit. Wer keine MSDN-Subscription hat, kann sich hier die Trail-Versionen herunterladen. Visual Studio 2008 Trial Downloads
Ich habe bei mir eine Liste die wiederum eine Liste mit Unterobjekten enthält. Ich möchte nun daraus ein Element der Unterliste mit einer bestimmten ID selektieren. Eine klare Sache für LINQ! Als Leitfaden habe ich auf 101 LINQ Samples mir folgendes Beispiel rausgesucht: 1: public void Linq15() { 2: List customers = GetCustomerList(); 3: 4: var orders = 5: from c in customers, 6: o in c.Orders 7: where o.Total < 500.00M 8: select new {c.CustomerID, o.OrderID, o.Total}; 9: 10: ObjectDumper.Write(orders); 11: }
Das sieht ganz eifach aus, hat bei mir aber absolut nicht funktioniert. Ich konnte das schon nicht sauber eingeben, da er in Zeile 6 für c keine Intellisense-Unterstützung geboten hat. Das Ganze konnte ich dann lösen, indem ich das etwas umgestellt habe, auf das Beispiel oben übertragen sieht meine Lösung so aus:
1: public void Linq15() { 2: List customers = GetCustomerList(); 3: 4: var orders = 5: from c in customers 6: from o in c.Orders 7: where o.Total < 500.00M 8: select new {c.CustomerID, o.OrderID, o.Total}; 9: 10: ObjectDumper.Write(orders); 11: }
Ich habe einfach in Zeile 6 statt des Kommas in der vorherigen Zeile nochmals ein from eingebaut. So funktioniert es bei mir nun, wie ich mir das gewünscht habe.
Na wenigstens nimmt Visual Studio einen Absturz nicht auf die leichte Schulter sondern gibt zu, dass das eine Katastrophe ist. 
Damit Ich habe ein Web User Control bei dem ich eine TextBox als Property nach außen geben möchte, damit man die Eigenschaften der Textbox editieren kann. Das kann man durch ein paar Attribute erreichen. [Browsable(true),
NotifyParentProperty(true),
PersistenceMode(PersistenceMode.InnerProperty),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
RefreshProperties(RefreshProperties.Repaint)]
public TextBox DropDownTextbox
{
get
{
return this.TextBox1;
}
set
{
this.TextBox1 = value;
}
}
Damit werden auf dem UserControls zusätzliche Properties angelegt und zwar alle Properties einer Textbox mit dem Prefix "DropDownTexbox" also dem Namen des Properties auf dem Control.
Im Markup werden die Properties ganz normal als Attribute eingefügt. Was mich allerdings etwas gewundert hat war, dass ich im Markup über Intellisense die Textbox allerdings auch als separates Tag angeben kann und darauf meine Attribute definiere. Allerding wird das denn im Designer nicht mehr sauber gerendert.
<uc1:WebUserControl1 ID="WebUserControl11" runat="server" DropDownTextBox-BackColor="#FFCC00"> <DropDownTextbox BackColor="red"></DropDownTextbox> </uc1:WebUserControl1>
Der Team Foundation Server ist ein sehr flexibles Werkzeug. Es lässt sich an verschiedene Prozessmodelle anpassen. Die die beiden folgenden Links verweisen zu entsprechenden Kapiteln in der MSDN-Hilfe die beschreiben wie Workitem Typen und Prozessvorlagen angepasst werden können. Customizing Work Item Types Customizing Process Templates
LINQ erweitert ICollections, IEnumerable etc. mit einigen Extension Methods wie z.B. ToList() was sehr hilfreich ist. Ich hatte gerade das Problem, dass diese Extensions nicht im Intellisense angezeigt wurden. Nach einigem Suchen habe ich festgestellt, das lag daren, dass ich kein using System.Linq drin hatte, sondern nur auf System.Data.Linq und System.Data.Linq.Mapping. Nachdem ich das using ergänzt habe, funktionierte das problemlos.
Das alte Jahr ist noch nicht zu Ende undf schon verspricht das neue Jahr ereignisreich zu werden. Im Februar bin ich wieder auf Tour: 13. / 14. Feb. 2008 - VSOne in München Hier halte ich zwei Vorträge zu XML-Serialisierung und Architektur 19. / 20. Feb. 2008 - Launch Event Microsoft in Frankfurt Hier bin ich als ATE (Ask the Expert) zum Thema Visual Studio Team System 26. / 27. Feb. 2008 - BASTA! Sprint Edition in Frankfurt Auf der BASTA! werde ich zwei Vorträge zum Thema TFS halten. Weitere Details folgen noch. Ich würde mich freuen, den einen oder anderen Leser meines Blogs auf einem dieser Events persönlich kennen zu lernen.
Ich hatte gerade ein Aha-Erlebnis der etwas anderen Art. Im Infragistics-Chart gibt es eine Zoom-Funktion für die Achsen. Bei einem Composite-Chart scheint das aber nicht zu funktionieren. Ich habe folgendes im Code stehen: ChartObj.CompositeChart.ChartAreas[0].Axes[0]. Aber mein Intellisense zeigt kein passendes Property an. Im Forum steht auch die Aussage von einem Infragistics-Mitarbeiter, dass das nicht geht. Wenn ich dann "blind" das vervollständige zu ChartObj.CompositeChart.ChartAreas[0].Axes[0].ScrollScale.Visible = true;
funktioniert der Code wunderbar! Mal abgesehen davon, dass ich gar nicht wüsste, wie man Properties im Intellisense versteckt aber dennoch verfügbar macht, warum um alles in der Welt haben die Jungs dieses Property nicht öffentlich zugänglich gemacht?
Das Problem kennt vermutlich fast jeder Notebook-Besitzer der an seinem Arbeitsplatz noch einen zusätzlichen PC hat. Wenn man am Arbeitsplatz sitrzt steht das Notebook entweder nutzlos in der Ecke oder man kommt mit den Mäusen und Tastaturen immer durcheinander. Wäre es nicht schön, das Notebook am Arbeitsplatz zu integrieren. Unter XP hatte ich hier eine geniale Lösung - Maxivista. Damit konnte man sogar eine Zweischirmlösung aufbauen indem das Notebook einfach den Desktop des Arbeitsplatzrechners erweiterte. Absolut klasse, nur funktioniert der Host unter Vista nicht (zumindest nur mit den WDDM-Treibern, was für mich allerdings keine Alternative ist). Nun habe ich Synergy entdeckt. Dieses Opensource-Tool bitet die Möglichkeit, einen Rechner mit der Maus / Taststur eines zweiten Rechners fernzusteuern. Es unterschiedet sich zu Remote Desktop o. ä., indem es nicht den Bildschirm des PCs auf den Zweit-PC überträgt. Es lässt sich in meinem Szenario damit wunderbar nutzen. Ich habe auf meinem Desktop-PC Visual Studio laufen und kann dann einfach mit der Maus links zum Bildschirmrand rausfahren und schon bin ich auf meinem Notebook und kann damit mit der gleichen Tastatur / Maus z.B. Suchen im Internet, Downloads, E-Mail oder andere Funktionen aufrufen ohne dass mein Desktop-PC damit belastet wird. Das Ganze läuft auch problemlos unter Vista und ist zumindest mal ein brauchbarer Ersatz für MaxiVista.
Ich habe mir gerade ein kleines Beispiel für den Zugriff auf einen Webservice per JavaScript per AJAX zusammengebaut. Da ich hier einige Informationen aus verschiedenen Quellen zusammengetragen habe, möchte ich das Beispiel hier kurz posten, vielleicht hilft es dem einen oder anderen, einige Informationen gesammelt zu finden. Hier zunächst der Code für den Webservice: 1: namespace ValuePlanner_2008.Services 2: { 3: /// <summary> 4: /// Summary description for INNProjectExplorerWebService 5: /// </summary> 6: [WebService(Namespace = "http://tempuri.org/")] 7: [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] 8: [GenerateScriptType(typeof(myData))] 9: [ToolboxItem(false)] 10: [ScriptService] 11: public class INNProjectExplorerWebService : System.Web.Services.WebService 12: { 13: [WebMethod] 14: [ScriptMethod] 15: public myData HelloWorld(int ID) 16: { 17: return new myData { ID = ID, Text = "Hello World" + ID.ToString() }; 18: } 19: } 20: 21: public class myData 22: { 23: public int ID { get; set; } 24: public string Text { get; set; } 25: } 26: }
Kurz zu erwähnen sind hier folgende Details: In Zeile 10 wird über ein entsprechndes Attribut der Webservice für die Zusammenarbeit mit AJAX konfiguriert. Das selbe gilt in Zeile 14 für die Methode, die der Webservicebereitstellt. Da die Methode einen eigenen Datentyp (myData) zurückgibt, wird in Zeile 8 dieser Typ ebenfalls für AJAX veröffentlicht. Man kan so beliebig komplexe Datenstrukturen zwichen JavaScript und dem WebService austauschen, solange diese auf Datentypen basieren, dieJavaScript auch verarbeiten kann (also z.B. keine generischen Listen etc.). Der restliche Code wird automatisch über das Webservice Template erzeugt bzw. sollte keiner weiteren Erklärung bedürfen.
In der ASPX-Seite muss ein Scriptmanager eingebaut werden und der Service darauf registriert werden. Da ich de Scriptmanager in meinem Beispiel in der Master-Page habe, verwende ich einen ScriptmanagerProxy, der es erlaubt, die Registrierungen für einzelne Seiten vorzunehmen und an den Scriptmanager in der Master-Page weiterleitet. Dies ist deshalb notwendig, da auf einer Seite nur ein einziger Scriptmanager vorkommen darf.
1: <asp:ScriptManagerProxy ID="ScriptManagerProxy1" runat="server"> 2: | |