Posted on 12. January 2011

SilverlightShow's ECO Contest

Ресурс SilverlightShow объявил конкурс Silverlight приложений Forests Eco Contest, который являеться частью акции International Year of Forests. В рамках этого конкурса необходимо разработать Silverlight приложение, которое будет информировать о катастрафической ситауции с сохранением лесов или способствовать защите этих ресурсов. Это еще одна возможность продемонстрировать свои возможности по созданию Silverlight приложений. Кроме того данный конкурс имеет свой набор призов. Главный приз – поездка на конференцию MIX11.

Правила участия в конкурсе читайте на сайте конкурса



Posted on 22. July 2010

Вышел релиз WCF RIA Services Contrib

WCF RIA Services Contrib – это коллекция инструментов для WCF RIA Serivces.

Текущая версия содержит набор расширения для классов Entity и EntitySet, которые добавляют возможности импорта и экспорта данных.

В этой версии Contrib добавлены методы ApplyState и ExtractState для объектов типа Entity, метод Import для объектов типа EntityList и метод Export для объектов типа IEnumerable, где T – Entity класс. Для использования этих методов необходимо подключить сборку RIAServicesContrib.dll и подключить пространство имен RiaServicesContrib.Extensions.

Пример использования перечисленных выше методов смотрите на странице решения.

Более детальное описание решения.



Posted on 8. July 2010

Обновился конвертер из Word в Xaml

Word to XAML Converter это расширение для Word 2010, которое позволяет конвертировать Office Open XML в XAML:

  • для WPF документ  преобразовывается в FlowDocument элемент;
  • для Silverlight документ преобразовывается в StackPanel элемент, который содержит в себе элементы TextBlock или RichTextBox

Изменения

  • расширение находится на закладке File в группе Save & Send;
  • исправлены ошибки после генерации XAML контента;
  • генерация Silverlight XAML разметки имеет две опции:
    • StackPanel + TextBlock: поддерживает форматирование через стили(эта опция предназначена для Windows Phone 7 контента);
    • RichTextBox: поддерживает картинки и графики, но не форматирование через стили.

Инструкцию по установке и использованию читайте на странице проекта

Оригинал.



Posted on 8. July 2010

Microsoft Silverlight Media Framework 2.0

Доступна 2-я версия Microsoft Silverlight Media Framework (SMF). Это открытое решение, которое позволяет разработчикам быстро создавать расширяемый и легко изменяемый медиа проигрыватель для воспроизведения контента формата Smooth Streaming. Ядро истемы разработано на основе Smooth Streaming Client, а также добавлено много других возможностей, включая расширяемый API, который позволяет создавать расширения для SMF.

Новинки версии 2.0

Данная версия имеет полностью новую архитектуру. В данной реализации она стала еще модульнее с большым количеством API для разработчиков и партнеров. Текущая архитектура позволяет исключать из проекта сборки, в которых нет нужды при работе приложения, тем самым позволяет уменьшить размер конечного Silverlight приложения. Текущая версия будет включать расширения для Timed Text, связывание фреймов, поддержку Microsoft Silverlight Analytics Framework, поддержку множества аудио треков, улучшен процесс наблюдения за битрейтом, поддержка глобольных стилей в Silverlight 4, Javascript API и др.

Скачать SMF можно на странице проекта. Следует отметить что 2-я версия SMF работает только с Silverlight 4. Для других версий Silverlight можно использовать более рание версии SMF.

Кроме этого разработчики написали о возможных нововвеедениях в следующих версиях продукта:

  • поддержка стандартов рекламы, такиз как VAST, MAST и VPAID через API;
  • фреймворк метаданных;
  • воспроизведения офлайн DRM и работа в режиме вне браузера;
  • глобализация.


Posted on 1. July 2010

Варианты реализации INotifyPropertyChanged

Инфраструктура Silverlight имеет мощную модель связывания данных. Одним из главных элементов данной возможности является интерфейс INotifyPropertyChanged. Он используется для уведомления клиента(это может быть интерфейс приложения или внутренние объекты приложения) об изменении свойств определенного объекта. В этом посте я хочу описать несколько возможных вариантов реализации INotifyPropertyChanged, которые появились в процессе его использовния.

Базовая реализация

При самом простом подходе реализации этого интерфейса нам необходимо объявить событие PropertyChanged. А также метод для запуска события. Пример реализации:

