Динамическое создание объектов SilverLight 1.0

Опубликовано 22 Май | Автор LOB
Ключевые слова:, , ,

Стояла задача – сделать анимацию в Silverlight, формирование страницы в зависимости от некоторых условий (например, в зависимости от пользователя), и чтобы все хорошо смотрелось в IE и FF.

Создадим новый проект Silverlight 1.0. По-умолчанию он состоит из следующих файлов:
Default.html и Default.html.js
Scene.xaml и Scene.xaml.js
Silverlight.js

Default.html – содержит ссылки на все скриптовые файлы в заголовке и вызов функции createSilverlight() в теле.
Scene.xaml – собственно xaml-код приложения.
Silverlight.js и другие *.js-файлы содержат java-script, необходимый для работы.

Увы, в данном случае возможно показывать только заранее созданную xaml-форму. Но часто требуется, чтобы наполнение формы зависело от каких-то условий. Например, разным пользователям нужно показывать разные пункты меню. Попробуем сделать это.

Для начала создадим в проекте еще aspx-форму с именем XamlForm.aspx и в редакторе заменим стандартный код на следующий:

Код XAML:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="XamlForm.aspx.cs"
Inherits="SilverlightJSApplication1.XamlForm" ContentType="text/xaml" %>

<Canvas
	xmlns="http://schemas.microsoft.com/client/2007"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	Width="640" Height="480"
	Background="#FFF6F4F0"
	x:Name="Page">
	<Canvas x:Name="Menu" Width="400" Height="420"
		Canvas.Top="200" Canvas.Left="320">
		<Rectangle Width="400" Height="420" Fill="#FFFFFFFF"
			Stroke="#FF000000" RadiusX="10" RadiusY="10"/>
	</Canvas>
</Canvas>

Также добавим в проект файл XamlForm.js и в него перенесем код из Scene.xaml.js, очистив от всего лишнего:

Код JavaScript:

if (!window.SilverlightJSApplication1)
	window.SilverlightJSApplication1 = {};

SilverlightJSApplication1.Scene = function()
{

}

SilverlightJSApplication1.Scene.prototype =
{
	handleLoad: function(plugIn, userContext, rootElement)
	{
		this.plugIn = plugIn;
	}
}

Файлы Scene.xaml и Scene.xaml.js можно удалить из проекта, они больше не понадобятся.

Чтобы увидеть, что у нас получилось, нужно в файле Default.html заменить путь к Scene.xaml.js на путь к новому XamlForm.js и добавить атрибуты в :

leftmargin=”0″ topmargin=”0″ marginheight=”0″ marginwidth=”0″

А в Default.html.js заменить строку source c ‘Scene.xaml’ на ‘ XamlForm.aspx’. Теперь в качестве xaml-файла у нас обыкновенная страница aspx, и мы имеем возможность динамически ее наполнять. Поправим aspx код на:

Код XAML:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="XamlForm.aspx.cs"
Inherits="SilverlightJSApplication1.XamlForm"
ContentType="text/xaml" %>

<Canvas
	xmlns="http://schemas.microsoft.com/client/2007"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	Width="640" Height="480"
	Background="#FFF6F4F0"
	x:Name="Page">
		<Canvas.Resources>
		<Storyboard x:Name="animation">
		<%= createRectAnimation() %>
		</Storyboard>
		</Canvas.Resources>
	<Canvas x:Name="Menu" Width="330" Height="170"
		Canvas.Top="200" Canvas.Left="320">
		<Rectangle Width="330" Height="170" Fill="#FFFFFFFF"
			Stroke="#FF000000" RadiusX="10" RadiusY="10"/>
	</Canvas>
	<%= createRectangles()%>
</Canvas>

В cs-коде напишем:

Код C#:

using System;
using System.Collections;
using System.Text;

