Это очень просто, довольно весело и демонстрирует небольшое использование Rx, довольно необычно использует API Bing Image Search — и это сыграет вспомогательную роль в моем новом приложении для Windows Phone 7. Базовая структура поведения настраивается с использованием библиотеки SafeBehavior # wp7nl, которую я описал ранее:
using System;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Xml;
using System.Xml.Linq;
using Microsoft.Phone.Reactive;
namespace Wp7nl.Behaviors
{
/// <summary>
/// A behavior that puts an image on the background of the Attched object
/// using Bing Image Search
/// </summary>
public class DynamicBackgroundBehavior : SafeBehavior<Panel>
{
private ImageBrush backgroundBrush;
public DynamicBackgroundBehavior()
{
Opacity = 1.0;
}
#region SearchString
public const string SearchStringPropertyName = "SearchString";
/// <summary>
/// The search string to be used on Bing Maps
/// </summary>
public string SearchString
{
get { return (string)GetValue(SearchStringProperty); }
set { SetValue(SearchStringProperty, value); }
}
public static readonly DependencyProperty SearchStringProperty =
DependencyProperty.Register(
SearchStringPropertyName,
typeof(string),
typeof(DynamicBackgroundBehavior),
new PropertyMetadata(String.Empty, SearchStringChanged));
public static void SearchStringChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var behavior = d as DynamicBackgroundBehavior;
if (behavior != null)
{
behavior.StartGetFirstImage((string)e.NewValue);
}
}
#endregion
/// <summary>
/// Bing search key
/// </summary>
public string BingSearchKey { get; set; }
/// <summary>
/// Stretch used for the image
/// </summary>
public Stretch Stretch { get; set; }
/// <summary>
/// Opacity used for the image
/// </summary>
public double Opacity { get; set; }
}
}
Короче говоря, это поведение имеет четыре свойства:
- помутнение
- Протяжение
- BingSearchKey
- SearchString

BingSearchKey — это строка длиной 40 символов, идентифицирующая ваше приложение. Вы должны создать ключ для своего приложения на портале Bing Developer . Нажмите левую кнопку («Войти — API поиска Bing») и заполните форму, изображенную справа (нажмите для увеличения изображения).
Примечание: поведение ссылается на Microsoft.Phone.Reactive — поэтому проект, в котором это происходит, должен называться Microsoft.Phone.Reactive.dll и System.Observable.dll.
Перейдем к настройке поведения, которая теперь очень проста, так как мы опираемся на SafeBehavior:
/// <summary>
/// Setup the behavior
/// </summary>
protected override void OnSetup()
{
backgroundBrush = new ImageBrush
{
Stretch = Stretch,
Opacity = Opacity
};
// Set the image brush to the background of the Panel
AssociatedObject.Background = backgroundBrush;
}
Проще говоря: создайте кисть Image, используя настройки свойств, и поместите ее в качестве фона для элемента GUI, к которому привязано поведение.
Метод, который вызывается из SearchStringChanged (который запускается при изменении свойства зависимости SearchString), реализован, как показано ниже:
/// <summary>
/// Start the image request using Bing Serach
/// </summary>
/// <param name="searchString"></param>
protected void StartGetFirstImage(string searchString)
{
var queryUri =
string.Format(
"http://api.bing.net/xml.aspx?Appid={0}&query={1}&sources=image",
BingSearchKey, searchString);
var request = WebRequest.Create(queryUri) as HttpWebRequest;
var response =
Observable.FromAsyncPattern<WebResponse>(
request.BeginGetResponse, request.EndGetResponse)();
response.Subscribe(WebClientOpenReadCompleted, WebClientOpenReadError);
}
Uri формируется с использованием BingSearchKey и фактической строки поиска, а также в разделе «sources = image», сообщающем Bing, что нужно возвращать изображения. Это Ури подается на стандартный веб-запрос. И тогда в игру вступает инфраструктура Rx, чтобы легко обработать процесс асинхронного чтения. Использование Observable.FromAsyncPattern и Subscribe имеет явное преимущество, заключающееся в том, что нет необходимости подключать все виды обработчиков событий, перехватывать ошибки с помощью блоков try-catch и не забывать отключать обработчики событий, когда чтение завершено. Платформа Rx обрабатывает все это, поэтому мне не нужно беспокоиться об этом.
Последний фрагмент поведения — фактическая обработка изображения:
/// <summary>
/// Called when image search returns
/// </summary>
/// <param name="result"></param>
private void WebClientOpenReadCompleted(WebResponse result)
{
using (var stream = result.GetResponseStream())
{
using (var reader = XmlReader.Create(stream,
new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore }))
{
var doc = XDocument.Load(reader);
// Get the first image from the result
XNamespace ns = "http://schemas.microsoft.com/LiveSearch/2008/04/XML/multimedia";
if (doc.Root != null)
{
var firstImage = doc.Root.Descendants(ns + "MediaUrl").FirstOrDefault();
if (firstImage != null)
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
var bi = new BitmapImage
{
UriSource = new Uri(firstImage.Value),
CreateOptions = BitmapCreateOptions.BackgroundCreation
};
backgroundBrush.ImageSource = bi;
});
}
}
}
}
}
/// <summary>
/// Called upon a search error (not used)
/// </summary>
/// <param name="ex"></param>
private void WebClientOpenReadError(Exception ex)
{
}
Поскольку на страницу xml.aspx ссылаются, Bing возвращает результат в виде документа xml. Если вас интересуют подробности результатов поиска Bing, не стесняйтесь исследовать документ XML — этот код в основном просто находит первый тег «MediaUrl», создает из него BitMapImage и помещает результат в backgroundBrush. И мы сделали.

Я собрал небольшое демонстрационное приложение, содержащее и демонстрирующее поведение . Это отклоняется двумя способами от моего обычного режима работы. Во-первых, не работает из коробки — сначала вам нужно получить собственный ключ API поиска Bing. Второе: он не использует MVVM — у меня есть данные, привязывающие свойство SearchString поведения непосредственно к свойству TextBox Text, которое заставляет поведение начинать поиск фона сразу же после начала набора текста, как показано слева. Так что, если вы наберете «морковь» в текстовое поле, то получите — изображение моркови ?
Ну, это все на 2011 год. Это особенный для меня год с некоторыми взлетами и падениями, когда награда MVP для Windows Phone Development определенно стала главным событием в категории «взлеты». Теперь до 2012 года, который, я думаю, окажется действительно очень интересным. Я надеюсь, что вы все продолжите получать удовольствие от этого блога, как и я — и вы, очевидно, тоже в 2011 году.