タッチパネルでドラッグ&ドロップを使う汎用的なサンプル

ApplicationBarIconButtonの「カメラ起動」アイコンがタップされた時の処理
Showメソッドでカメラを起動します。
Private Sub GoCamera(sender As Object, e As EventArgs)
myCameraTask.Show()
End Sub
myImage(Canvasに追加されたカメラで撮影された画像)から指が離れた時の処理
ドラッグされるmyImageオブジェクトのYの位置が300より大きく、かつXの位置が200より大きい(つまりmyImageオブジェクトがカバン画像の領域に入った)場合は、myImageを非表示にし、カバンのアニメーションであるmyStoryboard1を開始します。
Private Sub myImageDropped(sender As Object, e As MouseButtonEventArgs)
Dim myImage As Image = DirectCast(sender, Image)
If behavior.Y > 300 AndAlso behavior.X > 200 Then
myImage.Visibility = Windows.Visibility.Collapsed
Storyboard1.Stop()
Storyboard1.Begin()
End If
End Sub
カバンのアニメーションであるStoryboard1が完了した時の処理
画像とXMLファイルを保存するImageSaveプロシージャを実行します。
Private Sub Storyboard1_Completed(sender As Object, e As System.EventArgs) Handles Storyboard1.Completed
ImageSave()
End Sub
画像とXMLファイルを保存する処理
保存する画像のファイル名を作成します。現在の[年月日時間分秒.jpg]をファイル名にし、変数imageFileNameに格納しておきます。
変数storageを、ファイルとディレクトリを格納している分離ストレージ領域を表す、IsolateStorageFileクラスとして宣言します。DirectryExistsメソッドでPictureDataというフォルダが存在しているかどうかをチェックし、存在していない場合は、CreateDirectoryメソッドでPictureDataというフォルダを作成します。
Path.CombineでPictureDataというフォルダとimageFileNameに格納されている画像名とを連結します。
分離ストレージ内のファイルを表すIsolatedStorageFileStreamクラス用オブジェクト変数myStream変数を用意し、IsolatedStorageFile.CreateFileメソッドで、分離ストレージ内にfilePath変数の持っているフォルダ名付き画像ファイルを作成します。次に、IsolatedStorageFileStream.Writeメソッドで、バイト配列から読み取ったデータを使用して、IsolatedStorageFileStreamオブジェクトにバイトのブロックを書き込みます。
IsolatedStorageFileStream.Writeメソッドの書式は下記の通りです。
IsolatedStorageFileStream.Write(書き込むバッファ, 開始位置を示すバッファ内のバイト オフセット,書き込む最大バイト数)
変数xmlStorageを、ファイルとディレクトリを格納している分離ストレージ領域を表すIsolateStorageFileクラスとして宣言します。Path.Combineで、PictureDataというフォルダ名と、imageFileList.xmlという画像ファイル名を記録したXMLファイルを連結し、xmlFilePath変数に格納しておきます。
PictureDataというフォルダ内にimageFileList.xmlが存在していない場合は、Visual Basic の埋め込み式を用いて、XML宣言とルート要素image、その子要素としてfileName、その属性に”imageFileName”を指定し、埋め込み式の構文である を用いてimageFileName変数の値を指定します。これは ASP.NET で使用される構文と同じです。
分離ストレージ内のファイルを表すIsolatedStorageFileStreamクラス用オブジェクト変数xmlStreamを用意し、IsolatedStorageFile.CreateFileメソッドで、分離ストレージ内にxmlFilePath変数の持っているフォルダ名付きXMLファイルを作成します。
imageFileList.xmlファイルが存在する場合は、新しいStreamWriterを生成し、IsolatedStorageFile.OpenFileメソッドで、指定したファイルアクセスを使用して指定したモードでファイルを開き、初期化します。Writeメソッドで埋め込み式のXMLをストリームに書き込みます。保存した旨のメッセージを表示します。
「画像一覧」と「削除」のApplicationBarIconButtonの使用を可能にします。
次は、既にPictureDataフォルダ内にimageFileList.xmlが存在する場合の処理です。
IsolatedStorageFileクラスのOpenFileメソッドでPictureDataフォルダ内のimageFileList.xmlファイルを、指定したファイルアクセスを使用して指定したモードでファイルを開きます。開いたファイルをStreamReaderで読み込みます。ReadToEndメソッドでファイルの最後まで読み取り、変数readXmldoc変数に格納しておきます。読み込んだXMLテキストをParseメソッドでXElementとして読み込みます。
追加するfileName要素を作成し、埋め込み式を用いて、”imageFileName”属性の値にimageFileName変数の値を指定します。新しく生成したXML要素を、読み込んだXMLにAddメソッドで追加します
imageFileList.xmlファイルが存在する場合は、新しいStreamWriterを生成し、IsolatedStorageFile.OpenFileメソッドで、指定したファイルアクセスを使用して指定したモードでファイルを開き、初期化します。Writeメソッドで新しいXML要素の追加されたXMLを、ストリームに書き込みます。保存した旨のメッセージを表示します。
「画像一覧」と「削除」のApplicationBarIconButtonの使用を可能にします。
Private Sub ImageSave()
'画像の保存
Storyboard1.Stop()
Dim imageFileName As String = DateTime.Now.ToString("yyyyMMddHHmmss") & ".jpg"
Dim storage As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication
If storage.DirectoryExists("PictureData") = False Then
storage.CreateDirectory("PictureData")
End If
Dim filePath As String = Path.Combine("PictureData", imageFileName)
Using myStream As IsolatedStorageFileStream = storage.CreateFile(filePath)
myStream.Write(imageByte, 0, imageByte.Length)
End Using
'XMLファイルの保存
Dim xmlStorage As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication
Dim xmlFilePath As String = Path.Combine("PictureData", "imageFileList.xml")
If xmlStorage.FileExists(xmlFilePath) = False Then
Dim xmldoc As XDocument = <?xml version="1.0" encoding="utf-8"?>
<image>
<fileName imageFileName=<%= imageFileName %>/>
</image>
Using xmlStream As IsolatedStorageFileStream = xmlStorage.CreateFile(xmlFilePath)
End Using
If xmlStorage.FileExists(xmlFilePath) = True Then
Using xmlwriter As StreamWriter = New StreamWriter(xmlStorage.OpenFile(xmlFilePath, FileMode.Open, FileAccess.Write))
xmlwriter.Flush()
xmlwriter.Write(xmldoc.ToString)
End Using
MessageBox.Show("画像とXMLファイルを保存しました。")
End If
TryCast(ApplicationBar.Buttons(1), ApplicationBarIconButton).IsEnabled = True
TryCast(ApplicationBar.Buttons(2), ApplicationBarIconButton).IsEnabled = True
Else
Dim xmlStream As IsolatedStorageFileStream = xmlStorage.OpenFile(xmlFilePath, FileMode.Open, FileAccess.Read)
Using xmlreader As StreamReader = New StreamReader(xmlStream)
Dim readXmldoc As String = xmlreader.ReadToEnd
Dim doc As XElement = XElement.Parse(readXmldoc)
Dim addXml As XElement = <fileName imageFileName=<%= imageFileName %>/>
doc.Add(addXml)
'xmlreader.Close()
xmlStream.Close()
If xmlStorage.FileExists(xmlFilePath) = True Then
Using xmlwriter As StreamWriter = New StreamWriter(storage.OpenFile(xmlFilePath, FileMode.Open, FileAccess.Write))
xmlwriter.Flush()
xmlwriter.Write(doc.ToString)
'xmlwriter.Close()
MessageBox.Show("画像とXMLファイルを保存しました。")
End Using
End If
End Using
TryCast(ApplicationBar.Buttons(1), ApplicationBarIconButton).IsEnabled = True
TryCast(ApplicationBar.Buttons(2), ApplicationBarIconButton).IsEnabled = True
End If
End Sub
「画像一覧」のApplicationBarIconButtonがタップされた時の処理
これから作成するIchiranPage.xamlに遷移します。
Private Sub GoIchiran(sender As Object, e As EventArgs)
NavigationService.Navigate(New Uri("/IchiranPage.xaml", UriKind.Relative))
End Sub
「削除」のApplicationBarIconButtonがタップされた時の処理
これから作成するDeletePage.xamlに遷移します。
Private Sub GoDelete(sender As Object, e As EventArgs)
NavigationService.Navigate(New Uri("/DeletePage.xaml", UriKind.Relative))
End Sub
End Class
「Windows Phone 縦向きのページ」(IchiranPage.xaml(画像一覧))の作成
VS2010メニューの[プロジェクト(P)/新しい項目の追加(W)]を選択し、続けて「Windows Phone 縦向きのページ」を選択します。「名前(N)」にはIchiranPage.xamlと入力します(図7)。
![]() |
図7:「Windows Phone 縦向きのページ」(IchiranPage.xaml)を作成する(クリックで拡大) |
IchiranPage.xamlの編集とコントロールの配置
x:NameがPageTitleというTextBlockのTextプロパティに「画像一覧」と指定します。Styleプロパティに指定されているPhoneTextTitle1StyleをPhoneTextTitle2Styleに変更します。フォントが小さくなって表示されます。ツールボックスからListBoxコントロールを1個配置します(図8)。
![]() |
図8:ListBoxコントロールを配置した(クリックで拡大) |
書き出されたXAMLコードをリスト3のように編集します。
リスト3 編集したXAMLコード(IchiranPage.xaml)
(1)
ここで指定する名称は、VBコード内のクラスで定義するプロパティ名です。
(2)(1)で定義したListBoxTemplateをItemTemplateに指定して参照します。
<phone:PhoneApplicationPage
x:Class="WP71_DragDropSave.IchiranPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">
<phone:PhoneApplicationPage.Resources> ■(1)
<DataTemplate x:Key="ListBoxTemplate">
<StackPanel Margin="10">
<Image Width="400" Height="360" Stretch="Fill" Source="{Binding imageFileName}" Margin="35">
<Image.RenderTransform>
<CompositeTransform Rotation="90" CenterX="200" CenterY="180"/>
</Image.RenderTransform>
</Image>
</StackPanel>
</DataTemplate>
</phone:PhoneApplicationPage.Resources> ■(1)
<!--LayoutRoot は、全てのページ コンテンツが配置されるルート グリッドです-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel は、アプリケーション名とページ タイトルを格納します-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle" Text="マイ アプリケーション" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="画像一覧" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle2Style}"/>
</StackPanel>
<!--ContentPanel - 追加コンテンツをここに入力します-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<ListBox Height="636" HorizontalAlignment="Left" Margin="12,6,0,0" Name="ListBox1" VerticalAlignment="Top" Width="438" ItemTemplate="{StaticResource ListBoxTemplate}"/> ■(2)
</Grid>
</Grid>
<!--ApplicationBar の使用法を示すサンプル コード-->
~コード略~
</phone:PhoneApplicationPage>
次に、IchiranPage.xamlを展開して表示される、IchiranPage.xaml.vbをダブルクリックしてリスト4のコードを記述します。
ロジックコードを記述する
リスト4 (IchiranPage.xaml.vb)
Option Strict On Imports System.Xml.Linq Imports System.IO Imports System.IO.IsolatedStorage Imports System.Windows.Media.Imaging Imports Microsoft.Phone
ImageInfoクラス内にWriteableBitmapクラス型のimageFileNameプロパティを定義しておきます。
Public Class ImageInfo
Property imageFileName As WriteableBitmap
End Class
Partial Public Class IchiranPage
Inherits PhoneApplicationPage
Public Sub New()
InitializeComponent()
End Sub
ページがアクティブになった時呼び出されるメソッド
変数storageを、ファイルとディレクトリを格納している分離ストレージ領域を表すIsolateStorageFileクラスとして宣言します。Path.CombineでPictureDataというフォルダとimageFileList.xmlというXMLファイル名を連結します。
分離ストレージ内のファイルを表すIsolatedStorageFileStreamクラス用オブジェクト変数myStreamを用意します。IsolatedStorageFileクラスのOpenFileメソッドで、PictureDataフォルダ内のimageFileList.xmlファイルを、指定したファイルアクセスを使用して、指定したモードで開きます。開いたファイルをStreamReaderで読み込みます。ReadToEndメソッドでファイルの最後まで読み取り、変数readXmldoc変数に格納しておきます。
読み込んだXMLテキストをParseメソッドでXElementとして読み込みます。ImageInfoクラス型の新しいリストであるmyImageInfoオブジェクトを作成します。
Descendantsメソッドで、子孫要素である全ての
Path.CombineでPictureDataフォルダと、
IsolatedStorageFileStreamクラスのOpenFileメソッドで、PictureDataフォルダ内にあるimageFileList.xmlファイルを、指定したファイルアクセスを使用して、指定したモードで開きます。
WriteableBitmap型の変数imageSourceを宣言し、PictureDecoder.DecodeJpegメソッドで、開いたストリームをJPEGファイルとしてWriteableBitmapオブジェクトにデコードします。
PictureDecoder.DecodeJpegメソッドはMicrosof.Phone名前空間に属しています。WriteableBitmapクラスは書き込み更新することのできるBitmapSourceを提供するクラスです。
ImageInfoクラスのimageFileNameプロパティに、読み込んだWriteableBitmapオブジェクトのimageSourceオブジェクトを指定し、AddメソッドでmyImageInfoオブジェクトに追加していきます。ListBox1のItemsSourceプロパティにmyImageInfoオブジェクトを指定します。これで、撮った画像の一覧が表示されます。
Protected Overrides Sub OnNavigatedTo(e As System.Windows.Navigation.NavigationEventArgs)
Dim storage As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication
Dim filePath As String = Path.Combine("PictureData", "imageFileList.xml")
Using myStream As IsolatedStorageFileStream = storage.OpenFile(filePath, FileMode.Open, FileAccess.Read)
Using reader As StreamReader = New StreamReader(myStream)
Dim readXmldoc As String = reader.ReadToEnd
Dim doc As XElement = XElement.Parse(readXmldoc)
Dim myImageInfo As New List(Of ImageInfo)
For Each result In From c In doc.Descendants("fileName") Select c
Dim imageFilePath As String = Path.Combine("PictureData", result.Attribute("imageFileName").Value)
Dim imageStorage As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication
Using stream As IsolatedStorageFileStream = imageStorage.OpenFile(imageFilePath, FileMode.Open, FileAccess.Read)
Dim imageSource As WriteableBitmap = PictureDecoder.DecodeJpeg(stream)
With myImageInfo
.Add(New ImageInfo With {.imageFileName = imageSource})
End With
'stream.Close()
End Using
Next
ListBox1.ItemsSource = myImageInfo
End Using
End Using
MyBase.OnNavigatedTo(e)
End Sub
End Class
「Windows Phone 縦向きのページ」(DeletePage.xaml(削除))の作成
VS2010メニューから[プロジェクト(P)/新しい項目の追加(W)]を選択し、続けて「Windows Phone 縦向きのページ」を選択します。「名前(N)」にはDeletePage.xamlと入力します。
DeletePage.xamlの編集とコントロールの配置
x:NameがPageTitleというTextBlockのTextプロパティに、「削除」と指定します。Styleプロパティに指定されているPhoneTextTitle1StyleをPhoneTextTitle2Styleに変更すると、フォントが小さくなって表示されます。
ツールボックスから、ListBoxコントロールを1個と、Imageコントロールを2個配置します。そのうち、1つのImageコントロールのSourceプロパティには、Imageフォルダ内のカバンの画像を指定します。ListBoxコントロールの枠線の太さ(BorderThickness)に5を指定し、枠線の色(BorderBrush)にNavyを指定しておきます(図9)。
![]() |
図9:ListBoxとImageコントロールを配置した(クリックで拡大) |
書き出されたXAMLコードをリスト5のように編集します。
リスト5 編集したXAMLコード(DeletePage.xaml)
(1)
Marginに15を指定して余白を設けます。子要素として
(2)(1)のままだと、ListBoxに表示される画像が、横一列で表示されてしまうため、複数列に渡って表示されるようにします。WrapPanelListBoxというKey名の
WrapPanelコントロールがツールボックスに登録されていない場合は、ツールボックスを右クリックして表示されるメニューの「アイテムの選択(I)」から追加しておいてください。
追加する場合、Windows Phone Toolkitがインストールされている必要があります。Windows Phone Toolkitは下記URLよりダウンロードできます。
→参照:Windows Phone Toolkit - Nov 2011 (7.1 SDK)
(3)(1)と(2)で定義したListBoxTemplateとWrapPanelListBoxをItemTemplateとItemsPanelに指定して参照します。
<phone:PhoneApplicationPage
x:Class="WP71_DragDropSave.DeletePage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="ListBoxTemplate"> ■(1)
<StackPanel Orientation="Horizontal" Margin="15" HorizontalAlignment="Center">
<Image Width="200" Height="180" Source="{Binding imageFileName}" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="0">
<Image.RenderTransform>
<CompositeTransform Rotation="90" CenterX="100" CenterY="90"/>
</Image.RenderTransform>
</Image>
</StackPanel>
</DataTemplate> ■(1)
<ItemsPanelTemplate x:Key="WrapPanelListBox"> ■(2)
<toolkit:WrapPanel Width="500"/>
</ItemsPanelTemplate> ■(2)
</phone:PhoneApplicationPage.Resources>
<!--LayoutRoot は、全てのページ コンテンツが配置されるルート グリッドです-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel は、アプリケーション名とページ タイトルを格納します-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle" Text="マイ アプリケーション" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="削除" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle2Style}"/>
</StackPanel>
<!--ContentPanel - 追加コンテンツをここに入力します-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Image Height="90" HorizontalAlignment="Left" Margin="185,511,0,0" x:Name="delImage1" Stretch="Fill" VerticalAlignment="Top" Width="100">
<Image.RenderTransform>
<CompositeTransform Rotation="90" CenterX="50" CenterY="45"/>
</Image.RenderTransform>
</Image>
<Image x:Name="bugImage" HorizontalAlignment="Left" Height="200" Margin="124,454,0,0" VerticalAlignment="Top" Width="200" Source="/WP71_DragDropSave;component/Image/IW007.png" />
<ListBox Height="422" HorizontalAlignment="Left" Margin="0,6,0,0" x:Name="ListBox1" VerticalAlignment="Top" Width="456" ItemsPanel="{StaticResource WrapPanelListBox}" ItemTemplate="{StaticResource ListBoxTemplate}" BorderBrush="Navy" BorderThickness="5" /> ■(3)
</Grid>
</Grid>
<!--ApplicationBar の使用法を示すサンプル コード-->
~コード略~
</phone:PhoneApplicationPage>
次に、ソリューションエクスプローラー内のDeletePage.xamlを選択し、マウスの右クリックで表示される「Expression Blendを開く(X)」からExpression Blendを起動し、カバンの中から画像が出てきて消えるアニメーションを作成します。
タッチパネルでドラッグ&ドロップを使うサンプル