namespace SilverlightJSApplication1
{
	public partial class XamlForm : System.Web.UI.Page
	{
		// {0} - TargetName
		// {1} - end X value
		// {2} - end Y value
		private string xamlAnimation = @"<DoubleAnimationUsingKeyFrames  BeginTime=""00:00:00""
		Storyboard.TargetName=""{0}""
		Storyboard.TargetProperty=""(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)"">
		<SplineDoubleKeyFrame KeyTime=”"00:00:02″” Value=”"{1}”"/> 
		</DoubleAnimationUsingKeyFrames> 
		<DoubleAnimationUsingKeyFrames  BeginTime=”"00:00:00″” Storyboard.TargetName=”"{0}”"
		Storyboard.TargetProperty=”"(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)”"> 
		<SplineDoubleKeyFrame KeyTime=”"00:00:02″” Value=”"{2}”"/> 
		</DoubleAnimationUsingKeyFrames>”;
// {0} - Name
		// {1} - Width
		// {2} - Height
		// {3} - Left
		// {4} - Top
		// {5} - Color (#FFFFFFFF)
		// {6} - Visibility (Visible | Collapsed)
		private string xamlRectString = @"<Rectangle Width=""{1}""  Height=""{2}"" Fill=""{5}""
		Stroke=""#FF000000"" Canvas.Left=""{3}""  Canvas.Top=""{4}""
		RenderTransformOrigin=""0.5,0.5"" x:Name=""{0}""  Visibility=""{6}""> 
		<Rectangle.RenderTransform>
		<TransformGroup> 
		<ScaleTransform ScaleX=”"1″” ScaleY=”"1″”/> 
		<SkewTransform AngleX=”"0″” AngleY=”"0″”/> 
		<RotateTransform Angle=”"0″”/> 
		<TranslateTransform X=”"0″” Y=”"0″”/> 
		</TransformGroup> 
		</Rectangle.RenderTransform> 
		</Rectangle>”;
private ArrayList arrayObjects;

		protected void Page_Load(object sender, EventArgs e)
		{
			arrayObjects = new ArrayList(4);
			arrayObjects.Add(new XamlRectangle("rect1", 160, 80, 40, 40, 260, 180, "#FFC42B2B", "Visible"));
			arrayObjects.Add(new XamlRectangle("rect2", 160, 80, 440, 40, -260, 180, "#FF33AB23", "Visible"));
			arrayObjects.Add(new XamlRectangle("rect3", 160, 80, 40, 360, 260, -180, "#FF3A2BC4", "Visible"));
			arrayObjects.Add(new XamlRectangle("rect4", 160, 80, 440, 360, -260, -180, "#FFDEBA10", "Visible"));
		}

		protected string createRectAnimation()
		{
			StringBuilder result = new StringBuilder();

			foreach (XamlRectangle rect in arrayObjects)
			{
				result.AppendFormat(xamlAnimation, rect.Name, rect.EndX, rect.EndY);
			}

			return result.ToString();
		}

		protected string createRectangles()
		{
			StringBuilder result = new StringBuilder();

			foreach (XamlRectangle rect in arrayObjects)
			{
				result.AppendFormat(xamlRectString, rect.Name, rect.Width, rect.Height, rect.StartX, rect.StartY,
				rect.Color, rect.Visibility);
			}

			return result.ToString();
		}
	}
}

Да, еще потребуется новый класс XamlRectangle.cs. Его код:

Код C#:

using System;

namespace SilverlightJSApplication1
{
	public class XamlRectangle
	{
		public string Name;
		public int Width;
		public int Height;
		public int StartX;
		public int StartY;
		public int EndX;
		public int EndY;
		public string Color; // #FFFFFFFF
		public string Visibility; // Visible | Collapsed

		public XamlRectangle(string name, int width, int height, int startX, int startY, int endX, int endY,
		string color, string visibility)
		{
			this.Name = name;
			this.Width = width;
			this.Height = height;
			this.StartX = startX;
			this.StartY = startY;
			this.EndX = endX;
			this.EndY = endY;
			this.Color = color;
			this.Visibility = visibility;
		}
	}
}

Теперь мы можем генерировать нужные элементы «на лету», в зависимости от начальных условий. Но то, что получилось, пока выглядит не очень красиво. Добавим анимацию и автоматическое изменение размера под всю страницу. Для этого в файле XamlForm.js допишем:

Код JavaScript:

SilverlightJSApplication1.Scene.prototype =
{
	handleLoad: function(plugIn, userContext, rootElement)
	{
		this.plugIn = plugIn;
		this.plugIn.content.onResize = Silverlight.createDelegate(this, this.onResize);

		this.border = 5;
		this.indent = 100;
		this.animate = false;

		rootElement.addEventListener("MouseLeftButtonDown", Silverlight.createDelegate(this, this.handleMouseDown));
	},

	// Sample event handler
	handleMouseDown: function(sender, eventArgs)
	{
		if (this.animate == false)
		{
		this.animation = sender.findName("animation");
		this.animation.begin();
		this.animate = true;
		}
	},

	onResize: function(sender, args) {
		var targetWidth = sender.getHost().content.actualWidth;
		var targetHeight = sender.getHost().content.actualHeight;

		var page = sender.findName("Page");
		page.Width = targetWidth;
		page.Height = targetHeight;

		var menu = sender.findName("Menu");
		menu["Canvas.Top"] = (targetHeight - menu["Height"]) / 2;
		menu["Canvas.Left"] = (targetWidth - menu["Width"]) / 2;

		var rect1 = sender.findName("rect1");
		rect1["Canvas.Top"] = menu["Canvas.Top"] - rect1["Height"] - this.indent + this.border;
		rect1["Canvas.Left"] = menu["Canvas.Left"] - rect1["Width"] - this.indent + this.border;

		var rect2 = sender.findName("rect2");
		rect2["Canvas.Top"] = menu["Canvas.Top"] - rect2["Height"] - this.indent + this.border;
		rect2["Canvas.Left"] = menu["Canvas.Left"] + menu["Width"] + this.indent - this.border;

		var rect3 = sender.findName("rect3");
		rect3["Canvas.Top"] = menu["Canvas.Top"] + menu["Height"] + this.indent - this.border;
		rect3["Canvas.Left"] = menu["Canvas.Left"] - rect3["Width"] - this.indent + this.border;

		var rect4 = sender.findName("rect4");
		rect4["Canvas.Top"] = menu["Canvas.Top"] + menu["Height"] + this.indent - this.border;
		rect4["Canvas.Left"] = menu["Canvas.Left"] + menu["Width"] + this.indent - this.border;
	}
}

