第一個WP8程序,照相機

安裝win8 64位,vs2013(包含wp8 sdk),百度各類獲得學生開發者帳戶以後,終於能夠試一下將本身的app部署到手機上的感受了。shell

 

首先來個簡單練練手的照相機功能express

  • 照相

即從主界面進入到照相機界面,進行拍照,並對照片進行保存app

  • 相冊

對已拍照片管理,查看,刪除ide


  • 界面設計

 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.csthis

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));
        }
    }

意思就很簡單了,點擊拍照,就進入照相界面spa

下面拍照界面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用於顯示照相機捕捉到的圖像
一個按鈕,用於拍照調試

 

  • PhotoCamera

上MSDN查詢:http://msdn.microsoft.com/zh-cn/library/microsoft.devices.photocamera(v=vs.92).aspxcode

備註中提到一些實用方法,其中提到了幾個方法

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

人生還有無限可能,不要放棄努力。

相關文章
相關標籤/搜索