public class Customer : INotifyPropertyChanged
{
	public event PropertyChangedEventHandler PropertyChanged;
 
	protected void RaisePropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null && !String.IsNullOrWhiteSpace(propertyName))
            {
                 handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
}

Главная проблема, которая возникает при реализации INotifyPropertyChanged заключается в том, что бы значения параметра propertyName в методе RaisePropertyChanged сдалеть "дружественным" к рефакторингу.

Как правило, реализация свойства, которое извещается о своем изменении имеет следующий вид:

private string _firstName;
 
public string FirstName
{
	get
	{
		return _firstName;
	}
	set
	{
		if (!object.Equals(_firstName, value))
		{
			_firstName = value; 
			RaisePropertyChanged("FirstName");
		}
	}
}

 Иногда, код внутри "сеттера" заменяют на использование обобщенного метода:

protected bool SetValue(ref T property, T value, string propertyName)
{
	bool result = false;
	if (!Object.Equals(property, value))
	{
		property = value;
		OnPropertyChanged(propertyName);
		result = true;
	}

	return result;
}

Кроме этого необходимо изменить наше свойство

public string FirstName
{
	get
	{
		return _firstName;
	}
	set
	{
		SetValue(ref _firstName, value, "FirstName");
	}
}

Данное решение не является дружественным к рефакторингу: когда вы меняете название свойства вам необходимо вручную изменять название свойства которое находится внутри строки. Если вы этого не сделаете, то сборка проекта пройдет успешно, но в последствии могут появится ошибки, которые будет трудно исправлять. Для решения этой проблемы Josh Smith предложил следующее решение:

[Conditional("DEBUG")]
private void VerifyProperty(string propertyName)
{
	Type type = this.GetType();
 
	// Look for a public property with the specified name.
	PropertyInfo propInfo = type.GetProperty(propertyName);
 
	Debug.Assert(propInfo != null, string.Format(CultureInfo.InvariantCulture, "{0} is not a property of {1}", propertyName, type.FullName));
}

Следовательно нам необходи теперь изменить метод запуска события:

protected void RaisePropertyChanged(string propertyName)
{
	VerifyProperty(propertyName);
 
	PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null && !String.IsNullOrWhiteSpace(propertyName))
            {
                 handler(this, new PropertyChangedEventArgs(propertyName));
            }

}

Данный подход не выявит ошибок при компиляции проекта, если в параметре придет название свойства, которое отсутствует у объекта, но будет создана ошибка в режиме отладки, когда метод RaisePropertyChanged вызовется с несуществующим свойством. Тем не менее данный подход не покажет ошибки связанной с неправильным использованим параметра. Например:

private string _firstName;
private string _lastName;
 
public string FirstName
{
	get { return _firstName; }
	set { SetValue(ref _firstName, value, "FirstName"); }
}
 
public string LastName
{
	get { return _lastName; }
	set { SetValue(ref _lastName, value, "FirstName"); }
}

При использовании copy/past вероятность появления такого кода очень высока.

Использование Lambda Expressions и Expression Trees

Этот вариант заключается в использовании Lambda Expressions и Expression Trees для определения названия свойства. Ключевой точкой в этом подходе является следующий метод:

public static string GetPropertyNameFromExpression(Expression> property)
{
	var lambda = (LambdaExpression)property;
	MemberExpression memberExpression;
 
	if (lambda.Body is UnaryExpression)
	{
		var unaryExpression = (UnaryExpression)lambda.Body;
                memberExpression = (MemberExpression)unaryExpression.Operand;
	}
	else
	{
		memberExpression = (MemberExpression)lambda.Body;
	}
 
	return memberExpression.Member.Name;
}

с последующим добавлением обобщенного метода RaisePropertyChanged:

protected void RaisePropertyChanged(Expression> property)
{
RaisePropertyChanged(GetPropertyNameFromExpression(property));
}

Теперь свойство будет иметь вид:

private string _firstName;
 
public string FirstName
{
	get
	{
		return _firstName;
	}
	set
	{
		if (!Object.Equals(_firstName, value))
		{
			_firstName = value;
 
			RaisePropertyChanged(() => FirstName);
		}

	}
}

или же метод SetValue будет иметь следующий код: 

protected bool SetValue(ref T property, T value, Expression> propertyDelegate)
{
	var result = false;
	if (!Object.Equals(property, value))
	{
		property = value;
		RaisePropertyChanged(propertyDelegate);
		result = true
	}
	return result;
}

 мы можем изменить наше свойство следующим образом:

