Украина |
Silverlight и WPF в Visual Studio 2010 (продолжение)
Поддержка нескольких окон
Для приложений с повышенными привилегиями, работающих вне браузера, стало возможным отображать несколько немодальных окон, которые могут перемещаться за пределы родительского окна, а также интегрируются с панелью задач Windows 7.
Ниже приведен небольшой код, который, внутри конструктора главного окна, генерирует дочернее окно и делает его видимым:
public MainPage() { InitializeComponent(); Window childWindow = new Window(); childWindow.Height = 400; childWindow.Width = 600; childWindow.Top = 30; childWindow.Left = 30; childWindow.Title = "Child Window"; childWindow.Visibility = Visibility.Visible; }
В данном примере дочернее окно создается с размерами 600 на 400, при этом верхний левый его угол будет находиться в позиции (30, 30), относительно экрана системы (не родительского окна). При этом обратите внимание на то, что созданное окно поддерживается панелью задач Windows 7 (рис. 7.4):
Доступ к файловой системе для приложений с повышенными привилегиями
Технология Silverlight 4 поддерживала возможность приложениям с повышенными привилегиями получать доступ к файловой системе пользователя. Правда, доступ был ограничен лишь несколькими папками. Так, в режиме с повышенными привилегиями, приложения получают полный контроль к специальным папкам, ассоциированным с пользователем: MyDocuments, MyVideos, MyPictures, MyMusic. Пути к указанным папкам можно получить, используя статический класс Environment. При этом нужно отметить, что SilverLight-приложение работает только с папками, но не с библиотеками (Windows 7).
В Silverlight 5 появилась возможность взаимодействовать со всей файловой системой пользователя. Речь идет как о чтении файлов, так и о записи.
Установка имени файла по умолчанию в SaveFileDialog
Теперь при вызове этого диалогового окна, можно установить имя файла (как и список расширений), которое будет отображаться по умолчанию, как имя файла, предлагаемого для записи. Вот как это выглядит:
SaveFileDialog dialog = new SaveFileDialog(); dialog.DefaultFileName = "hello.txt"; dialog.ShowDialog();
Кроме описанной возможности, появилось свойство InitialDirectory, позволяющее задать директорию, которая будет открыта в диалоге по умолчанию.
Улучшение работы с аудио
В Silverlight 5 стала доступна библиотека по работе с Media. Классы этой библиотеки представлены пространством имен Microsoft.Xna.Framework.Audio. Нетрудно догадаться, что данный шаг выполнен в рамках интеграции с XNA библиотеками, которые можно использовать и в Silverlight (это аудио и 3D).
Новое пространство имен содержит два основных класса, позволяющих создавать аудио эффекты в процессе работы Silverlight приложения. Файлы, доступные для проигрывания, должны быть в формате WAV и могут быть загружены с помощью класса SoundEffect. Конструктор этого класса получает ссылку на набор данных и (или) настройки аудио. Создание конкретного экземпляра можно также выполнить с помощью статического метода FromStream, получающего ссылку на поток в качестве параметров. Проигрывание эффекта осуществляется с помощью метода Play. Каких-то других методов SoundEffect не имеет, но это вовсе не означает, что отдельно взятым объектом нельзя управлять. Так, если вы хотите не просто воспроизвести эффект, но и добавить элементы управления аудио (громкость, пауза и т .д.), то вместо метода Play следует вызывать метод CreateInstance, создающий конкретный экземпляр на базе SoundEffect, и возвращающий ссылку типа SoundEffectInstance, которая позволит управлять нашим аудио файлом.
SoundEffect sEffect=SoundEffect.FromStream(streamInfo.Stream); sEffect.Play();
Изменение скорости проигрывания медиа
В Silverlight 5 произошли улучшения и в MediaElement элементе. Теперь этот элемент управления содержит такое свойство как PlaybackRate и событие RateChanged. Свойство позволяет задавать скорость проигрывания, синхронизировать видео и звук, а также выполнять "переметку" не только вперед, но и назад. Предполагается, что можно будет использовать следующие множители для скорости проигрывания: 0.2, 0.4, 0.6, 0.8, 1, 2, 4, 8, 16, 32. Событие RateChanged позволит реагировать на изменение свойства.
Поддержка пульта дистанционного управления
Silverlight 5 поддерживает и работу с пультом. Данная функциональность стала доступна благодаря поддержке события MediaCommand, которое доступно у всех UIElement. Иными словами, если вы хотите обрабатывать нажатия кнопок пульта, то Вам следует обработать это событие у родительского контейнера (от дочерних элементов оно как раз туда и свалится). Чтобы понять, какая кнопка на пульте была нажата, обработчик события получает доступ к свойству в MediaCommandEventArgs, содержащему свойство перечислимого типа MediaCommand. Последнее и содержит информацию по нажатой кнопке.
Работа с текстом
Silverlight 5 предлагает несколько интересных возможностей при работе с текстом. Так, элементы управления Control, TextBlock и TextElement, имеют новое свойство CharacterSpacing. Это свойство позволяет установить расстояние между символами внутри текста.
Свойство LineHeight позволяет установить ширину строки (можно интерпретировать, как расстояние между строками) и определено в таких элементах как Block, TextBlock, TextBox и RichTextBox. Для элемента RichTextBox можно также задать стратегию с помощью свойства LineStackingStrategy. На рис. 7.5 пример текста внутри элемента TextBlock с расстоянием между строками 30 и расстоянием между символами – 200:
Наконец, Silverlight 5 стал поддерживать два новых текстовых элемента, это RichTextBlock и RichTextBlockOverflow. Эти элементы аналогичны элементам RichTextBox и RichTextBoxOverflow, но позволяют отображать текст только на чтение.
Рассмотрим небольшой пример с элементом RichTextBlockOverflow:
<StackPanel x:Name="LayoutRoot" Background="White" Orientation="Horizontal" VerticalAlignment="Top"> <RichTextBlock Width="250" FontSize="16" OverflowContentTarget= "{Binding ElementName=SecondBox}"> <Paragraph> В лесу родилась елочка, </Paragraph> . . . . . . . . //повторить 20 разJ </RichTextBlock> <RichTextBlockOverflow Width="250" Name="SecondBox"> </RichTextBlockOverflow> </StackPanel>
Результат работы этого кода показан на рис. 7.6:
Как видно, RichTextBlockOverflow может отображать текст, который не "вмещается" в основной элемент RichTextBlock. Благодаря таким элементам мы можем размещать текст в 2, 3 и более колонках (или реализовывать более сложные сценарии).
Печать
Silverlight 5 позволяет теперь не только реализовать растровую, но и векторную печать. Для этих целей используется все тот же метод Print класса PrintDocument, который осуществляет попытку печати в векторном формате, а в случае неудачи (принтер не поддерживает), перейти к печати в растровом виде. Растровую печать можно инициировать с помощью нового метода PrintBitmap.
P/Invoke
В документации эта возможность пока не описана, но она уже реализована – возможность вызова методов Windows API из Silverlight приложений, обладающих повышенными полномочиями. Причем речь идет о приложениях, которые работают как в браузере, так и вне браузера. Поскольку вызов нативных функций в .NET обычно осуществляется с помощью атрибута DllImport. Запустим приложение с повышенными привилегиями:
public partial class MainPage : UserControl { [DllImport("user32.dll", CharSet = CharSet.Unicode)] public static extern int MessageBox(IntPtr hWnd, String text, String caption, uint type); public MainPage() { MessageBox(new IntPtr(0), "Hello World!", "Hello Dialog", 0); InitializeComponent(); } }
На экране поверх браузера вы увидите стандартный MessageBox.
Отладка при связывании с данными
Современный отладчик в Visual Studio давно позволяет разработчику получать всю необходимую информацию, если речь идет о коде на C#, C++ или даже JavaScript. Но как только речь заходит о XAML, то тут механизмы отсутствуют. Казалось бы, зачем нужна отладка в XAML, если тут идет декларативное описание интерфейса приложения. Действительно, отладка в XAML не нужна, если речь не идет о связывании с данными. Небольшой кусок кода, связывающий наши данные и интерфейс, может вызвать массу проблем при отладке. Ведь причин для возникновения проблем при связывании может быть множество, это и отсутствие какого-либо свойства, и проблемы с преобразованием либо же несоответствие типа. Но если связывание с данными описывается в XAML, то механизма получить информацию о проблеме не было. В Silverlight 5 возможна отладка XAML кода, описывающего связывание элементов управления и данных.
Рассмотрим небольшой пример кода на XAML:
<UserControl x:Class="SilverlightApplication1.MainPage" xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml xmlns:d=http://schemas.microsoft.com/expression/blend/2008 xmlns:mc=http://schemas.openxmlformats.org/markup-compatibility/2006 Loaded="UserControl_Loaded" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> <Grid x:Name="LayoutRoot" Background="White"> <Grid.Resources> <Style TargetType="TextBox"> <Setter Property="Background" Value="AliceBlue"></Setter> <Setter Property="Width" Value="200"></Setter> <Setter Property="Margin" Value="5"></Setter> </Style> <Style TargetType="TextBlock"> <Setter Property="Margin" Value="5"></Setter> </Style> </Grid.Resources> <Grid.RowDefinitions> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"></ColumnDefinition> <ColumnDefinition Width="Auto"></ColumnDefinition> </Grid.ColumnDefinitions> <TextBlock Text="First Name:" Grid.Column="0" Grid.Row="0"/> <TextBlock Text="First Name:" Grid.Column="0" Grid.Row="1"/> <TextBlock Text="First Name:" Grid.Column="0" Grid.Row="2"/> <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding FisrtName}"/> <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding LastName}"/> <TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Age}"/> </Grid> </UserControl>
В результате мы получим небольшую формочку, которая позволяет заполнить три поля. Код, необходимый для работы формы, может выглядеть так:
private void UserControl_Loaded(object sender, RoutedEventArgs e) { Person p = new Person(); p.FirstName = "Sergey"; p.LastName="Baydachnyy"; p.Age = 33; LayoutRoot.DataContext = p; }
И класс Person:
public class Person { public string FirstName { get; set; } public string LastName { get; set; } public int Age { get; set; } }
Запустив это приложение, можно убедиться, что первое поле не было заполнено данными. Чтобы понять причину ошибки, достаточно установить Breakpoint в XAML файле на строку, описывающую связывание в первом поле, и запустить приложение в режиме отладки. Вот что можно увидеть в окне Locals:
Тут и информация об ошибке (ошибка намеренно сделана в имени поля) и данные об объекте и т. д. То есть, сгенерированный объект BindingState четко позволяет выявить проблему и проверить правильность данных.