Блог Сергея Байдачного

Мой блог о технологиях

Archive for Январь 2nd, 2010

Введение в SilverLight 4: правая кнопка мыши

3 комментария

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

SilverLight 4 позволяет полностью переопределить поведение при нажатии правой кнопки. При этом программист вовсе не обязан отображать меню. Действие может полностью зависеть от самого приложения.

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

· Отключить существующее меню. Для этого нужно определить обработчик с события MouseRightButtonDown и установить свойство Handled в true. Это сигнализирует о том, что мы берем обработку события на себя и стандартное меню отображать не нужно;

· Определить вызов собственного меню (или любые другие действия) в обработчике события MouseRightButtonDown.

Расширим функционал предыдущего приложения, добавив контекстное меню к изображениям на панели. Для этого, расширим метод photoPanel_Drop, добавив следующий код:

 
img.MouseRightButtonDown += new 
   MouseButtonEventHandler(img_MouseRightButtonDown);
img.MouseRightButtonUp += new
   MouseButtonEventHandler(img_MouseRightButtonUp);

 

Теперь реализуем сами обработчики событий. Начнем с MouseRightButtonDown:

 
void img_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
    e.Handled = true;
}

 

Как видно, тут нет ничего сложного. Мы просто нотифицируем SilverLight о перехвате события правой кнопки и подавляем отображение стандартного контекстного меню.

Теперь реализуем MouseRightButtonUp. Тут есть проблема, которая состоит в том, что если Вы хотите отобразить меню, то его нужно реализовать самостоятельно, или обратиться к сторонним разработчикам за дополнительными компонентами. В списке стандартных компонент и в SDK контекстное меню пока не реализовано. Я не стал разрабатывать меню сам, а установил тестовую версию с сайта: http://www.telerik.com. Тут Вы можете найти множество элементов управления для SilverLight 4.

Замечание. Никогда не используйте контекстное меню от Telerik так, как показано ниже. Компонент достаточно «умный», чтобы отобразить меню в качестве реакции на какое-то событие. Кроме того, этот элемент можно ассоциировать с любым интерфейсным элементом в момент его создания. Но, если сделать все правильно, то обработчик события для правой кнопки мыши и не понадобитсяJ Поэтому будем создавать меню именно при нажатии правой кнопки мыши и уничтожать его в «ручном» режиме.

private Image menuImage;
private RadContextMenu contextMenu;
       
void img_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
    menuImage = (Image)sender;
    if (contextMenu != null)
    {
        photoPanel.Children.Remove(contextMenu);
    }
 
    contextMenu = new RadContextMenu();
    contextMenu.Items.Add("Delete");
    contextMenu.Items.Add("Close Menu");
 
    Point p=e.GetPosition(photoPanel);
 
    contextMenu.Margin = new Thickness(p.X, p.Y, 0, 0);
    photoPanel.Children.Add(contextMenu);
 
    contextMenu.ItemClick += new 
        Telerik.Windows.RadRoutedEventHandler(menu_ItemClick);
}
 
void menu_ItemClick(object sender, 
        Telerik.Windows.RadRoutedEventArgs e)
{
    RadRoutedEventArgs args = e as RadRoutedEventArgs;
    RadMenuItem menuItem = args.OriginalSource as RadMenuItem;
    string tag = Convert.ToString(menuItem.Header);
    switch (tag)
    {
        case "Delete":
            photoPanel.Children.Remove(menuImage);
            photoPanel.Children.Remove(contextMenu);
            break;
        case "Close Menu":
            photoPanel.Children.Remove(contextMenu);
            break;
    }       
    contextMenu = null;
}

В коде выше я реализовал механизм создания нового контекстного меню, а также механизм обработки события, связанного с выбором пункта меню. Частично продублировал работу, уже реализованную в компоненте, но…

Ниже показан снимок экрана во время работы приложения.

image

Реклама

Written by Sergiy Baydachnyy

02.01.2010 at 21:51

Опубликовано в SilverLight

Tagged with

Введение в SilverLight 4: Печать

with one comment

Одна из важных и фундаментальных возможностей, которая должна значительно расширить возможности SilverLight-приложений, это печать.

Для демонстрации возможности печати, будем использовать пример из предыдущего поста, определив обработчик события Click для кнопки printButton, объект типа PrintDocument и обработчик события PrintPage. Вот как будет выглядеть наш код:

private PrintDocument printDoc;
 
public MainPage()
{
    InitializeComponent();
 
    printDoc.PrintPage += new 
       EventHandler<PrintPageEventArgs>(printDoc_PrintPage);
}
 
void printDoc_PrintPage(object sender, PrintPageEventArgs e)
{
    e.PageVisual = photoPanel;
    e.HasMorePages = false;
}
 
private void printButton_Click(object sender, RoutedEventArgs e)
{
    printDoc.DocumentName = "Images";
    printDoc.Print();
}
 

Как видно из этого примера, за печать в SilverLight отвечает класс PrintDocument, объект которого мы создали в коде выше. Объект этого класса способен генерировать три события: StartPrint, EndPrint и PrintPage. Первые два события позволяют провести предварительную подготовку к печати и получить информацию об успешном завершении печати соответственно. А вот обработчик события PrintPage как раз и выполняет всю черновую работу. Задача обработчика события PrintPage получить параметры страницы (тут только длина и ширина отображаемой области), используя параметр типа PrintPageEventArgs, сформировать содержимое страницы и отправить ее на печать. При этом управление печатью нескольких страниц происходит с помощью свойства HasMorePages.