public string FirstName
{
	get
	{
		return _firstName;
	}
	set
	{
		SetValue(ref _firstName, value, () => FirstName);
	}
}

Положительная часть представленного решения заключается в дружественности к рефакторингу: если когда-нибудь имя свойства измениться используя интрумент рефакторинга, делегат также будет изменен и корректное имя будет использоваться в событии PropertyChanged. Еще одним преимуществом является то, что при опечатках мы получаем ошибки компиляции. Отрицательная сторона заключается в использовании отражения. Еще один негативный момент - при использовании copy/paste можно допустить ошибку:

private string _firstName;
private string _lastName;
 
public string FirstName
{
	get { return _firstName; }
	set { SetValue(ref _firstName, value, () => FirstName); }
}
 
public string LastName
{
	get { return_lastName; }
	set { SetValue(ref _lastName, value, () => FirstName); }
}

Использование MethodBase.GetCurrentMethod()

Karl Shifflett предложил иной подход в своей статье. Он предложил брать имя свойства используя MethodBase.GetCurrentMethod(). Таким образом реализация свойства приобретает следующий вид:

public string FirstName
{
	get
	{
		return _firstName;
	}
	set
	{
		SetValue(ref _firstName, value, MethodBase.GetCurrentMethod().Name.Remove(0,4));
	}
}

Это решение работает немного лучше, но все равно в каждом свойстве необходимо добавлять строку: MethodBase.GetCurrentMethod().Name.Remove(0,4)

А какие варианты передачи имени свойства используете вы?

 

Материалы по теме:



Posted on 26. June 2010

Синхронизация данных между потоками в Silverlight

В Silverlight, по-умолчанию, весь пользовательский код выполняется в потоке интерфейса. Тем самым при длительных операциях мы может заблокировать не только Silverlight приложение, но и весь браузер. Что является не дружественным поведенем нашего приложения по отношеню к пользователям. Для решения этой проблемы можно запускать паралельные потоки или использовать пул потоков. И уже непосредственно в паралельных потоках запускать длительные по времени операции. При этом в интерфейсе можно отобразить индикатор работы процесса(например BusyIndicator).

Для эмуляции длительной операции создадим новое Silverlight приложение и в коде добавим следующее

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Threading;

namespace Multithreading.Dispatcher
{
	public partial class MainPage : UserControl
	{
		public MainPage()
		{
			InitializeComponent();
			Loaded += new RoutedEventHandler(MainPage_Loaded);
		}

		void MainPage_Loaded(object sender, RoutedEventArgs e)
		{
			for (int z = 0; z < 1000000; z++)
			{
				for (int i = 0; i < 1000000; i++)
				{
					int j = i;
				}
			}
		}
	}
}

При запуске такого приложения мы получем заблокированное окно браузера:

Длительная операция в потоке интерфейса

Чтобы решить эту проблему изменим наше тестовое приложение так, чтобы длительная операция выполнялась в другом потоке:

void MainPage_Loaded(object sender, RoutedEventArgs e)
		{
			ThreadPool.QueueUserWorkItem(new WaitCallback((obj) =>
				{
					for (int z = 0; z < 100000; z++)
					{
						for (int i = 0; i < 10000; i++)
						{
							int j = i;
						}
					}

				}), null);

			busyIndicator.IsBusy = true;
		}

Результат работы наших изменений смотрите ниже:

Длительная операция в паралельном потоке с индикатором процесса

Но здесь мы получаем проблему синхронизации данных между потоком интерфейса и "рабочим" потоком. Например в нашем примере нам необходимо спрятать BusyIndicator по окончанию длительной операции. Для решения этой задачи инфраструктура Silverlight предоставляет несколько способов:

Использование Dispatcher

Dispatcher предоставляет возможность выполнения кода в потоке интерфейса из неинтерфейсного потока. Для нашего примера нужно изменить код на следующий:

void MainPage_Loaded(object sender, RoutedEventArgs e)
		{
			ThreadPool.QueueUserWorkItem(new WaitCallback((obj) =>
				{
					for (int z = 0; z < 100000; z++)
					{
						for (int i = 0; i < 10000; i++)
						{
							int j = i;
						}
					}

					Dispatcher.BeginInvoke(new Action(() =>
					{
						busyIndicator.IsBusy = false;
					}));
				}), null);

			busyIndicator.IsBusy = true;
		}

 Через метод BeginInvoke() мы указываем какой код необходимо выполнить в потоке интерфейса.

