一般我們在撰寫Windows Phone App的時候有時會需要擷取螢幕上的控制項轉換成圖片,當我們想要在背景執行並生成圖片給使用者時,就必須用程式碼動態產生的方式來達成,但是怎麼邏輯上沒有錯,可是生成的圖片卻跟理想狀態不一樣呢?
本篇文章將引導您擷取UI轉換成WriteableBitmap並存入IsolatedStorage,解決控制項全部擠一起的問題。
一般我們在撰寫Windows Phone App的時候有時會需要擷取螢幕上的控制項轉換成圖片,當我們想要在背景執行並生成圖片給使用者時,就必須用程式碼動態產生的方式來達成,但是怎麼邏輯上沒有錯,可是生成的圖片卻跟理想狀態不一樣呢?
本篇文章將引導您擷取UI轉換成WriteableBitmap並存入IsolatedStorage,解決控制項全部擠一起的問題。
首先我們先學習一下如何將舞台上的UIElement擷取下來並存放在IsolatedStorage
在Xaml中必須定義控制項的名字,以便在程式碼中取用,並依照個人需求放入控制項:
1: <Grid x:Name="LayoutRoot" Background="Transparent">
2: ........
3: </Grid>
再來就是程式碼的部分:
1: public MainPage()
2: {
3: InitializeComponent();
4:
5: //必須在控制項已經繪製完成的時候動作,否則會擷取不到圖片
6: this.LayoutUpdated += (sender, e) => {
7: //將控制項轉換為WriteableBitmap
8: WriteableBitmap UI_Image = new WriteableBitmap(LayoutRoot, null);
9: //轉換為JPG並寫入IsolatedStorageFile
10: Write_Bitmap_TO_Isolate(UI_Image, "QQ.jpg");
11: };
12: }
13:
14: //將WriteableBitmap轉換為JPG並寫入IsolatedStorageFile
15: private void Write_Bitmap_TO_Isolate(WriteableBitmap WriteBitmap, string FileName)
16: {
17: try
18: {
19:
20: using (IsolatedStorageFile tStorage = IsolatedStorageFile.GetUserStoreForApplication())
21: {
22: var isolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
23: //如果目標檔案已經存在,則刪除檔案
24: if (isolatedStorage.FileExists(FileName))
25: {
26: isolatedStorage.DeleteFile(FileName);
27: Debug.WriteLine("目標檔案存在 刪除");
28: }
29: //創建檔案
30: IsolatedStorageFileStream fileStream = isolatedStorage.CreateFile(FileName);
31: //寫入檔案
32: WriteBitmap.SaveJpeg(fileStream, WriteBitmap.PixelWidth, WriteBitmap.PixelHeight, 0, 100);
33: //關閉IO
34: fileStream.Close();
35: fileStream.Dispose();
36: tStorage.Dispose();
37:
38: }
39: }
40: catch (Exception ex)
41: {
42: Debug.WriteLine("例外狀況:"+ex.Message);
43: }
44:
45: }
如此一來我們可以很輕易地擷取到控制項的畫面,
查看IsolatedStorageFile請參閱:
[Windows Phone 8 | Dev Tool]_介紹並解決Windows Phone Power Tools找不到SmartDevice.Connectivity的問題
Windows Phone 8 使用 IsoStoreSpy 查看 IsolatedStorageFile
用Xaml來做卻是相當的簡單,但是用C#程式碼來動態產生的UIElement,可能就會遇到一些事情了,
首先根據需求預想我們要的版面:
架構如右圖,想好版面後可以開始來用程式碼動態產生囉,
並用相同的方法轉換成WriteableBitmap並存入IsolatedStorage!!
動態產生控制項請參閱:
C# Windows 8,Windows Phone 8 WP8,使用程式碼動態產生Chart長條圖,不用Telerik UI也能做。
C# Windows 8,Windows Phone 8 WP8,使用程式碼動態產生ScrollViewer,並放入可捲動的資料。
C# Windows 8,Windows Phone 8 WP8,使用程式碼動態產生Grid。
C# Windows 8,Windows Phone 8 WP8,使用程式碼動態產生StackPanel。
[筆記]C# Windows Phone 8 WP8 開發,找回StackPanel底下Orientation消失的屬性。
1: double TD_R = 1234;
2: double TM_R = 5678;
3: string account = "一起做運動";
4:
5: //====================動態產生的UIElement====================
6: Grid Grid_Root = new Grid() {
7: Width = 336,
8: Height = 336
9: };
10: Grid_Root.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Auto) });
11: Grid_Root.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Auto) });
12: Grid_Root.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Auto) });
13: Grid_Root.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Auto) });
14:
15: StackPanel STP_Revenue = new StackPanel()
16: {
17: Orientation = System.Windows.Controls.Orientation.Vertical,
18: VerticalAlignment=VerticalAlignment.Top,
19: HorizontalAlignment=HorizontalAlignment.Left
20: };
21:
22: StackPanel STP_Title=new StackPanel(){
23: Orientation = System.Windows.Controls.Orientation.Horizontal,
24: Margin=new Thickness(10,10,10,10)
25: };
26: Image image=new Image(){
27: Height = 20,
28: Width = 20,
29: Stretch = Stretch.Uniform,
30: VerticalAlignment = VerticalAlignment.Center,
31: Source = new BitmapImage(new Uri("/Assets/ApplicationIcon.png", UriKind.RelativeOrAbsolute)),
32: Margin = new Thickness(10)};
33: TextBlock Text_Title=new TextBlock(){
34: Foreground=new SolidColorBrush(Colors.White),
35: FontSize=20,
36: VerticalAlignment=VerticalAlignment.Center,
37: Text="健康口訣"
38: };
39: STP_Title.Children.Add(image);
40: STP_Title.Children.Add(Text_Title);
41:
42: TextBlock Text_Account = new TextBlock()
43: {
44: Foreground = new SolidColorBrush(Colors.White),
45: FontSize = 20,
46: VerticalAlignment = VerticalAlignment.Center,
47: Text = account
48: };
49:
50: TextBlock Text_TM = new TextBlock() {
51: Foreground = new SolidColorBrush(Colors.White),
52: FontSize = 20,
53: VerticalAlignment = VerticalAlignment.Center,
54: Text = ""+TM_R
55: };
56:
57: TextBlock Text_TD = new TextBlock()
58: {
59: Foreground = new SolidColorBrush(Colors.White),
60: FontSize = 20,
61: VerticalAlignment = VerticalAlignment.Center,
62: Text = "" + TD_R
63: };
64:
65: Grid.SetRow(STP_Title, 0);
66: Grid.SetRow(Text_Account, 1);
67: Grid.SetRow(Text_TM, 2);
68: Grid.SetRow(Text_TD, 3);
69: Grid_Root.Children.Add(STP_Title);
70: Grid_Root.Children.Add(Text_Account);
71: Grid_Root.Children.Add(Text_TM);
72: Grid_Root.Children.Add(Text_TD);
73:
74: //將UIElement轉換為WriteableBitmap並寫入IsolatedStorageFile
75: WriteableBitmap UI_Image = new WriteableBitmap(Grid_Root, null);
76: Write_Bitmap_TO_Isolate(UI_Image,"QQ.jpg");
再去查看一下IsolatedStorageFile裡的檔案…
挖哩...全部擠成一塊啊!
這下可好...交到客戶手上又要變成垃圾中的垃圾了....
這其實是因為使用C#動態產生控制項時,雖然已經控制項的屬性還有子項目已經佈署完成,
可是控制項並尚未被繪製,所以才會看起來全部擠成一起。
好吧既然知道原因了,那就開始動手修改程式碼吧!
其實只要改一小小段程式碼就可以囉!大體上程式碼的架構還是沒有錯的,只是必須讓控制項先繪製,
再儲存到WriteableBitmap並存入IsolatedStorage!!
將以下程式碼刪除:
1: WriteableBitmap UI_Image = new WriteableBitmap(Grid_Root, null);
2: Write_Bitmap_TO_Isolate(UI_Image,"QQ.jpg");
換成:
1: //更新配置並指定大小
2: Grid_Root.Measure(new Size(336, 336));
3: //放置子項目,以及判斷 UIElement 的大小
4: Grid_Root.Arrange(new Rect(0, 0, 336, 336));
5: //給定WriteableBitmap要繪製的大小
6: WriteableBitmap UI_Image = new WriteableBitmap(336, 336);
7: UI_Image.Render(Grid_Root, null);
8: //繪製
9: UI_Image.Invalidate();
10: //將UIElement轉換為WriteableBitmap並寫入IsolatedStorageFile
11: Write_Bitmap_TO_Isolate(UI_Image, "QQ.jpg");
再運行一次
終於得到我們想要的結果了 呼~
如此一來就學會了擷取UIElement轉換成WriteableBitmap並存入IsolatedStorageFile,解決控制項全部擠一起的問題。
References :
UIElement.Measure
UIElement.Arrange
UIElement.Invalidate
WriteableBitmap
文章中的敘述如有觀念不正確錯誤的部分,歡迎告知指正 謝謝
轉載請註明出處,並且附上本篇文章網址 ! 感謝。