Dino Windows 8 学习笔记(九)-- 如何在App中添加喜爱的照片
不积跬步无以至千里。为什么要说这么一句话呢?是因为我学习Windows 8 开发是没有系统性可言的,而且根据微软MSDN官方的RoadMap进行学习的话我也觉得是零散而且不系统的,所以我的计划就是自己做个应用,碰到问题解决问题,解决问题记录问题,记录问题以便下次遇到可以知道在哪里找到。所以我走的都是一个个杂乱的跬步,但是这是经验的积累,希望有一天能至千里,我对这一天抱有期望。
额,跑题了,今天的主题是添加照片,还是先上图吧,老规矩:
先说说我的解决方案吧,我尽量描述的清楚:
这是一个GridView,GridView中放置的是一堆DataItem,每一个DataItem中都有一个Image属性,也有一个imagePath属性,用来接收图片的地址:
1
public
ref
class
SampleDataCommon : TestViewState::Common::BindableBase
2 {
3
4 public :
5 void SetImage(Platform::String ^ path);
6 property Windows::UI::Xaml::Media::ImageSource ^ Image { Windows::UI::Xaml::Media::ImageSource ^ get ();
void set (Windows::UI::Xaml::Media::ImageSource ^ value); }
7
8 private :
9
10 Windows::UI::Xaml::Media::ImageSource ^ _image;
11 Platform::String ^ _imagePath;
12
13 };
14
2 {
3
4 public :
5 void SetImage(Platform::String ^ path);
6 property Windows::UI::Xaml::Media::ImageSource ^ Image { Windows::UI::Xaml::Media::ImageSource ^ get ();
void set (Windows::UI::Xaml::Media::ImageSource ^ value); }
7
8 private :
9
10 Windows::UI::Xaml::Media::ImageSource ^ _image;
11 Platform::String ^ _imagePath;
12
13 };
14
正如大家所看到的那样,SetImage(..)方法接收一个String^ 类型的路径,用来设置图片。我们来看这个方法做了些什么:
1
ImageSource
^
SampleDataCommon::Image::
get
()
2 {
3 static Uri ^ _baseUri = ref new Uri( " ms-appx:/// " ); // 待添加 ms-appdata: // /
4 if (_image == nullptr && _imagePath != nullptr)
5 {
6 _image = ref new BitmapImage(_baseUri -> CombineUri(_imagePath)); // _baseUri + _imagePath
7
8 }
9 return _image;
10 }
11
12 void SampleDataCommon::Image:: set (ImageSource ^ value)
13 {
14 if (_image != value)
15 {
16 _image = value;
17 _imagePath = nullptr;
18 OnPropertyChanged( " Image " );
19 PropertySet set ;
20 }
21 }
22
23 void SampleDataCommon::SetImage(String ^ path)
24 {
25 _image = nullptr;
26 _imagePath = path;
27 OnPropertyChanged( " Image " );
28 }
29
2 {
3 static Uri ^ _baseUri = ref new Uri( " ms-appx:/// " ); // 待添加 ms-appdata: // /
4 if (_image == nullptr && _imagePath != nullptr)
5 {
6 _image = ref new BitmapImage(_baseUri -> CombineUri(_imagePath)); // _baseUri + _imagePath
7
8 }
9 return _image;
10 }
11
12 void SampleDataCommon::Image:: set (ImageSource ^ value)
13 {
14 if (_image != value)
15 {
16 _image = value;
17 _imagePath = nullptr;
18 OnPropertyChanged( " Image " );
19 PropertySet set ;
20 }
21 }
22
23 void SampleDataCommon::SetImage(String ^ path)
24 {
25 _image = nullptr;
26 _imagePath = path;
27 OnPropertyChanged( " Image " );
28 }
29
SetImage方法只是把path传递给back store _imagePath, 通过_imagePath,在Image::get()方法中,我们看到,一个ms-appx:///目录下的文件被作为源赋给了image。其实这个完整的路径应该是:ms-appx:///Asset/Gray.png.
一般文件都有一个路径,基本上是这样的:<scheme>://<domain name>/<path>.
在Windows 8 中,所有的文件都是从App的package中读取出来的 。代表App的本地打包文件的scheme是“ms-appx:"domain name 可有可无,一般都省略掉,这样App就假定domain name指的是App package的full name。
你也可以用 "/"来表示pakage的根目录,例如:"/pic.png"就是指在你的应用的根目录下的pic.png。
Your app doesn't have access to E:\demo folder. Your application has default access only to items within its app data and app package folders. By declaring the appropriate Capabilities(such as Picture Library access) it can get brokered access to files in libraries.
If you are loading a hard coded image then it should be in the app package.
You can't reference images on the file system outside of your package from Xaml, and doing so doesn't make much sense: you can't be sure that those images will even exist.
这几句话很简单,就是说,你只能使用包内的路径,或者你在Capability设置了可以访问Picture Library的话,你也可以用路径直接访问这里面的图片之类的文件。但是,如果你想使用路径访问其他地方的文件,那是不可能的。怎么办?使用流:
我错了,忘了把如何将图片放置在控件中的代码贴出来了。
1
FileOpenPicker
^
openPicker
=
ref
new
FileOpenPicker();
2 openPicker -> ViewMode = PickerViewMode::Thumbnail;
3 openPicker -> SuggestedStartLocation = PickerLocationId::PicturesLibrary;
4 openPicker -> FileTypeFilter -> Append( " .jpg " );
5 openPicker -> FileTypeFilter -> Append( " .jpeg " );
6 openPicker -> FileTypeFilter -> Append( " .png " );
7
8 create_task(openPicker -> PickSingleFileAsync()).then([ this ,clickedItem](StorageFile ^ file)
9 {
10 if (file)
11 {
12 create_task(file -> OpenAsync(FileAccessMode::Read)).then([ this ,clickedItem](IRandomAccessStream ^ stream)
13 {
14
15 auto bitmap = ref new BitmapImage();
16 bitmap -> SetSource(stream);
17 clickedItem -> Image = bitmap;
18 });
19 }
20 else
21 {
22 clickedItem -> Image = nullptr;
23 }
24 });
2 openPicker -> ViewMode = PickerViewMode::Thumbnail;
3 openPicker -> SuggestedStartLocation = PickerLocationId::PicturesLibrary;
4 openPicker -> FileTypeFilter -> Append( " .jpg " );
5 openPicker -> FileTypeFilter -> Append( " .jpeg " );
6 openPicker -> FileTypeFilter -> Append( " .png " );
7
8 create_task(openPicker -> PickSingleFileAsync()).then([ this ,clickedItem](StorageFile ^ file)
9 {
10 if (file)
11 {
12 create_task(file -> OpenAsync(FileAccessMode::Read)).then([ this ,clickedItem](IRandomAccessStream ^ stream)
13 {
14
15 auto bitmap = ref new BitmapImage();
16 bitmap -> SetSource(stream);
17 clickedItem -> Image = bitmap;
18 });
19 }
20 else
21 {
22 clickedItem -> Image = nullptr;
23 }
24 });
这里使用了FilePicker来选择文件,选择文件之后,然后打开文件,得到IRandomAccessStream^l流,然后赋值给BitmapImage的源,就可以显示我们选择的图片了。是挺简单的。感谢一下Draw/C#同学。如果你看到的话,thanks!
下章提要:如何在Resouce Dictionary中查找Style,并且赋值给控件,今天一直在研究这玩意。C#下好像很容易搞定,但是在C++下怎么就会出现exception呢?已经在MSDN论坛上发帖问了,希望有个答案。