Arbeitsblatt: Aufgaben zur Vorbereitung Dieses Arbeitsblatt enthält Aufgaben, die der Vorbereitung auf das Praktikum dienen. Die Aufgaben müssen bis zum 09.03.2011 bearbeitet werden. Die Ergebnisse werden am 10.03.2011 präsentiert. Die Bearbeitung erfolgt individuell. Die Aufgaben dieses Arbeitsblatts decken die im Praktikum betrachteten Arbeitsbereiche ab: Web Services Add-In-Entwicklung Windows Presentation Foundation Verknüpfung von Add-In-Entwicklung und WPF Hinweis: Bei der Bearbeitung der Aufgaben kommt es nicht auf optimale oder besonders schöne Lösungen an, sondern auf das Erlernen der Handhabung der jeweiligen Techniken. Aufgabe 1: Web Services Erstellen Sie einen ASP.NET WebService (Achtung: Template in Visual Studio 2010 ist nur für.net 3.5 und kleiner verfügbar). Der WebService soll das Anlegen und Abfragen von Projekten ermöglichen. Ein Projekt besteht der Einfachheit halber nur aus Projektnamen, Anfangsdatum, Enddatum. Sie können dafür folgende Klasse verwenden: public class Project public Project() //Notwendig für Serialisierung public Project(string projectname, DateTime startdate, DateTime? enddate) ProjectName = projectname; StartDate = startdate; EndDate = enddate; public string ProjectName get; set; public DateTime StartDate get; set; public DateTime? EndDate get; set; Aufgabe a) Implementieren Sie folgende Web-Methoden: [WebMethod] public Project[] Projects() [WebMethod] public bool Update(Project project) [WebMethod] public bool Add(Project project) Liefert alle am Server gespeicherten Projekte. Aktualisiert ein Projekt am Server. Wird das Projekt nicht gefunden es ist daher nicht am Server vorhanden dann liefern Sie false als Ergebnis zurück. Fügt ein neues Projekt zu den Projekten am Server hinzu. Kann aus irgendeinem Grund (z.b. ein Projekt mit gleichem Namen ist bereits vorhanden), das Projekt nicht hinzugefügt werden, liefern Sie false als Ergebnis. Am Server persistieren wir die Projekte in einer Dat -Datei, deren Format wir selber bestimmen. Wir legen fest, dass die in unserem Dateiformat gespeicherten Daten wie im Folgenden aussehen: Erstes Projekt;01.01.2011;- Zweiters Projekt;01.03.2009;12.05.2009 Das Format entspricht daher dem CSV-Format, wir trennen die Datenwerte mit einem ;. Der erste Wert ist der Projektname, der zweite das Anfangsdatum des Projektes und wenn kein Enddatum vorhanden ist, dann verwenden wir einen Bindestrich (-). Die Datei nennen wir ProjectList.dat. Nehmen Sie zusätzlich an, dass der Projektname eindeutig ist (Hinweis: Dies ist wichtig für die Aktualisierung). Bachelorpraktikum Add-In-Entwicklung für Visual Studio 1
Wir können daher für das Lesen und Laden der Daten folgende Methoden/Eigenschaften verwenden (Sie können diese Methoden/Eigenschaft 1:1 übernehmen diese dienen der Infrastruktur unseres WebServices): //Enthält die Projekte, während der WebService aktiv ist private List<Project> ProjectList = new List<Project>(); /// <summary> /// Lädt die Projekt- Daten /// </summary> private void LoadProjects() StreamReader sr = new StreamReader(ProjectListPath); //Dateizugriff: Lesend var projects = (from str_project in //lese Zeile ein und Teile sie nach jedem Zeilenende sr.readtoend().split(new string[] Environment.NewLine, StringSplitOptions.RemoveEmptyEntries) //teile jede Zeile wieder nach dem Trennzeichen ; select str_project.split(new char[] ';' ) //jeder string[] entspricht einem Project ).Select(str => new Project( str[0], DateTime.Parse(str[1]), str[2] == "- "? null : (DateTime?)DateTime.Parse(str[2]))); sr.close(); ProjectList.Clear(); ProjectList.AddRange(projects); /// <summary> /// Speichert die Projekt- Daten /// </summary> private void SaveProjects() //Dateizugriff: Neue Datei oder ersetzt vorhandene Datei StreamWriter sr = new StreamWriter(ProjectListPath, false); foreach (var p in ProjectList) sr.writeline( p.projectname + ";" + p.startdate.toshortdatestring() + ";" + (p.enddate.hasvalue? p.enddate.value.toshortdatestring() : "- ")); sr.close(); Hinweis: Vergessen Sie nicht, den Namensraum System.IO einzubinden. Überlegen Sie, wann Sie Ihre gespeicherten Daten Laden und Speichern. Wann ist das sinnvoll? Aufgabe b) Erstellen Sie eine Konsolenanwendung und testen Sie Ihren WebService: Fragen Sie dazu zunächst alle vorhandenen Projekte ab. Versuchen Sie ein bereits vorhandenes Projekt am Server hinzuzufügen (mittels Add ), überprüfen Sie die Rückgabe des WebService. Fügen Sie ein neues Projekt am Server hinzu und überprüfen Sie, ob ihr Projekt erfolgreich gespeichert wurde. Bachelorpraktikum Add-In-Entwicklung für Visual Studio 2
Aufgabe 2: Add-In-Entwicklung Erstellen Sie auf Basis von Aufgabe 1 ein einfaches Visual Studio Add-In, das den WebService konsumiert. implementieren Sie dazu die folgende Funktionalität: a) Das Add-In soll eine einfache grafische Benutzerschnittstelle habe (standardmäßig basiert diese auf Windows Forms). Das entsprechende Control, das zu implementieren ist, soll daher ein Textfeld für den Projektnamen enthalten, sowie jeweils ein DateTimePicker-Control für die Auswahl der Start- und Endedaten. b) Das Add-In soll es erlauben, ein neues Projekt anzulegen. c) Das Add-In soll es erlauben, ein bereits angelegtes Projekt zu laden. Dazu ist im Add-In ein Selektionsmöglichkeit vorzusehen, die alle Projekte vom WebService abfragt und das ausgewählte Projekt im Formular aus Aufgabe 2 anzeigt. d) Implementieren Sie eine Client-seitige Prüfung, ob das Endedatum nach dem Startdatum liegt. Ist dies nicht der Fall, darf der Datensatz nicht zum Server geschickt werden. Hinweis: Verwenden Sie den WebService aus Aufgabe 1 und binden Sie diesen in Ihr Projekt mithilfe einer Webreferenz ein. Verwenden Sie die generierte Proxy-Klasse, um mit dem WebService zu kommunizieren. Verwenden Sie für das Add-In den entsprechenden Visual Studio Projekttyp Visual Studio Add-In : Bachelorpraktikum Add-In-Entwicklung für Visual Studio 3
Aufgabe 3: Add-In-Entwicklung & WPF In dieser Aufgabe erstellen wir ein Visual Studio 2010 Add-in, welches den in Aufgabe 1 erstellten Webservice konsumiert und die Daten zur Projektdauer grafisch darstellt. Die Darstellung der Daten soll als Balkendiagramm in WPF erfolgen. Dazu verwenden wir die Charting Controls aus dem WPF Toolkit. a) Laden Sie das WPF Toolkit herunter. Sie finden dieses hier: http://wpf.codeplex.com/releases/view/40535 Der Installer der Binaries reicht. b) Installieren Sie die folgenden Assemblies im Global Assembly Cache: WPFToolkit.dll System.Windows.Controls.DataVisualization.Toolkit.dll Diese finden Sie im Installationsordner des WPF Toolkits (beispielsweise C:\Program Files\WPF Toolkit\v3.5.50211.1). Wen es interessiert, der Grund ist hier beschrieben: http://social.msdn.microsoft.com/forums/en-us/vsx/thread/068047ad-608c-47ba-a169-f8267cbf56b6 Die Vorbereitungen sind abgeschlossen und die Entwicklung des eigentlichen Add-ins kann beginnen. a) Legen Sie ein neues AddIn Projekt im Visual Studio an. Nachdem der Wizard den Rahmen generiert hat, fügen wir dem Projekt ein Windows Form hinzu. Dieses kann aus der Methode Exec in der Klasse Connect aufgerufen werden (vgl. Codebeispiel 1). b) Dem neuen Windows Form fügen wir ein ElementHost Control hinzu. Mithilfe des ElementHost können wir WPF innerhalb eines Windows Form verwalten. c) Wir fügen dem Projekt ein neues WPF UserControl hinzu. Das neue UserControl wird im ElementHost des zuvor angelegten Windows Form gehosted. Im Konstrktur des Windows Form instanziieren wir das WPF User- Control und weisen es der Child-Eigenschaft des ElementHost-Controls zu. Fügt man jetzt dem WPF Control beispielsweise einen TextBlock hinzu, sollte dieser im vom ElementHost eingenommenen Bereich des Windows Form erscheinen. d) Wir bauen einen Chart. Nachdem wir dem Projekt eine Referenz auf das Assembly System.Windows.Controls.DataVisualization.Toolkit.dll hinzugefügt haben und der Namespace Sys- tem.windows.controls.datavisualization.charting eingebunden ist, können wir das WPF UserControl mit Inhalt füllen. Ein Beispiel für das entsprechende Markup findet sich unten (Codebeispiel 2). e) Wir binden den Webservice ein. Hierzu fügen wir unserem Add-in-Projekt eine Service-Referenz auf den in Aufgabe 1 erstellten Webservice hinzu. Der Code-Generator fügt dem Projekt unter anderem eine app.config- Datei hinzu, welche die Kommunikation mit dem Webservice konfiguriert. Visual Studio Add-ins kennen keine Laufzeit-Konfigurationsdateien, weshalb die über die Konfigurationsdatei geregelte Instanziierung des Service- Proxies fehlschlagen würde. Wir müssen den Proxy also manuell konfigurieren. Codebeispiel 3 beinhaltet den nötigen Code. Die dort fest codierte Url würde später der Url der TFS-Webservices entsprechen und deshalb über eine entsprechende Funktion im Add-in vom Benutzer einstellbar sein. f) Wir füllen den Chart mit Inhalten aus dem Webservice. Der letzte Teil der Aufgabe ist der einfachste: Die vom Webservice zurückgegebenen Daten werden im Chart dargestellt. Ein Beispiel, wie dies aussehen könnte, findet sich im letzten Codebeispiel 4. Codebeispiel 1: public void Exec(string commandname, CommandExecOption executeoption, ref object varin, ref object varout, ref bool handled) handled = false; if(executeoption == vscommandexecoption.vscommandexecoptiondodefault) if(commandname == "WpfAddIn.Connect.WpfAddIn") EinWindowsForm form = new EinWindowsForm(); form.show(); handled = true; return; Bachelorpraktikum Add-In-Entwicklung für Visual Studio 4
Codebeispiel 2: <Grid> <charting:chart Canvas.Top="80" Canvas.Left="10" x:name="mcchart" Width="400" Height="250" Background="LightSteelBlue"> <charting:chart.series> <charting:barseries Title="Projektdauer" IndependentValueBinding="Binding Path=Key" DependentValueBinding="Binding Path=Value"> </charting:barseries> </charting:chart.series> </charting:chart> <Border x:name="borderprogress" HorizontalAlignment="Stretch" VerticalAlignment="Center" Visibility="Collapsed"> <StackPanel> <TextBlock Text="Lade..." HorizontalAlignment="Center"/> <ProgressBar Width="200" IsIndeterminate="True" Height="28"/> </StackPanel> </Border> </Grid> Codebeispiel 3: private ProjectService.ServiceSoapClient CreateServiceClient() var binding = new BasicHttpBinding(); var remoteaddress = new EndpointAddress("http://localhost:52119/WebService/Service.asmx"); var serviceclient = new ProjectService.ServiceSoapClient(binding, remoteaddress); return serviceclient; Codebeispiel 4: private void LoadBarChartData() borderprogress.visibility = System.Windows.Visibility.Visible; mcchart.visibility = System.Windows.Visibility.Collapsed; ProjectService.ServiceSoapClient client = CreateServiceClient(); client.projectscompleted += (s, e) => if(e.error == null) var projects = e.result; var bindingsource = from p in projects select new Key = p.projectname, Value = p.enddate.hasvalue? (p.enddate.value - p.startdate).days : 0 ; ; this.dispatcher.begininvoke(new Action(() => borderprogress.visibility = System.Windows.Visibility.Collapsed; mcchart.visibility = System.Windows.Visibility.Visible; ((BarSeries)mcChart.Series[0]).ItemsSource = bindingsource; )); client.projectsasync(); Bachelorpraktikum Add-In-Entwicklung für Visual Studio 5
Vorschlag/Ziel der Lösung Das Ergebnis dieser Aufgabe kann folgendes Aussehen haben: Bachelorpraktikum Add-In-Entwicklung für Visual Studio 6