安装win8 64位,vs2013(包含wp8 sdk),百度各种得到学生开发者账户之后,终于可以试一下将自己的app部署到手机上的感觉了。
首先来个简单练练手的照相机功能
即从主界面进入到照相机界面,进行拍照,并对照片进行保存
对已拍照片管理,查看,删除
MainPage.xaml
<phone:PhoneApplicationPage x:Class="OpenCamera.MainPage" 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" mc:Ignorable="d" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" shell:SystemTray.IsVisible="True"> <Grid> <Button Width="200" Height="200" Content="拍照" Click="ButtonBase_OnClick"></Button> </Grid> </phone:PhoneApplicationPage>
MainPage.xaml.cs
public partial class MainPage : PhoneApplicationPage { // 构造函数 public MainPage() { InitializeComponent(); } private void ButtonBase_OnClick(object sender, RoutedEventArgs e) { this.NavigationService.Navigate(new Uri("/Camera.xaml", UriKind.RelativeOrAbsolute)); } }
意思就很简单了,点击拍照,就进入照相界面
下面拍照界面Camera.xaml
<Grid x:Name="LayoutRoot" Background="Transparent"> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition Height="200"/> </Grid.RowDefinitions> <Canvas> <Canvas.Background> <VideoBrush x:Name="VideoBrush"></VideoBrush> </Canvas.Background> </Canvas> <StackPanel Grid.Row="1"> <Button Width="200" Height="200" Content="拍照" Click="ButtonBase_OnClick"> </Button> </StackPanel> </Grid>
一个Canvas用于显示照相机捕捉到的图像
一个按钮,用于拍照
上MSDN查询:http://msdn.microsoft.com/zh-cn/library/microsoft.devices.photocamera(v=vs.92).aspx
备注中提到一些实用方法,其中提到了几个方法
OnNavigatedTo(导航到本页面时触发)
OnNavigatedFrom(离开本页面后触发)
OnNavigatingFrom(离开本页面之前触发)
在Camera.xaml.cs中依次重写了3个方法,都打上断点,看执行顺序,发现执行过程是 点击拍照按钮=》OnNavigatedTo=》点击返回=>OnNavigatingFrom=》OnNavigatedFrom
好,现在就明白了,在OnNavigatedTo中来初始化PhotoCamera对象实例,并捕捉图像到Canvas上
protected override void OnNavigatedTo(NavigationEventArgs e) { _cam = new PhotoCamera(CameraType.Primary); VideoBrush.SetSource(_cam); base.OnNavigatedTo(e); }
好,此刻已按捺不住激动的心情了,编译,在模拟器中调试....,但是,程序出错。再次查看MSDN,发现这里
有个东西需要设置一下
好,现在在编译,运行,模拟器中如下
心想,这该没有什么问题了吧,插上手机,部署
运行,果然能够显示图像了。有点小兴奋。
拍照就很简单了,调用一个方法即可
private void ButtonBase_OnClick(object sender, RoutedEventArgs e) { _cam.CaptureImage(); }
调用了CaptrueImage方法,本以为会返回照片,但是继续查看MSDN发现需要注册一个事件,来获得图片。
这里还用到了一个类MediaLibrary:http://msdn.microsoft.com/query/dev12.query?appId=Dev12IDEF1&l=ZH-CN&k=k(Microsoft.Xna.Framework.Media.MediaLibrary);k(TargetFrameworkMoniker-WindowsPhone,Version%3Dv8.0);k(DevLang-csharp)&rd=true
但是,这里需要注意一下,使用MediaLibrary来保存数据还需要这一步设置,如下图:
这样,MediaLibrary才能正常使用(MSDN上没有说明这个:坑呀)
这里注册图片可用事件
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e) { if (_cam != null) { _cam.Dispose(); _cam.Initialized -= _cam_Initialized; _cam.CaptureCompleted -= _cam_CaptureCompleted; _cam.CaptureImageAvailable -= _cam_CaptureImageAvailable; _cam.CaptureThumbnailAvailable -= _cam_CaptureThumbnailAvailable; } base.OnNavigatingFrom(e); } protected override void OnNavigatedTo(NavigationEventArgs e) { _cam = new PhotoCamera(CameraType.Primary); _library = new MediaLibrary(); VideoBrush.SetSource(_cam); _cam.Initialized += _cam_Initialized; _cam.CaptureCompleted += _cam_CaptureCompleted;//照相完成事件 _cam.CaptureImageAvailable += _cam_CaptureImageAvailable;//图片可用事件 _cam.CaptureThumbnailAvailable += _cam_CaptureThumbnailAvailable;//缩略图可用事件 base.OnNavigatedTo(e); }
在OnNvaigatingForm中取消订阅事件
现在主要关注CaptureImageAvailable事件,该事件当照相生成的图片可以使用时触发,先不要关注注释部分的代码,这样就能将照片保存到手机相册里了
void _cam_CaptureImageAvailable(object sender, ContentReadyEventArgs e) { string fileName = string.Format("{0}-{1}-{2}", DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second) + ".jpg"; _library.SavePictureToCameraRoll(fileName, e.ImageStream); #region 独立存储 //string floderName = "Photo"; //string fileName = string.Format("{0}-{1}-{2}", DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second) + ".jpg"; //string fullName = Path.Combine(floderName, fileName); //using (IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication()) //{ // if (!file.DirectoryExists(floderName)) // { // file.CreateDirectory(floderName); // } // if (!file.FileExists(fullName)) // { // using (IsolatedStorageFileStream fileStream = file.OpenFile(fullName, FileMode.Create, FileAccess.Write)) // { // byte[] readBuffer = new byte[4069]; // int bytesRead = -1; // while ((bytesRead = e.ImageStream.Read(readBuffer, 0, readBuffer.Length)) > 0) // { // fileStream.Write(readBuffer, 0, bytesRead); // } // } // } //} #endregion e.ImageStream.Close(); }
但是,我们要制作自己的相册,就需要独立存储。
独立存储这一块请看MSDN吧,http://msdn.microsoft.com/zh-cn/library/system.io.isolatedstorage.isolatedstoragefile(v=vs.110).aspx
注释部分的代码就是将图片保存到独立存储中,而不是手机的相册中。
相册就是将所拍的照片展示出来,暂时用ListBox实现
界面Photo.xaml
<Grid x:Name="LayoutRoot" Background="Transparent"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <!--TitlePanel 包含应用程序的名称和页标题--> <StackPanel Grid.Row="0" Orientation="Horizontal" Margin="12,17,0,28"> <TextBlock Text="相册" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> <Image x:Name="TestImage"></Image> </StackPanel> <!--ContentPanel - 在此处放置其他内容--> <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <ListBox ItemsSource="{Binding AllPhoto}"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel> <Image Source="{Binding}"></Image> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </Grid> </Grid>
Photo.xaml.cs
#region 字段 private ObservableCollection<BitmapImage> _allPhoto; #endregion #region 属性 public ObservableCollection<BitmapImage> AllPhoto { get { return _allPhoto; } set { _allPhoto = value; OnPropertyChanged("AllPhoto"); } } #endregion public Photos() { InitializeComponent(); this.DataContext = this; AllPhoto=new ObservableCollection<BitmapImage>(); } #region 导航事件 protected override void OnNavigatedTo(NavigationEventArgs e) { using(IsolatedStorageFile file=IsolatedStorageFile.GetUserStoreForApplication()) { if (file.DirectoryExists("PhotoTH")) { string[] fileNames = file.GetFileNames("/PhotoTH/"); foreach (var fileName in fileNames) { using (IsolatedStorageFileStream fileStream = file.OpenFile("/PhotoTH/" + fileName, FileMode.Open)) { BitmapImage bitmapImage=new BitmapImage(); bitmapImage.SetSource(fileStream); AllPhoto.Add(bitmapImage); } } } } base.OnNavigatedTo(e); } #endregion public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this,new PropertyChangedEventArgs(propertyName)); } }
这样就能将图所拍照片的图片显示出来了。
这里一般都是长按相片,然后弹出菜单可以选择“删除”选项,这个就用到类似于WPF的ContextMenu,但是弄死在WP8项目中就是没有ContextMenu,各种百度之后,得知需要引用MicroSoft.Phone.Control.ToolKit
该Dll在http://www.nuget.org/packages/wptoolkit
下载之后,我们的Photo界面就要稍微修改,下面是修改之后的Photo.xaml
<!--LayoutRoot 是包含所有页面内容的根网格--> <Grid x:Name="LayoutRoot" Background="Transparent"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <!--TitlePanel 包含应用程序的名称和页标题--> <StackPanel Grid.Row="0" Orientation="Horizontal" Margin="12,17,0,28"> <TextBlock Text="相册" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> <Image x:Name="TestImage"></Image> </StackPanel> <!--ContentPanel - 在此处放置其他内容--> <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <ListBox ItemsSource="{Binding AllPhoto}"> <ListBox.ItemTemplate> <DataTemplate> <Button Width="200" Height="200"> <Button.Template> <ControlTemplate TargetType="Button"> <Grid> <Grid.Background> <ImageBrush ImageSource="{Binding Source}"> <ImageBrush.RelativeTransform> <CompositeTransform CenterX="0.5" CenterY="0.5" Rotation="90"></CompositeTransform> </ImageBrush.RelativeTransform> </ImageBrush> </Grid.Background> </Grid> </ControlTemplate> </Button.Template> <toolkit:ContextMenuService.ContextMenu> <toolkit:ContextMenu> <toolkit:MenuItem Header="删除" Click="MenuItem_OnClick" Tag="{Binding}"></toolkit:MenuItem> </toolkit:ContextMenu> </toolkit:ContextMenuService.ContextMenu> </Button> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </Grid> </Grid>
这里需要注意一下,一开始我们直接绑定的BitmapImage来获取图片,但是这样在删除的时候,不仅要从集合中删除BitmapImage,还要从独立存储中删除该图片,而BitmapImage获取UriSource不到(希望有同学解释一下),这里只能变通一下,创建类Photo
public class Photo { public string FileName { get; set; } public string FullName { get; set; } public BitmapImage Source { get; set; } }
这样我们集合中存储的就是该Photo类型的变量,有文件名,还有包含整个路径的文件名,还有BitmapImage对象,这样删除的时候,就非常容易了,下面是删除图片的代码
private void MenuItem_OnClick(object sender, RoutedEventArgs e) { MenuItem item = sender as MenuItem; Photo photo = item.Tag as Photo; AllPhoto.Remove(photo); using (IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication()) { if (file.FileExists(photo.FullName)) { file.DeleteFile(photo.FullName); } } }
好了,至此,大致的功能就完成了。以为是一个很简单的东西,其实其中还包含了一些未知的东西,如独立存储,还有配置文件(勾选相机功能可用的那个)等等,目前也就是学了个大概,后面还要慢慢深入。
Demo:http://files.cnblogs.com/HelloMyWorld/OpenCamera.rar
人生还有无限可能,不要放弃努力。