А в файле Default.html.js исправим свойства width и height на 100% Вот теперь все стало совсем красиво. :)

Увы, в данном случае без ложки дегтя не обошлось. То, что красиво выглядит в IE далеко не всегда также выглядит в Firefox. Точнее, если запустить Default.html, в FF, то все будет выглядеть аналогично IE. Но стоит заменить Default.html на Default.aspx, и тут же FF отказывается воспроизводить наш пример. На всякий случай приведу код Default.aspx:

КОД HTML:

<!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">
<head runat="server">
	<title>SilverLight Application</title>
	<script type="text/javascript" src="Silverlight.js"></script>
	<script type="text/javascript" src="Default.html.js"></script>
	<script type="text/javascript" src="XamlForm.js"></script>
</head>
<body leftmargin="0" topmargin="0" marginheight="0" marginwidth="0">
<form id="form1" runat="server">
	<div id="SilverlightPlugInHost">
		<script type="text/javascript">
			createSilverlight();
		</script>
	</div>
</form>
</body>
</html>

Экспериментальным путем выяснил, что FF плохо реагирует на width и height в Default.html.js указанные в %. Поэтому придется от них избавиться. Чтобы в обоих браузерах была полная аналогия придется поправить некоторый код. В файле Default.html.js добавить строку:

Код JavaScript:

var plugIn = null;

Файл XamlForm.js переписать следующим образом:

SilverlightJSApplication1.Scene.prototype =
{
	handleLoad: function(plugIn, userContext, rootElement)
	{
		this.plugIn = plugIn;
		this.plugIn.content.onResize = Silverlight.createDelegate(this, this.onResize);
		top.plugIn = plugIn;

		this.border = 5;
		this.indent = 100;
		this.animate = false;

		rootElement.addEventListener("MouseLeftButtonDown", Silverlight.createDelegate(this, this.handleMouseDown));

		if (window.navigator.userAgent.indexOf("MSIE ") &gt; 0)
		{
			this.plugIn.width = window.document.body.offsetWidth;
			this.plugIn.height = window.document.body.offsetHeight;
		}
		else
		{
			this.plugIn.width = window.innerWidth;
			this.plugIn.height = window.innerHeight;
		}
	},

	// Sample event handler
	handleMouseDown: function(sender, eventArgs)
	{
		if (this.animate == false)
		{
			this.animation = sender.findName("animation");
			this.animation.begin();
			this.animate = true;
		}
	},

	onResize: function(sender, args)
	{
		var page = sender.findName("Page");
		page.Width = window.document.body.offsetWidth;
		page.Height = window.document.body.offsetHeight;
	},

	function onBodyResize(body)
	{
		if (window.navigator.userAgent.indexOf("MSIE ") &gt; 0)
		{
			top.plugIn.width = window.document.body.offsetWidth;
			top.plugIn.height = window.document.body.offsetHeight;
		}
		else
		{
			top.plugIn.width = body.innerWidth;
			top.plugIn.height = body.innerHeight;
		}
	}
}

И добавить пару атрибутов в файла Default.aspx:

style=”width: 100%; height: 100%; overflow: hidden;” onresize=”onBodyResize(this)”

Вот теперь все! :)

Сатья взята со страницы пользователя Daniel Auer’s

Оригинал:
http://danielauer.livejournal.com/23812.html?mode=reply

личная страница пользователя:
http://danielauer.livejournal.com/

Popularity: 55% [?]

Add to zakladki:
Нет Комментариев | Примеры | Вся статья

Leave a Reply

Ваш Комментарий * [b][/b] - [i][/i] - [u][/u]- [quote][/quote]