Использование SynchronizationContext

SynchronizationContext обеспечивает базовую функциональность для синхронизации контекста в различных моделях синхронизации. Данный подход является более мощным, чем использование Dispatcher. Например он позволяет выполнять код синхронно или асинхронно в потоке интерфейса по отношению к текущему потоку. При использовании контекста синхронизации его необходимо передать в "рабочий" поток. Пример:

void MainPage_Loaded(object sender, RoutedEventArgs e)
		{
			ThreadPool.QueueUserWorkItem(new WaitCallback((obj) =>
				{
					for (int z = 0; z < 100000; z++)
					{
						for (int i = 0; i < 10000; i++)
						{
							int j = i;
						}
					}

					((SynchronizationContext)obj).Post(new SendOrPostCallback((parameter) =>
						{
							busyIndicator.IsBusy = false;
						}), null);
				}), SynchronizationContext.Current);

			busyIndicator.IsBusy = true;
		}

Исходный код:



Posted on 16. June 2010

Темы для Silverlight приложений

На прошлой неделе было опубликовано несколько новых тем для шаблона Silverlight Business Application. Скачать обновленные Silverlight 4 темы можно по этому адресу.

Пакет тем состоит из трех файлов:

  • README_FIRST.txt
  • SL4Themes-templates.zip - включает каталог для шаблонов Expression Blend и Visual Studio. Католог для Visual Studio также содержит подкаталог для шаблонов RIA сервисов.
  • SL4Themes-rawassets.zip - включает справочники ресурсов для каждой темы.

Новые три темы:

Cosmopolitan

Silverlight 4 theme: Cosmopolitan

 

Windows 7 Theme

Silverlight 4 theme: Windows 7

 

Accent Color Theme

Silverlight 4 theme: Accent Color

 

Ссылки по теме:



Posted on 15. June 2010

Обновился Microsoft Silverlight Analytics Framework

В блоге я уже писал о данном решении. Выпуск текущей версии предназначен для синхронизации решения с выходом нескольких продуктов и технологий. Скачать установочный файл можно на сайте проекта. Новые возможности текущей версии:

Поддержка новых сервисов аналитики

  • Eqatec WebAnalytics EqatecAnalytics EQATEC Analytics
  • Omniture WebAnalytics OmnitureAppMeasurement Omniture, Adobe Company
  • Webtrekk WebAnalytics WebtrekkAnalytics Webtrekk
  • Новые элементы управления

  • ComponentOne
  • Infragistics
  • Telerik
  • IIS Smooth Streaming Client 1.0
  • Microsoft Silverlight Media Framework 2.0
  • Поддержка Silverlight 3, Silverlight 4 и WPF

    Кроме этого проект содержит ряд других улучшений.

    Ссылки по теме:



    Posted on 3. June 2010

    Вышел Prism 4.0 Drop 1

    Не так давно я описал о том, что Composite Application Guidance for WPF and Silverlight обновился. И вот еще одно обновление.

    Эта версия включает в себя 2-а новые решения QuickStarts и Stock Trader Reference. QuickStarts содержит:

    • Model-View-ViewModel (MVVM). Это решение находится в каталоге QuickStart. Для него необходим установлений Silverlight.
    • Модульность используя Managed Extensibility Framework (MEF). Тоже находится в катологе QuickStart и требует установленый .NET 4.0.

    Данная версия находится только в Alpha, поэтому разработчики решения очень нуждаются в отзывах о текущем решении. MVVM можно запускать без каких-либо библиотек Prism.

     

    Системные требования

    Перед тем, как использовать Prism, необходимо установить:

     

    Вы также можете установить:



    Posted on 31. May 2010

    Обновления в Silverlight 4 Training Kit

    Ранее компания Microsoft выпустила Silverlight 4 Training Kit. Курс содержит описание новых возможностей Silverlight 4, лабораторные работы по возможностям Silverlight 4 и 8-м модулей по разработке бизнес приложений используя Silverlight 4 технологию. Все модули, как и 25-ть видео записей, рассматривают ключевые моменты создания бизнес приложений. В данный момент курс развивается дальше. Его создатели планируют добавить примеры кодов на VisualBasic и расширить курс. Во время подготовки было выявленно несколько ошибок, о которых подробнее читайте в блоге John Papa.