Фактически, объект типа PrintDocument способен печатать любой элемент, порожденный от UIElement, то есть, для печати страницы Вы можете выбрать любой из контейнеров, расположить в нем свои элементы и передать ссылку на этот контейнер с помощью свойства PageVisual. В примере выше, мы не формировали специальную страницу для печати, а просто использовали существующий контейнер, отображающий наши картинки.

Written by Sergiy Baydachnyy

02.01.2010 at 08:55

Опубликовано в SilverLight

Tagged with

Введение в SilverLight 4: Drag and Drop

leave a comment »

Уже две недели прошло с момента анонса SilverLight 4, а я только сел писать об этой новой потрясающей технологии. Обещаю исправиться и наверстать упущенное.

Обзор новых возможностей начнем с простого, но приятного нововведения в SilverLight 4 – поддержки технологии Drag & Drop. Естественно, речь идет ни о том, как перемещать элементы внутри самого SilverLight – приложения (это легко сделать и в первой версии), а как передать приложению внешний объект, находящийся на машине пользователя.

Чтобы продемонстрировать новые возможности, разработаем приложение, в окно которого можно перетянуть ряд изображений (в формате, поддерживаемом SilverLight) и отобразить их. Для этой цели в SilverLight 4 присутствует очень полезное свойство AllowDrop, которое доступно у любого из наследников UIElement, то есть у любого из визуальных элементов. Это означает, что перетащить внешний объект можно на любой из визуальных элементов, а не только на контейнер. Устанавливая свойство AllowDrop в значение True, разработчик инициирует работу четырех событий, которые можно использовать для реализации Drag & Drop технологии: Drop, DragEnter, DragLeave, DragOver. Основным событием является Drop, именно оно генерируется при завершении операции перетаскивания объекта. Остальные три события генерируются при перемещении курсора мыши, захватившего объект, но до завершения операции перетаскивания, то есть эти события являются вспомогательными и могут быть использованы для дополнительной визуализации процесса перетаскивания в интерфейсе (например, выделение областей, доступных для освобождения объекта, цветом).

Реализуем простой интерфейс, содержащий кнопку и панель типа Canvas. Объект на основе Canvas подходит для наших целей лучше всего, так как позволяет привязать отображаемое изображение к координатам курсора мыши.

<UserControl x:Class="DragAndDrop_Chapter0.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="50"></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <Button x:Name="printButton" Content="Print" Width="100"></Button>
        <Border Grid.Row="1" x:Name="photoBorder" 
            BorderBrush="Blue" BorderThickness="4">
            <Canvas x:Name="photoPanel" Grid.Row="1" 
                    Background="Gray" AllowDrop="True"
                    Drop="photoPanel_Drop"
                    DragEnter="photoPanel_DragEnter"
                    DragLeave="photoPanel_DragLeave">
            </Canvas>
        </Border>
    </Grid>
</UserControl>

Панель photoPanel мы будем использовать для отображения изображений, перетянутых с компьютера пользователя. Тут же мы определили свойство AllowDrop, установленное в True и указали обработчики событий.

Ниже показана реализация описанных выше обработчиков событий Drop, DragEnter, DragLeave.

private void photoPanel_Drop(object sender, DragEventArgs e)
{
    photoBorder.BorderBrush = new SolidColorBrush(Colors.Blue);
 
    IDataObject data = e.Data;
    FileInfo[] files = (FileInfo [])data.GetData
        (DataFormats.FileDrop);
 
    foreach (FileInfo f in files)
    {
        Stream s=f.OpenRead();
        BitmapImage bitmap=new BitmapImage();
        bitmap.SetSource(s);
 
        Image img = new Image();
        img.Source = bitmap;
 
        img.Width = 100;
        img.Height = 80;
 
        Point p = e.GetPosition(photoPanel);
        img.Margin = new Thickness(p.X, p.Y, 0, 0);
 
        photoPanel.Children.Add(img);
    }
}
 
private void photoPanel_DragEnter(object sender, DragEventArgs e)
{
    photoBorder.BorderBrush = new SolidColorBrush(Colors.Red);
}
 
private void photoPanel_DragLeave(object sender, DragEventArgs e)
{
    photoBorder.BorderBrush = new SolidColorBrush(Colors.Blue);
}

Последние два события мы обрабатываем лишь с целью выделить область, доступную для размещения перетаскиваемого объекта (тут нужно помнить, что при генерации события Drop, событие DragLeave уже не сгенерируется, поэтому нужно снять выделение и в Drop). А вот обработчик события Drop делает основную работу: получение информации о передаваемых файлах, открытие потока, загрузка и отображение изображения с помощью Pixel API (одно из новшеств SilverLight 3). Чтобы сделать код более читабельным, мы не обрабатываем ошибки, связанные с типом файлов, но в реальной задаче это необходимо сделать обязательно (попробуйте в этом примере перетащить текстовый файл или офисный документ).

Written by Sergiy Baydachnyy

02.01.2010 at 08:50

Опубликовано в SilverLight

Tagged with