|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Services
Chapters
Feature Zones
|
Contents
IntroductionOK so we've all got the hang of WPF right, so now we have another beast to slay, it's Silverlight. Silverlight is an internet browser plugin that rivals Adobe Flash for capabilities, and uses a cut down version of Windows Presentation Foundation (WPF) which used to be known as WPF/e (WPF everywhere). Silverlight currently comes in two flavours, Silverlight 1.0 which is JavaScript based, and the slightly newer 1.1 Alpha which can use managed .NET code. I personally am not that fond of JavaScript so I have been putting the Silverlight mission off until version 1.1. So now that the 1.1 alpha is out, I thought it high time that I got down and started writing a Silverlight article. I have to say I am fairly pleased with this article, and I think it covers most aspects of what Silverlight can currently do. Of course this may change over time, but let's just assume that things are the way they are right now. Before we get started, there is one thing that you will really need in order to run the demo project, and that's Visual Studio 2008 Beta 2, which is available here, I went for the Professional edition, and it works a treat. Downloaded, installed and worked first time, unlike all other VS2008 versions I went for. Professional edition works, use that. AssumptionsThat the reader is .NET proficient and at least an average level web user, and is fairly familiar with ASP.NET and Visual Studio. Getting Started With Silverlight 1.1/VS2008One of the first things that you will notice when you start VS2008, is that there is a new project type available, yep you guessed it - a Silverlight project.
Remember that Silverlight applications are web based, so the best place to start is probably with a ASP.NET web project. If we then proceed to add a Silverlight project to our existing Web project, we end up with two projects as shown below. In this example (the demo app) the projects are Web: ASP.NET web site, and SilverlightProject1 which is the Silverlight project. One thing to notice in the screen shot below is that the Web project can be configured to run on a certain port within Visual Studio. This setting tells Cassini (the inbuilt VS web browser) to use a static or dynamic port, there will be more mentioned about this later.
When we add a new Silverlight project we end up with some boiler plate files, much the same way one does when creating a new project using one of the other Visual Studio templates. Consider the figure below which is a brand new Silverlight project.
The Silverlight DLLs are installed to the Program Files\Silverlight location.
There are three files for a new Silverlight project:
I'm just going to show you a bit about each of these three files, so you get the demo app file structure. 1. Page.xamlIs made up of two files, the XAML and the code behind. Let's start with the XAML.
As can be seen from the figure above, the Page is simply a The code behind for page is simply enough: using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace SilverlightProject1
{
public partial class Page : Canvas
{
public void Page_Loaded(object o, EventArgs e)
{
// Required to initialize variables
InitializeComponent();
}
}
}
One thing you won't find is the 2. TestPage.htmlTestpage.html is the page that holds the Silverlight object. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<!-- saved from url=(0014)about:internet -->
<head>
<title>Silverlight Project Test Page </title>
<script type="text/javascript" src="Silverlight.js"></script>
<script type="text/javascript" src="TestPage.html.js"></script>
<style type="text/css">
.silverlightHost { width: 640px; height: 480px; }
</style>
</head>
<body>
<div id="SilverlightControlHost" class="silverlightHost" >
<script type="text/javascript">
createSilverlight();
</script>
</div>
</body>
</html>
This also has a JavaScript code behind file, which is called within the // JScript source code
//contains calls to silverlight.js, example below loads Page.xaml
function createSilverlight()
{
Silverlight.createObjectEx({
source: "Page.xaml",
parentElement: document.
getElementById("SilverlightControlHost"),
id: "SilverlightControl",
properties: {
width: "100%",
height: "100%",
version: "1.1",
enableHtmlAccess: "true"
},
events: {}
});
// Give the keyboard focus to the Silverlight control by
//default
document.body.onload = function() {
var silverlightControl = document.
getElementById('SilverlightControl');
if (silverlightControl)
silverlightControl.focus();
}
}
3. Silverlight.jsSilverlight.js is a rather large helper script that is MSFT authored and is used to perform additional functions in order to setup the Silverlight object within the host browser. A Bit of Warning about AlphasWhen I first started looking at Silverlight (about one week now) I was very disappointed that there were no input controls, such as Buttons, TextBoxes, Tabs, ScrollViewers etc. I mean jeez no input controls, come on now. You have to create these sort of things yourself, which is a bit time consuming but doable. There are some free controls available as mentioned in the resources section at the bottom of this article. One bit of good news is that the Silverlight 1.1 Alpha Refresh does include some basic controls. Have a look there before you start. When dealing with Silverlight one must remember it is still Alpha, so things will change and get included. I have to say I started out quite negative (cos I like Flash) but by the end I loved Silverlight. What Can One Do With Silverlight 1.1If we look at the Silverlight 1.1 Tutorials and Code Starts one can see that the following appears to be a list of what we can reasonably expect a Silverlight 1.1 application to be able to do (at the moment):
The attached demo app will demonstrate and discuss each of these areas. The Demo AppSo what does the demo app look like, well it looks like this: What Does it Do / What are the RequirementsOk so that's a screen shot of what it looks like. But what does it do, what were my requirements? When I started (one week ago) I decided that I wanted to write a Silverlight application that would utilise most of the current Silverlight functions available. So I gave it a thought, and I came up with this: I wanted an application that would use a Web service that would query Flickr for images using a RSS feed, and would show these images in a scrollable panel from where the user may select an image to be viewed in the main page area. When an image was in the main area, I wanted it to be able to be dragged/resized and rotated (like MSFT surface) and removed from the main page area. The user may also get the next/previous page of results from Flickr, so it would have some sort of paging mechanism. I also wanted it to look cool. This application has a lot of scope, it does indeed cover a lot of Silverlight functionality, and by the end of this article, I hope that you lot will get what you can do with Silverlight right now. Here is another diagram for the finished demo app with some callouts showing which of the items shown are created by which classes in the attached application. As I stated earlier, this demo app covers a lot of ground, it covers the following areas:
This image may help a little to see the dependencies and how all the classes and even projects relate to each other
It can be seen that there are two projects in the attached demo application, the Web project and the Silverlight project. The Silverlight project consists of the Silverlight page object and the hosting HTML page and setup JavaScript, along with code for all the custom controls that have been authored in order to carry out the demo application functionality. The Web project has the compiled Silverlight project's DLL, and a copy of the Silverlight page object and the hosting HTML page and setup JavaScript. But the web project also has other classes, which are used by the Silverlight project. The rule of thumb with Silverlight 1.1 is that it can ONLY use localhost (127.0.0.1) resources, so that's why there are some extra items in the web project, basically they are used by the Silverlight project in one way or another. Don't worry, these will be described in detail in the following sections.
I'll briefly describe some of the extra files:
Getting Started with Silverlight DevelopmentThis was already discussed above. Networking and Communication in SilverlightThere are several different options for getting data into Silverlight, you can use either of the following approaches:
I'll talk about each of these a bit and then I'll show you what the demo application actually does to get its data. XML FilesAs I don't do this in my demo application (attached), I'm going to simply use the quickstart code from here to illustrate how to read XML data in your Silverlight applications. The relevant MSFT quick start is located here. What they do is use a local XML file called rssfeed.xml, which they then parse and use within a Silverlight application. The format of the rssfeed.xml file is as shown below: <?xml version="1.0" encoding="ISO-8859-1" ?>
<?xml-stylesheet type='text/xsl' href='RssPretty.xslt' version='1.0'?>
<rss version="2.0">
<link rel="alternate" type="application/rss+xml" title="RSS FEED TITLE"
href="RSS FEED URL" />
<channel>
<title>Microsoft Windows Vista</title>
<link>http://www.microsoft.com/windowsvista/</link>
<description>Get new content and articles about Windows
Vista directly from Microsoft.</description>
<copyright>?2006 Microsoft Corporation. All rights reserved.
</copyright>
<language>en-us</language>
<ttl>1440</ttl>
<item>
<title>Make Beautiful Music with Windows Vista—at Home
or On the Go</title>
<pubDate>Wed, 24 Jan 2007 11:00:00 GMT</pubDate>
<description>Columnist S.E. Slack explains how to use
Windows Media Center in Windows Vista to experience
digital music on your PC and portable device.
</description>
<link>http://www.microsoft.com/windowsvista/community/
beautifulmusic.mspx</link>
</item>
....
....
</channel>
</rss>
And then they parse this XML file within their Silverlight application as follows: using System;
using System.Linq;
using System.Xml;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.IO;
using System.Net;
using System.Text;
using System.Windows.Browser;
using System.Windows.Browser.Net;
namespace BasicRss
{
public partial class Page : Canvas
{
public void Page_Loaded(object o, EventArgs e)
{
// Required to initialize variables
InitializeComponent();
string url = GetXmlRssUrl();
try
{
HttpWebRequest request = new
BrowserHttpWebRequest(new Uri(url));
// Get the response.
HttpWebResponse response = request.GetResponse();
// Get the stream containing content returned by the
//server.
Stream content = response.GetResponseStream();
// Create a XMLWriter that outputs to a
//StringBuilder and Create XMLReader
StringBuilder xamlString = new StringBuilder();
using (XmlWriter writer = XmlWriter.Create(xamlString))
using (XmlReader reader = XmlReader.Create(new
StreamReader(content)))
{
// Create a Canvas element, that will be converted
//to Canvas control and will be added to the
//parent Canvas control.
writer.WriteStartElement("Canvas");
int canvasTop = 40;
//Start reading the content.
while (reader.Read())
{
if ((reader.IsStartElement()) &&
("item" == reader.LocalName))
{
using (XmlReader itemReader =
reader.ReadSubtree())
{
while (itemReader.Read())
{
if (itemReader.IsStartElement())
{
if ("title" ==
itemReader.LocalName)
{
//Write the title.
writer.WriteStartElement
("TextBlock");
writer.WriteAttributeString
("Canvas.Top",
canvasTop.ToString());
writer.WriteAttributeString
("Foreground", "Blue");
// Move canvas top
canvasTop = canvasTop + 20;
writer.WriteAttributeString
("Text",
"Title: " +
itemReader.
ReadElementContentAsString());
writer.WriteEndElement();
}
else if ("link" ==
itemReader.LocalName)
{
//Write the link.
writer.WriteStartElement
("TextBlock");
writer.WriteAttributeString
("Canvas.Top",
canvasTop.ToString());
writer.WriteAttributeString
("Foreground", "Blue");
// Move canvas top
canvasTop = canvasTop + 40;
writer.WriteAttributeString
("Text",
"Link: " +
itemReader.
ReadElementContentAsString());
writer.WriteEndElement();
}
}
}
}
}
}
// Close the "Canvas" element.
writer.WriteEndElement();
// Flush the buffer.
writer.Flush();
}
// Clean up.
response.Close();
// Display XAML on the page
// by adding it to the Canvas's children collection.
System.Windows.DependencyObject controls =
XamlReader.Load(xamlString.ToString());
this.Children.Add(controls as Visual);
}
catch (Exception ex)
{
TextBlock error = (TextBlock)this.FindName("error");
error.Text = " Error: " + ex.Message;
}
}
/// <summary>
/// Gets the local url of the RSS feed
/// </summary>
/// <returns></returns>
private string GetXmlRssUrl()
{
string path = HtmlPage.DocumentUri.AbsolutePath;
int lastSlash = path.LastIndexOf("/");
path = path.Substring(0, lastSlash + 1);
return "http://" + HtmlPage.DocumentUri.Host + path +
"rssfeed.xml";
}
}
}
Whilst this certainly does the job just fine, a better approach may be to use a Web service to return a nice collection of some .NET objects that the Silverlight app could use, without having to do all this parsing. Enter Web Services / Silverlight communications. Web Services and SilverlightSilverlight can actually call an ASP.NET web service no problem. It's simply a question of creating a web reference in the Silverlight project. One thing that is important to note, is that cross domain calls (not localhost) aren't currently allowed using certain Silverlight objects, as I'll discuss later on when we get to the I'm going to go through the steps to get an ASP.NET web service up and running with Silverlight in VS2008. If you want a good link to get you started with Silverlight and ASP.NET web services in VS2008, check out this excellent entry, by MSFTs Mike Taulty. This is what got me up and running. I've copied his post here for folk that just want to read everything in one article. Steps as below:
[WebService(Namespace = "http://tempuri.org/")]
[ScriptService]
public class WebService : System.Web.Services.WebService {
public WebService ()
{
}
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string HelloWorld() {
return "Hello World";
}
Quite an important part to note is that the web methods should be marked with the Now we have a service, let's build something from Silverlight to call it:
The Demo App ImplementationOk so I've now shown you that you can use XML and Web Services from within your Silverlight app, which is cool, huh. I also stated that I was not that keen on using XML file parsing in my Silverlight application. So what do I do. Well I have a fairly simply ASP.NET web service that I reference, and call just like I described above, and I am using XML too. It's just how the XML is dealt with that's different. Let's have a look at what I do. Recall, I wanted to use Flickr. Flickr actually has a RssFeed which is available using the following URL: "http://www.flickr.com/services/rest/?method=flickr.interestingness.getList&api_key=" + _FLICKR_API_KEY; When I bash this URL into the browser, the following XML is returned. <rsp stat="ok">
<photos page="1" pages="5" perpage="100" total="500">
<photo id="1809392098" owner="37451064@N00"
secret="9ddb3512d4" server="2012" farm="3"
title="Day 278/365......This is about as Halloween as I get"
ispublic="1" isfriend="0" isfamily="0"/>
<photo id="1807982526" owner="51107197@N00" secret="1dd4e67541"
server="2241" farm="3"
title="Polihale Sunset" ispublic="1" isfriend="0" isfamily="0"/>
<photo id="1807122211" owner="55217458@N00" secret="4c333e73e4"
server="2112" farm="3"
title="waiting" ispublic="1" isfriend="0" isfamily="0"/>
<photo id="1808703464" owner="76743095@N00" secret="85d3010d77"
server="2131" farm="3"
title="Cyclops" ispublic="1" isfriend="0" isfamily="0"/>
....
....
</photos>
</rsp>
So I thought why not use XLINQ to do something cool. There may be some of you who have read some of my other WPF articles, and have seen this before. But I am a creature of habit, and really like Flickr, so sorry if this is old to you guys. But with this XML feed available I am able to use XLINQ to select the data I'm interested in, into new .NET types, which are returned via the web service to the Silverlight application. Let's have a look shall we. In my Page.xaml.cs Silverlight file, I called the web service like: using System;
using System.Windows;
using System.Windows.Controls;
using System.Collections.Generic;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Browser;
using SilverlightProject1.Controls;
namespace SilverlightProject1
{
public partial class Page : Canvas
{
private SilverlightProject1.FlickrService.PhotoInfo[] photos;
private FlickrService.WebService websservice;
public void Page_Loaded(object o, EventArgs e)
{
// Required to initialize variables
InitializeComponent();
//create the web service
websservice = new FlickrService.WebService();
photos = websservice.GetFlickr(pageIndex,
Constants._NUM_OF_PHOTOS_FROM_FLICKR);
}
}
}
It can be seen that this call to the web service actually returns an array of using System;
using System.Linq;
using System.Web;
using System.Collections;
using System.Collections.Generic;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Linq;
using System.Web.Script.Services;
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class WebService : System.Web.Services.WebService
{
private RSSFeed _Feed;
public WebService () {
_Feed = new RSSFeed();
}
[WebMethod]
//For Silverlight, as v1.1 only allows JSON
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public List<PhotoInfo> GetFlickr(int pageIndex,
int numOfImageToFetch)
{
return _Feed.LoadPictures(pageIndex, numOfImageToFetch); ;
}
}
So it can also been seen that the web service holds an instance to an using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Xml.Linq;
using System.Collections.Generic;
public class RSSFeed
{
#region Instance fields
private const string _FLICKR_API_KEY =
"c705bfbf75e8d40f584c8a946cf0834c";
private const string _MOST_RECENT =
"http://www.flickr.com/services/rest/?method=flickr.
photos.getRecent&api_key=" + _FLICKR_API_KEY;
private const string _INTERESTING = "http://www.flickr.com/
services/rest/?method=flickr.interestingness.getList&
api_key=" + _FLICKR_API_KEY;
private string _url = _INTERESTING;
public RSSFeed()
{
}
public List<PhotoInfo> LoadPictures(int pageIndex, int numOfImageToFetch)
{
try
{
var xraw = XElement.Load(_url);
var xroot = XElement.Parse(xraw.ToString());
var photos = (from photo in xroot.Element("photos").
Elements("photo")
select new PhotoInfo
{
_Id = (string)photo.Attribute("id"),
_Owner = (string)photo.Attribute("owner"),
_Title = (string)photo.Attribute("title"),
_Secret = (string)photo.Attribute("secret"),
_Server = (string)photo.Attribute("server"),
_Farm = (string)photo.Attribute("farm")
}).Skip(pageIndex * numOfImageToFetch).
Take(numOfImageToFetch);
return photos.ToList<PhotoInfo>();
}
catch
{
return null;
}
}
}
Notice the cool XLINQ stuff, all too easy, no nasty XML file parsing. Sold that. Just use XLINQ and create a collection of new CLR objects, ( Building Dynamic User Interfaces with SilverlightSilverlight development is all about custom controls, there are very few native controls the way it stands at the moment. But it's only an alpha after all. That said there aren't any input controls, which I mentioned earlier. You have to write most of the stuff yourself. The Silverlight 1.1 reference poster quite clearly shows you which controls are available to you. It's basically the following controls:
So how are people creating such RIAs using Silverlight. Well it's down to hard work, and to be honest it's not that hard, and Silverlight is actually fun you know, so you get into it. I think the best place to start is to show you how to create a custom control or two. I'm going to show you how to create a button and then an image which is rotated and has an alpha applied to it when you mouse over it. I'll also briefly show screen shots and offer simple (yes, you'll have to investigate further) explanations of all other controls in the attached demo application. Custom Button ControlI like to start with a screen shot. This is what we are going to be making. A very simply button that glows when it has mouse focus, and can be disabled which will use a different disabled color brush. So that's what we are trying to achieve. So let's begin. Most controls in Silverlight will either inherit from using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Browser;
namespace SilverlightProject1.Controls
{
public class GrayButton : Control
{
private FrameworkElement _root;
public GrayButton()
{
System.IO.Stream s = this.GetType().Assembly.
GetManifestResourceStream(
"SilverlightProject1.Controls.GrayButton.xaml");
_root = this.InitializeFromXaml(new
System.IO.StreamReader(s).ReadToEnd());
...
...
}
}
}
So once you've loaded the XAML and obtained a reference to the actual element ( using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Browser;
namespace SilverlightProject1.Controls
{
/// <summary>
/// Provides a minimal button implementation
/// </summary>
public class GrayButton : Control
{
#region Instance fields
private FrameworkElement _root;
private Storyboard _animate;
private TextBlock _text;
private Rectangle _background, _highlight;
private bool _mouseDown;
private bool _IsEnabled = true;
private Brush _EnabledBrush;
private Brush _DisabledBrush;
public event EventHandler MouseDown, MouseUp, Click;
#endregion
#region Ctor
public GrayButton()
{
System.IO.Stream s = this.GetType().Assembly.
GetManifestResourceStream(
"SilverlightProject1.Controls.GrayButton.xaml");
_root = this.InitializeFromXaml(new
System.IO.StreamReader(s).ReadToEnd());
// Fetch elements from the loaded XAML
_animate = (Storyboard)_root.FindName("animate");
_text = (TextBlock)_root.FindName("text");
_background = (Rectangle)_root.FindName("background");
_EnabledBrush = _background.Fill;
_DisabledBrush = new SolidColorBrush(Colors.LightGray);
_highlight = (Rectangle)_root.FindName("highlight");
_mouseDown = false;
//hook up events
MouseEnter += new MouseEventHandler(OnMouseEnter);
MouseLeave += new EventHandler(OnMouseLeave);
MouseLeftButtonDown += new MouseEventHandler(
OnMouseLeftButtonDown);
MouseLeftButtonUp += new MouseEventHandler(
OnMouseLeftButtonUp);
CenterText();
}
#endregion
#region Public methods/properties
public String Text
{
get { return _text.Text; }
set
{
_text.Text = value;
CenterText();
}
}
public double Left
{
get { return (double)GetValue(Canvas.LeftProperty); }
set { SetValue(Canvas.LeftProperty, value); }
}
public double Top
{
get { return (double)GetValue(Canvas.TopProperty); }
set { SetValue(Canvas.TopProperty, value); }
}
public new double Width
{
get { return _background.Width; }
set
{
_background.Width = value;
_highlight.Width = value;
CenterText();
}
}
public new double Height
{
get { return _background.Height; }
set
{
_background.Height = value;
_highlight.Height = value;
CenterText();
}
}
public double RadiusX
{
get { return _background.RadiusX; }
set
{
_background.RadiusX = value;
_highlight.RadiusX = value;
}
}
public double RadiusY
{
get { return _background.RadiusY; }
set
{
_background.RadiusY = value;
_highlight.RadiusY = value;
}
}
public bool IsEnabled
{
get { return _IsEnabled; }
set
{
_IsEnabled = value;
_background.Fill = _IsEnabled ? _EnabledBrush :
_DisabledBrush;
}
}
#endregion
#region Private methods/properties
private void CenterText()
{
_text.SetValue(Canvas.LeftProperty,
_background.Width / 2 - (_text.ActualWidth / 2));
_text.SetValue(Canvas.TopProperty,
_background.Height / 2 - (_text.ActualHeight / 2));
}
private void OnMouseLeftButtonUp(object sender, MouseEventArgs e)
{
if (_IsEnabled)
{
if (_mouseDown)
{
Click(this, new EventArgs());
_mouseDown = false;
}
}
}
private void OnMouseLeftButtonDown(object sender, MouseEventArgs e)
{
if (_IsEnabled)
{
_mouseDown = true;
MouseDown(this, new EventArgs());
}
}
private void OnMouseLeave(object sender, EventArgs e)
{
if (_IsEnabled)
{
_animate.Stop();
}
}
private void OnMouseEnter(object sender, MouseEventArgs e)
{
if (_IsEnabled)
{
_animate.Begin();
}
}
#endregion
}
}
And here's the associated XAML for the <Canvas xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="15" Height="50">
<Canvas.Resources>
<Storyboard x:Name ="animate">
<DoubleAnimation Storyboard.TargetName="highlight"
Storyboard.TargetProperty="Opacity"
AutoReverse="True" RepeatBehavior="Forever"
Duration="0:0:0.5" From="0" To="0.5"/>
</Storyboard>
</Canvas.Resources>
<Rectangle x:Name="background" Width="130" Height="55"
StrokeThickness="1" RadiusX="2" RadiusY="2"
Stroke="#000000">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<LinearGradientBrush.GradientStops>
<GradientStop Color="#ffffff" Offset="0"/>
<GradientStop Color="#d2dfe8" Offset="0.2"/>
<GradientStop Color="#0475bc " Offset="0.50"/>
<GradientStop Color="#d2dfe8" Offset="0.8"/>
<GradientStop Color="#ffffff" Offset="1"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<TextBlock x:Name="text" FontSize="14" Foreground="#000000"
Canvas.Top="17" Canvas.Left="33" Text=""
FontFamily="Arial Black" FontWeight="Bold"/>
<Rectangle x:Name="highlight" Width="15" Height="50"
StrokeThickness="4" Stroke="#ffffff"
Fill="#ffffff" Opacity="0"/>
</Canvas>
You can see that the root element is actually a So that's one way of creating a custom control. But suppose you don't want any XAML and you just need code. Can you do that? Well sure you can, you can just inherit from The code for this is shown below: public class ScrollCanvas : Canvas
{
#region Instance fields
private SilverlightProject1.FlickrService.PhotoInfo[] _Photos;
private Point _PrevPoint = new Point();
public delegate void photoClickedDelegate(
SilverlightProject1.FlickrService.PhotoInfo file);
public event photoClickedDelegate PhotoClickedEvent;
public bool _IsScrolling=false;
#endregion
#region Ctor
public ScrollCanvas()
{
this.SetValue(Canvas.BackgroundProperty, Colors.LightGray);
this.SetValue(Canvas.WidthProperty,
Constants.SCROLL_CANVAS_WIDTH);
this.SetValue(Canvas.HeightProperty,
Constants.SCROLL_CANVAS_HEIGHT);
this.MouseMove += new MouseEventHandler(ScrollCanvas_MouseMove);
this.MouseLeftButtonDown += new MouseEventHandler(
ScrollCanvas_MouseLeftButtonDown);
this.MouseLeftButtonUp += new MouseEventHandler(
ScrollCanvas_MouseLeftButtonUp);
}
#endregion
#region Public properties/methods
public SilverlightProject1.FlickrService.PhotoInfo[] Photos
{
get { return _Photos; }
set
{
_Photos = value;
if (_Photos.GetUpperBound(0) > 0)
{
this.Children.Clear();
int xOffset = 30;
foreach (SilverlightProject1.FlickrService.PhotoInfo
file in _Photos)
{
SmallPhoto sp = new SmallPhoto(this, file);
sp.Left = xOffset;
sp.Top = 20;
sp.Width = Constants.SMALL_PHOTO_HEIGHT;
sp.Height = Constants.SMALL_PHOTO_HEIGHT;
sp.PhotoClickedEvent += new
SmallPhoto.photoClickedDelegate(
sp_PhotoClickedEvent);
this.Children.Add(sp);
xOffset += ((int)sp.Width + 30);
}
}
}
}
public double Left
{
get
{
return (double)GetValue(Canvas.LeftProperty);
}
set
{
SetValue(Canvas.LeftProperty, value);
}
}
public double Top
{
get
{
return (double)GetValue(Canvas.TopProperty);
}
set
{
SetValue(Canvas.TopProperty, value);
}
}
public void OnPhotoClickedEvent(SilverlightProject1.FlickrService.
PhotoInfo file)
{
//Invoking all the event handlers
if (PhotoClickedEvent != null) PhotoClickedEvent(file);
}
#endregion
#region Private properties/methods
private void sp_PhotoClickedEvent(SmallPhoto sender)
{
OnPhotoClickedEvent(sender.File);
}
private void ScrollCanvas_MouseLeftButtonUp(object sender,
MouseEventArgs e)
{
_IsScrolling = false;
}
private void ScrollCanvas_MouseLeftButtonDown(object sender,
MouseEventArgs e)
{
_PrevPoint = new Point(0, 0);
_IsScrolling = true;
}
private void ScrollCanvas_MouseMove(object sender,
MouseEventArgs e)
{
if (_IsScrolling)
{
int deltaX;
if (_PrevPoint.Equals(new Point(0, 0)))
{
deltaX = 0;
}
else
deltaX = (int)(e.GetPosition(this).X -
_PrevPoint.X);
double leftEdge = (double)this.GetValue(Canvas.
LeftProperty);
leftEdge += deltaX;
if (leftEdge < ((this.Width / 2) * -1))
return;
if (!(leftEdge > 0))
{
this.SetValue(Canvas.LeftProperty, leftEdge);
}
_PrevPoint = new Point(e.GetPosition(this).X,
e.GetPosition(this).Y);
}
}
#endregion
}
So I hope that's enough to get you started with custom controls. I did mention that I would briefly discuss all the custom controls in the demo app, so here we go. The SmallPhotoIt is a small control that holds an image and is randomly rotated and has mouse events for selecting, and has a selected event which is used by the parent (
The PhotoIt is a control that holds an image and is randomly rotated and has mouse events for dragging/selecting/scaling/rotating. It looks like this. The combination of the
The
Interaction between HTML and Managed CodeSilverlight has the ability to interact with the page that is hosting it. As mentioned above this may be one approach, where Silverlight could talk to ASP.NET input controls (remember Silverlight 1.1 doesn't have these as standard) that are actually not part of the Silverlight object that exist within the page hosting the Silverlight object. The reason I have not done this is that even if you go down the route of using ASP.NET web controls, they can't be positioned over the Silverlight object even if they are positioned using absolute positioning. Well that didn't work for me at any rate. But if you want them to be available outside of the Silverlight control area, this is entirely feasible. But I just think a better approach is to author the custom controls you think you need in .NET code. This way the controls are re-usable and are packaged into the Silverlight projects output DLL. More typically what you may want to do is, set or get a value from the DOM for the page that is hosting the Silverlight object, so I'm going to talk you through how to do that. It's ever so easy, let's have a look at it. So firstly let's look at the hosting pages HTML (the DOM): <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns=" | ||||||||||||||||||||||