Surface 2.0 SDK - Drag & Drop API Udostępnij na: Facebook

Autor: Tomasz Kowalczyk

Opublikowano: 2011-11-18

Artykuł ten jest trzecim z serii artykułów, wprowadzających programistę w techniki programowania aplikacji sterowanych dotykiem. Opisuje on, w jaki sposób wykonać oprogramowanie, posiadające funkcję „przeciągnij i upuść”. Jest to powszechnie używana funkcja nie tylko w aplikacjach dotykowych, polegająca na przemieszczaniu obiektu z jednego obszaru do drugiego za pomocą pojedynczego ruchu.

Wiele kontrolek, dostępnych dla programistów, zawartych w Surface 2.0 SDK, posiada predefiniowaną możliwość użycia ich zgodnie z przeznaczeniem funkcji „przeciągnij i upuść”. Kontrolki, które natomiast nie posiadają takiej możliwości, mogą korzystać z dostępnego Drag & Drop API. Biblioteki te pozwalają na używanie funkcji „przeciągnij i upuść” z każdą kontrolką, dostępną w Surface 2.0 SDK.

Artykuł zawiera informacje o:

Wprowadzenie

Surface 2.0 SDK Drag & Drop API pozwala na implementacje funkcji „przeciągnij i upuść” dla wielu obiektów jednocześnie. Biblioteka ta zawiera klasę, która reprezentuje przeciągany obiekt oraz klasy zdarzeniowe, których zadaniem jest wywołanie odpowiedniej metody podczas „przeciągania” i „upuszczania” obiektu pomiędzy różnymi obszarami.

Podczas „przeciągania” i „upuszczania” obiektów, w obrębie aplikacji, istotną rolę odgrywają trzy elementy:

  • źródło – obszar, z którego pochodzą przeciągane obiekty,
  • kursor – element, będący graficzną reprezentacją zdarzenia przeciągania obiektu,
  • cel – obszar, na który obiekty są przeciągane.

W celu przedstawienia możliwości, jakie daje biblioteka Drag & Drop API, w artykule tym zostanie opisana implementacja oprogramowania, korzystającego z możliwości urządzeń wielodotykowych.

Informacja
Wszystkie kody źródłowe projektów, utworzonych w ramach artykułów, będą dostępne na tej stronie.

Implementacja

Aplikacja, przygotowana w celu wyjaśnienia materiału, zawartego w tym artykule, pozwala na wyświetlenie zdjęć w jednej z kontrolek platformy Surface:LibraryContainer lub LibraryBar. Następnie tak wyświetlone zdjęcia będą mogły być przeciągane do kontrolki ScatterView, gdzie dostępne dla nich będą wszystkie operacje, udostępniane przez tę kontrolkę tj. przemieszczanie po ekranie, obracanie i zmiana rozmiaru. Użytkownik, korzystając z tej aplikacji, będzie mógł również przeciągnąć zdjęcia z powrotem z kontrolki ScatterView do kontrolki LibraryContainer.

Przygotowanie projektu

W celu implementacji wyżej opisanego projektu, przede wszystkim musisz uruchomić Visual Studio 2010. Następnie wybierz opcję File, potem New i Project. Z kolumny, znajdującej się po lewej stronie, wybierz opcję Surface. Aplikacja ta będzie korzystała z WPF.

Następnie wykonaj kolejno poniższe kroki:

  1. Do projektu dodaj nowy katalog o nazwie Images, w którym będą znajdowały się zdjęcia początkowo wyświetlane w kontrolce LibraryContainer. Aby to zrobić kliknij prawym przyciskiem myszy na nazwę projektu, a następnie na opcje Add i New Folder. W oknie Eksploratora Windows przenieś do tego folderu parę zdjęć i dodaj je do projektu. Aby tego dokonać, po skopiowaniu plików do katalogu Images, w oknie Solution Explorer środowiska Visual Studio 2010 wybierz katalog Images. Następnie z menu głównego Visual Studio 2010 wybierz Project i Show All Files. Kolejno wybierz teraz prawym przyciskiem myszy każdy plik graficzny i z menu kontekstowego wybierz opcję Include In Project. Rys. 1. przedstawia utworzony folder wraz z paroma dodanymi zdjęciami.

Rys. 1. Repozytorium nowo utworzonego projektu.

  1. Następnie zaimplementuj klasę, która będzie pozwalała tworzyć obiekty, będące wyświetlonymi obrazkami wraz z opisem, umieszczonym pod każdym z nich. Aby to zrobić kliknij prawym przyciskiem myszy na nazwę projektu, wybierz Add, następnie New Item. W nowo wyświetlonym oknie wybierz opcję Class i nazwij ją np. PhotoData. Kompletny kod źródłowy klasy PhotoData umieszczono poniżej:
using System;

namespace FotoDrag
{
    public class PhotoData
    {
        //Atrybuty okreslajace zrodlo i opis kazdego z obrazkow
        public string Source { get; private set; }
        public string Caption { get; private set; }

        public PhotoData(string source, string caption)
        {
            this.Source = source;
            this.Caption = caption;
        }
    }
}

Utwórz dwie kolekcje kroku typu ObservableCollection, które to będą magazynować obrazki w poszczególnych kontrolkach. Przed wykonaniem poniższego kroku dodaj deklarację w pliku SurfaceWindow1.xaml.cs:

using System.Collections.ObjectModel;

Użycie typu ObservableCollection pozwala na uaktualnienie interfejsu użytkownika (UI) w przypadku zmiany elementów listy. Listy te będą również korzystały z opisanego we wcześniejszym artykule Databindingu, stąd też wymóg implementacji publicznych metod dostępowych. Kod źródłowy list umieszczono poniżej, są to, omawiając najprościej mówiąc, dwie kolekcje, które będą przechowywały obiekty klasy PhotoData, która została zaimplementowana wcześniej.

//Definicje kolekcji, w ktorych przechowywane beda obrazki w poszczegolnych kontrolkach
private ObservableCollection<PhotoData> libraryItems = 
new ObservableCollection<PhotoData>();
private ObservableCollection<PhotoData> scatterItems = 
new ObservableCollection<PhotoData>();

public ObservableCollection<PhotoData> LibraryItems
{
get { return libraryItems; }
}

public ObservableCollection<PhotoData> ScatterItems
{
get { return scatterItems; }
}

Powyższy kod umieść w pliku SurfaceWindow1.xaml.cs zaraz przed domyślnym konstruktorem (SurfaceWindow1()).

  1. Dla poprawnego działania Databindingu ustaw tzw. DataContext. Implementuje to metoda OnInitialized(), której kod źródłowy z przykładowymi zdjęciami znajduje się poniżej:
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
       DataContext = this;
//Definicja DataContext I przydzielenie kilku przykladowych wartosci
       LibraryItems.Add(new PhotoData("Images/Desert.jpg", "Desert"));
       LibraryItems.Add(new PhotoData("Images/Hydrangeas.jpg", "Hydrangeas"));
}
  1. Następnie ustal, jak poszczególne kontrolki mają być wyświetlone. Dokonaj tego, definiując tzw. DataTemplate. Poniższy kod umieść w pliku SurfaceWindow1.xaml między tagami SurfaceWindow i Grid.
<s:SurfaceWindow.Resources>
<DataTemplate x:Key="ImageOnlyTemplate">
        <Image Source="{Binding Source}" MaxWidth="200" />
</DataTemplate>
        
<DataTemplate x:Key="ImageAndCaptionTemplate">
<StackPanel>
<Image Source="{Binding Source}" MaxWidth="200" MaxHeight="50" Stretch="Uniform" />
<TextBlock Text="{Binding Caption}" MaxWidth="200" TextWrapping="Wrap" HorizontalAlignment="Center" />
</StackPanel>
</DataTemplate>
</s:SurfaceWindow.Resources>
  1. W pliku SurfaceWindow.xaml zdefiniuj zachowanie poszczególnych kontrolek. Określ atrybuty Name dla każdej z kontrolek oraz pozostałe atrybuty, by Databinding zadziałał poprawnie . Dokonaj tego między znacznikami Grid. Pełny kod źródłowy znajduje się w repozytorium projektu.

W tym momencie uruchomienie aplikacji jest już możliwe (w związku z tym wciśnij klawisz F5). Testując aplikację możesz zaobserwować (np. za pomocą narzędzia Input Simulator) zwykłe wyświetlenie kontrolek LibraryContainer, wraz z obrazkami, oraz ScatterView. Powyższe zależności zostały przedstawione na Rys. 2. Pierwsze uruchomienie projektu.

Rys. 2. Pierwsze uruchomienie projektu.

Wykorzystanie Drag & Drop API

Aby zezwolić na przeciąganie obiektów na kontrolkę ScatterView, w pliku SurfaceWindow.xaml w obrębie Tagu <s:ScatterView> dodaj atrybuty:

  • AllowDrop o wartości True,
  • s:SurfaceDragDrop.Drop o wartości Scatter_Drop.

Pierwszy z nich zezwala na przeciąganie elementów na kontrolkę, drugi natomiast deklaruje użycie metody zdarzeniowej o nazwie Scatter_Drop w momencie, gdy na kontrolkę ScatterView zostanie przeciągnięty obiekt.

  1. Implementacja metody Scatter_Drop została przedstawiona poniżej:
private void Scatter_Drop(object sender, SurfaceDragDropEventArgs e)
{
if (!ScatterItems.Contains(e.Cursor.Data))
       {
        ScatterItems.Add((PhotoData)e.Cursor.Data);
    }
// Pobiera automatycznie generowane ScatterViewItem i jej atrybutom nadaje konkretne wartosci.
       ScatterViewItem svi = 
        scatter.ItemContainerGenerator.ContainerFromItem(e.Cursor.Data) as ScatterViewItem; 
    svi.Visibility = System.Windows.Visibility.Visible;
       svi.Width = e.Cursor.Visual.ActualWidth;
       svi.Height = e.Cursor.Visual.ActualHeight;
       svi.Center = e.Cursor.GetPosition(scatter);
       svi.Orientation = e.Cursor.GetOrientation(scatter);
       svi.Background = Brushes.Transparent;
       e.Handled = true;
}
  1. Uruchom ponownie aplikację (wciśnij klawisz F5). Dzięki temu zaobserwujesz, że możliwe jest już przeciąganie elementów z kontrolki LibraryContainer do kontrolki ScatterView. Nie ma natomiast możliwości odwrotnego przemieszczania obiektów ze względu na specyfikę kontrolki ScatterView. Aby zrealizować możliwość przeciągania obiektów z kontrolki ScatterView zaimplementuj dodatkowo trzy zdarzenia, definiowane odpowiednio atrybutami:
  • PreviewTouchDown o wartości Scatter_PreviewTouchDown,
  • s:SurfaceDragDrop.DragCanceled o wartości Scatter_DragCanceled,
  • s:SurfaceDragDrop.DragCompleted o wartości Scatter_DragCompleted.

Wartość każdego z atrybutów określa nazwę metody, która zostanie uruchomiona w momencie zaistnienia, określonego atrybutem, zdarzenia. Kod źródłowy powyższych metod, ze względu na ich objętość, znajduje się w repozytorium projektu. Pełny kod źródłowy kontrolki ScatterView, zdefiniowanej w pliku SurfaceWindow.xaml znajduje się poniżej:

<s:ScatterView 
       Grid.Row="1"
       x:Name="scatter"
       Background="LightBlue"
       ItemTemplate="{StaticResource ImageAndCaptionTemplate}"
       ItemsSource="{Binding ScatterItems}"
       AllowDrop="True"
       PreviewTouchDown="Scatter_PreviewTouchDown"
       s:SurfaceDragDrop.DragCanceled="Scatter_DragCanceled"
       s:SurfaceDragDrop.DragCompleted="Scatter_DragCompleted"
s:SurfaceDragDrop.Drop="Scatter_Drop">
</s:ScatterView>

MetodaScatter_PreviewTouchDown zostanie uruchomiona w momencie, gdy użytkownik dotknie ekranu w obrębie kontrolki ScatterView. Kiedy użytkownik upuści obiekt na kontrolce zostanie uruchomiona metoda Scatter_DragCanceled lub metoda Scatter_DragCompleted, zależnie od tego skąd i dokąd zostanie przeciągnięty obiekt.

  1. Zapamiętaj, że masz możliwość zdefiniowania dodatkowych atrybutów oraz operacji wg. potrzeby. Atrybuty te pozwalają określić, czy zdarzenie zakończyło się sukcesem czy porażką (metoda SurfaceDragDrop.DragEnter) oraz dodać dodatkowe efekty (metoda SurfaceDragDrop.DragEnter).
  2. Za pomocą klawisza F5 uruchom aplikację w trybie Debug, następnie przetestuj ją za pomocą narzędzia Input Simulator. Teraz wyświetlone obrazki mogą być przeciągane pomiędzy dwoma kontrolkami. Efekt końcowy został pokazany na Rys. 3. Gotowa aplikacja z funkcją Drag and Drop.

Rys. 3. Gotowa aplikacja z funkcją Drag and Drop.

Podsumowanie

W tym artykule opisano, w jaki sposób używać Drag & Drop API, zbioru bibliotek dostarczonych wraz z Surface 2.0 SDK, które umożliwiają przeciąganie elementów pomiędzy obszarami aplikacji. Wykonana aplikacja pokazała, w jaki sposób zaimplementować funkcję „przeciągnij i upuść” dla różnego typu kontrolek platformy Surface.

W kolejnym artykule zostaną zaprezentowane różne metody na przygotowanie efektownego interfejsu użytkownika w oparciu o program Microsoft Expression Blend 4 dla platformy Surface.