SharePoint 2007 & WPF/E

För ett par veckor sedan så var jag med och presenterade på ”Innovation Day: SharePoint 2007” i våra lokaler och i en av de demos jag presenterade så byggde jag en webpart som använde WPF/E för att tydligt visualisera KPI-värden från en KPI-lista i MOSS 2007.

När det gäller att integrera WPF/E så är det inga större problem. Det man behöver göra är egentligen 4 saker vilka är:

  1. Placera filen aghost.js någonstans under root:en för den webbplats du vill integrera WPF/E med, lämpligen skapas en katalog som heter ”wpfe”.
  2. Skapa en XAML-fil som innehåller definitionen av det som ska visas. Vill man så kan man sätta det helt dynamiskt via JavaScript. Exempel på en fil finns nedan. Vill man inte supportera filändelsen ”.xaml” och konfigurera IIS:en för detta så kan man lika gärna döpa om filen till ”.xml” som redan fungerar i IIS:en.
  3. Skapa en JavaScript-fil som innehåller all funktionalitet som du vill att din webpart ska ha. Exempelkod nedan. Det jag inte gjort i koden nedan är att jag bundit ihop den med en "riktig" KPI-lista. Jag kommer posta koden till en Windows Sidebar Gadget som gör detta, den koden som använder XMLHTTP kan man enkelt skruva in i denna istället.
  4. Bygg en webpart som innehåller de få rader som krävs för att visa WPF/E-element. Kod finns nedan. Kom ihåg att sökvägarna måste stämma med var du lagt din fil ”aghost.js”, ”dinwebpart.js” och ”dinwebpart.xaml”. Enklaste sättet att bygga en webpart och testa den är genom att använda VS 2005 Extensions for SharePoint.

Webpart

protected override void Render(HtmlTextWriter writer)
{
writer.Write("<script type=\"text/javascript\" src=\"/wpfe/aghost.js\"></script>");
writer.Write("<script type=\"text/javascript\" src=\"/wpfe/sampleproject.js\"></script>");
writer.Write("<div id=\"agControl1Host\"></div>");
writer.Write("<script type=\"text/javascript\">");
writer.Write("new agHost(");
writer.Write("\"agControl1Host\",");
writer.Write("\"agControl1\",");
writer.Write("\"300px\",");
writer.Write("\"300px\",");
writer.Write("\"#ffffff\",");
writer.Write("null,");
writer.Write("\"/wpfe/sampleprojectv1.xml\",");
writer.Write("\"false\",");
writer.Write("\"30\",");
writer.Write("null");
writer.Write(");");
writer.Write("var agControl = document.getElementById(\"agControl1\");");
writer.Write("</script>");
}

XAML

<Canvas Width="300" Height="300"
xmlns="https://schemas.microsoft.com/client/2007"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml">
<Canvas.Triggers>
<EventTrigger RoutedEvent="Canvas.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetName="kpi1"
Storyboard.TargetProperty="(Fill).(Color)"
From="Green" To="LightGreen" Duration="0:0:2" AutoReverse="True" RepeatBehavior="Forever" />

<DoubleAnimation
Storyboard.TargetName="kpi2"
Storyboard.TargetProperty="(Canvas.Width)"
To="80" Duration="0:0:1" AutoReverse="True" RepeatBehavior="Forever" />

</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Canvas.Triggers>

<Rectangle Height="300" Width="300" Fill="Lime">
<Rectangle.OpacityMask>
<LinearGradientBrush>
<GradientStop Offset="0" Color="#00000000"/>
<GradientStop Offset="1" Color="#FF000000"/>
</LinearGradientBrush>
</Rectangle.OpacityMask>
</Rectangle>

<TextBlock FontFamily="Verdana, Arial" Canvas.Top="10"
Text="Test KPI 1" FontSize="30" x:Name="kpitext1" MouseEnter="javascript:textEnter" MouseLeave="javascript:textLeave"/>
<Ellipse x:Name="kpi1" Height="40" Width="40" Canvas.Left="200" Canvas.Top="10"
Stroke="Black" StrokeThickness="2" Fill="Green"/>

<TextBlock FontFamily="Verdana, Arial" Canvas.Top="60"
Text="Test KPI 2" FontSize="30" x:Name="kpitext2" MouseEnter="javascript:textEnter" MouseLeave="javascript:textLeave"/>
<Ellipse x:Name="kpi2" Height="40" Width="40" Canvas.Left="200" Canvas.Top="60"
Stroke="Black" StrokeThickness="2" Fill="Red"/>

<TextBlock FontFamily="Verdana, Arial" Canvas.Top="110"
Text="Test KPI 3" FontSize="30" x:Name="kpitext3" MouseEnter="javascript:textEnter" MouseLeave="javascript:textLeave"/>
<Path x:Name="kpi3" Data="M 0,40 L40,40 20,0z"
Stroke="Black" StrokeThickness="2" Fill="Yellow"
Canvas.Left="200" Canvas.Top="110" />

<Rectangle
Canvas.Left="200" Canvas.Top="200"
Width="50" Height="50"
Fill="RoyalBlue">
<Rectangle.RenderTransform>
<RotateTransform x:Name="myTransform" Angle="45" CenterX="25" CenterY="25" />
</Rectangle.RenderTransform>
<Rectangle.Triggers>
<EventTrigger RoutedEvent="Rectangle.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="myTransform"
Storyboard.TargetProperty="Angle"
From="0" To="360" Duration="0:0:5" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>
</Rectangle>
<TextBlock x:Name="info" FontFamily="Verdana, Arial" Canvas.Top="170"
Text="" FontSize="30" Foreground="DarkGreen"/>
</Canvas>

JavaScript

function textEnter(sender, args) {
sender.foreground = "red"
if(sender.Name == "kpitext1")
sender.findName("info").text = "Value: 100\nGoal: 90\nWarning: 50"
if(sender.Name == "kpitext2")
sender.findName("info").text = "Value: 38\nGoal: 50\nWarning: 30"
if(sender.Name == "kpitext3")
sender.findName("info").text = "Value: 300\nGoal: 1000\nWarning: 500"
}

function textLeave(sender, args) {
sender.foreground = "black"
sender.findName("info").text = ""
}