Windows App開發之文件與數據
讀取文件和目錄名
這一節開始我們將陸續看到Windows App是如何操作文件的。
在Windows上讀取文件名稱、目錄名
首先我們在XAML中定義一個Button和TextBlock,將讀取文件/目錄名的過程寫在前者的click事件中。後者則用來顯示文件信息。
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel Orientation="Horizontal">
<Button Name="btnGetName" Width="200" Height="100" Content="讀取文件名稱" Click="btnGetName_Click"/>
<TextBlock Name="textBlockFileName" Width="500" Height="300" FontSize="30" Margin="12"/>
</StackPanel>
</Grid>
以下這段代碼,首先通過StorageFolder類讀取圖片庫。然後使用異步的方式將圖片庫的文件和目錄信息載入對應的List中。
新建一個StringBuilder用以保存這些文件的信息。在這裏僅僅是使用了文件/目錄的Name屬性,但屬性還有非常多。比方Path屬性。最後再將這些獲取到的信息賦值給TextBlock就可以。
private async void btnGetName_Click(object sender, RoutedEventArgs e)
{
StorageFolder pictureFolder = KnownFolders.PicturesLibrary;
IReadOnlyList<StorageFile> pictureFileList = await pictureFolder.GetFilesAsync();
IReadOnlyList<StorageFolder> pictureFolderList = await pictureFolder.GetFoldersAsync();
StringBuilder picutreFolderInfo = new StringBuilder();
foreach(StorageFile f in pictureFileList)
{
picutreFolderInfo.Append(f.Name+"\n");
}
foreach(StorageFolder f in pictureFolderList)
{
picutreFolderInfo.Append(f.Name+"\n");
}
textBlockFileName.Text = picutreFolderInfo.ToString();
}
註意要在方法名前面加上async哦。還有要在清單文件裏聲明我們的應用要使用圖片庫哦,一會在Windows Phone中也一樣。
在Windows Phone上讀取文件名稱、目錄名
後臺代碼不用做不論什麽改動。僅僅需把XAML代碼改動改動以適應屏幕就可以~
<Grid>
<StackPanel Orientation="Vertical">
<Button Name="btnGetName" Width="150" Height="70" HorizontalAlignment="Center"
Content="讀取文件名稱" Click="btnGetName_Click"/>
<TextBlock Name="textBlockFileName" Width="300" Height="300" FontSize="30" Margin="12" TextWrapping="Wrap"/>
</StackPanel>
</Grid>
讀取文件名稱的其它方法
private async void btnGetName_Click(object sender, RoutedEventArgs e)
{
StorageFolder picutureFolder = KnownFolders.PicturesLibrary;
StringBuilder pictureFolderInfo = new StringBuilder();
IReadOnlyList<IStorageItem> pictureFileItem = await picutureFolder.GetItemsAsync();
foreach(var i in pictureFileItem)
{
if (i is StorageFolder)
pictureFolderInfo.Append(i.Name + "\n");
else
pictureFolderInfo.Append(i.Name + "\n");
}
textBlockFileName.Text = pictureFolderInfo.ToString();
}
文件選取器
使用文件選取器保存文件
就我個人而言。還是非常喜歡使用文件選取器的。由於能夠用自己的代碼來調用系統的各種彈框。
在這個演示樣例中。首先在XAML中加入一個Button和一個TextBlock,分別命名為btnSaveFile和tBlockSaveInfo。
對於這個保存文件這個操作在後臺的Click事件中就能夠輕易完畢了。
private async void btnSaveFile_Click(object sender, RoutedEventArgs e)
{
FileSavePicker saveFile = new FileSavePicker();
saveFile.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
// 顯示在下拉列表的文件類型
saveFile.FileTypeChoices.Add("批處理文件", new List<string>() { ".bat" });
// 默認的文件名稱
saveFile.SuggestedFileName = "SaveFile";
StorageFile file = await saveFile.PickSaveFileAsync();
if(file!=null)
{
// 在用戶完畢更改並調用CompleteUpdatesAsync之前,阻止對文件的更新
CachedFileManager.DeferUpdates(file);
string fileContent = "@echo off \n dir/s \n pause";
await FileIO.WriteTextAsync(file, fileContent);
// 當完畢更改時,其它應用程序才幹夠對該文件進行更改。
FileUpdateStatus updateStatus = await CachedFileManager.CompleteUpdatesAsync(file);
if(updateStatus==FileUpdateStatus.Complete)
{
tBlockSaveInfo.Text = file.Name + " 已經保存好了。"
;
}
else
{
tBlockSaveInfo.Text = file.Name + " 保存失敗了。";
}
}
else
{
tBlockSaveInfo.Text = "保存操作被取消。"
;
}
}
代碼中的下拉列表的文件類型就是例如以下所看到的這個樣子喲。
大部分的內容我都已經通過凝視的方式加入到代碼中了,至於fileContent的那段代碼究竟是什麽意思,大家試試就知道了,我感覺蠻有意思的。3行代碼列出硬盤上全部文件及目錄
假設大家試過打開這個bat文件,有沒有認為有趣呢?
更厲害的是。我們剛才所寫的代碼能夠在Windows Phone上不經改動而直接使用。我的Lumia 638已經刷上了Windows 10預覽版。大家能夠瞧瞧,全新的資源管理器。
使用文件選取器打開文件
和用文件選取器保存文件相相似,打開文件的邏輯都差點兒相同。
這個演示樣例中相同在XAML中定義一個名為btnOpenFile的Button和一個名為tBlockOpenInfo的TextBlock。
private async void btnOpenFile_Click(object sender, RoutedEventArgs e)
{
FileOpenPicker openFile = new FileOpenPicker();
openFile.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
openFile.ViewMode = PickerViewMode.List;
openFile.FileTypeFilter.Add(".txt");
openFile.FileTypeFilter.Add(".docx");
openFile.FileTypeFilter.Add(".pptx");
// 選取單個文件
StorageFile file = await openFile.PickSingleFileAsync();
if (file != null)
{
tBlockOpenInfo.Text = "你所選擇的文件是: " + file.Name;
}
else
{
tBlockOpenInfo.Text = "打開文件操作被取消。"
;
}
// 選擇多個文件
//IReadOnlyList<StorageFile> fileList = await openFile.PickMultipleFilesAsync();
//StringBuilder fileOpenInfo = new StringBuilder();
//if(fileList!=null)
//{
// foreach( StorageFile f in fileList)
// {
// fileOpenInfo.Append(f.Name + "\n");
// }
// tBlockOpenInfo.Text = "你所選擇的文件是: "+"\n"+ fileOpenInfo.ToString();
//}
//else
//{
// tBlockOpenInfo.Text = "打開文件操作被取消。";
//}
}
我已經將選取多個文件的代碼也列了出來,僅僅須要取消凝視就可以。像ViewMode和FileTypeFilter這樣的屬性。看看名字應該都知道了吧。重在實踐。
在手機上也是通用的。剛才我試過了。成功進入了資源管理器,只是沒能打開文件。應該是由於預覽版的原因,這個預覽版連Office都被移除了。預計會在下一版中加入通用版的Office應用。
寫入和讀取
準備工作
在XAML中加入一個TextBlock用於顯示相關信息,加入一個Button來使用它的Click事件。當然了。最後分別創建2個。
創建文件和讀取文件
1.實例化StorageFolder類
我們的文件不可能讓其任意保存在計算機/手機中的不論什麽一個地方,應該先確定它的目錄,對吧?
在新的Windows 8中。微軟開啟了Windows上的App時代,下載的軟件再也不能任意安裝到不論什麽地方了。而是由操作系統統一放到一塊叫做“獨立存儲”的地方。這也是出於安全的考慮。用過Windows Phone 8的朋友應該更加清楚了。
那麽以下這行代碼的LocalFolder究竟在哪裏呢?
StorageFolder folder = Windows.Storage.ApplicationData.Current.LocalFolder;
下圖中的文件,就是我當前所寫的App。
(補充一條哦,一開始我裝了Win8後,下載了一個遊戲。模擬類的,有金幣呀什麽的,後來我找到這個App的文件,將數據改了之後金幣就嘩嘩的啦。
當然了,對於其它單機而言這個全然不值一提,但App的數據,相信還有非常多人沒有改過吧。)
那麽這張圖中的紅方框的目錄就是LocalFolder啦,以下另一個存儲漫遊文件的目錄。
不論是讀取文件還是寫入文件。都得先確定一個目錄哦。
2.實例化StorageFile
確定了目錄,就得確定文件咯。對於創建文件而言。執行以下代碼。既然用到了異步,在函數上加上async是不可缺少的咯。這一點我們在前面講到過。
後面的ReplaceExisting屬性是指的,假設該文件(名)已經存在了,則替換它。
StorageFile file =
await folder.CreateFileAsync("New Document.txt", CreationCollisionOption.ReplaceExisting);
那麽對於讀取文件呢。就直接讀取好啦。
StorageFile file = await folder.GetFileAsync("sample.txt");
3.創建和讀取文件
將文本寫入文件依照例如以下代碼。將文件名稱和文本內容(字符串)。
await FileIO.WriteTextAsync(file, "Write text to file.");
讀取文件也是相似的。
string text = await FileIO.ReadTextAsync(file);
我們還能夠將這個讀取的字符串傳遞給前面定義的TextBlock來加以調試。以下是完整的代碼。
// 創建文件
StorageFolder folder = Windows.Storage.ApplicationData.Current.LocalFolder;
StorageFile file = await folder.CreateFileAsync("New Document.txt", CreationCollisionOption.ReplaceExisting);
await FileIO.WriteTextAsync(file, "Write text to file.");
// 2 從文本讀取文件
StorageFolder folder = Windows.Storage.ApplicationData.Current.LocalFolder;
StorageFile file = await folder.GetFileAsync("sample.txt");
string text = await Windows.Storage.FileIO.ReadTextAsync(file);
tBlockReadInfo.Text = text;
使用緩沖區將字節寫入到文件或從文件讀取字節
1.實例化StorageFolder類
同上。
2.實例化StorageFile
同上。
3.將字節寫入到文件
a.建立緩沖區
var buffer = Windows.Security.Cryptography.CryptographicBuffer.ConvertStringToBinary("There‘s buffer ...... ", Windows.Security.Cryptography.BinaryStringEncoding.Utf8);
b.將緩沖區中的字節寫入到文件
await Windows.Storage.FileIO.WriteBufferAsync(file, buffer);
4.從文件讀取字節
a.將文件載入到緩沖區
var buffer = await Windows.Storage.FileIO.ReadBufferAsync(file);
b.實例化DataReader。讀取緩沖區
DataReader dataReader = Windows.Storage.Streams.DataReader.FromBuffer(buffer);
c.從DataReader對象中讀取字符串
string text = dataReader.ReadString(buffer.Length);
使用流將文本寫入文件或從文件讀取文本
1.實例化StorageFolder類
同上。
2.實例化StorageFile
同上。
3.新建流,並異步地將file打開。使用可讀寫的方式
var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite);
4.將文本寫入到文件
a.使用using
using (var writeStream= stream.GetOutputStreamAt(0))
{
......
}
b.(在using語句的花括號內)創建DataWriter對象。並調用DataWriter.WriteString方法,將文本寫入到writeStream中
DataWriter dataWriter = new DataWriter(writeStream);
dataWriter.WriteString("Stream is a good thing.");
c.將文本保存到文件裏。並通過StoreAsync和FlushAsync方法存儲和關閉流
await dataWriter.StoreAsync();
await writeStream.FlushAsync();
5.從文件讀取文本
a.獲取該流的size
var size = stream.Size;
b.使用using
using (var readStream = stream.GetOutputStreamAt(0))
{
......
}
c.(在using語句的花括號內)創建DataWriter對象,並調用LoadAsync方法,最後調用ReadString就可以。最後還能夠將信息輸出到TextBlock中。
DataReader dataReader = new DataReader(readStream);
uint uintBytes = await dataReader.LoadAsync((uint)size);
string text = dataReader.ReadString(uintBytes);
tBlockReadInfo.Text = text;
獲取文件屬性
這一節來看看獲取文件屬性吧,能夠獲取到文件名稱、類型、近期訪問時間等等屬性。
創建Button和TextBlock
以下這段代碼呢,都非常easy。
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Width="200" Height="70" Name="btnGetProp" Content="獲取文件屬性" Click="btnGetProp_Click"/>
<TextBlock Name="tBlockProp" Margin="12" Width="480" FontSize="30"/>
</StackPanel>
</Grid>
</Page>
在Click事件中,先獲取到圖片庫,當然了。你能夠獲取其它地方。我電腦上的庫文件裏,就僅僅有文檔庫和圖片庫有文件了。
然後創建一個文件查詢,最後將這些文件都賦給files。
這裏的var可謂是非常的強大啊。實例化一個StringBuilder對象來輔助輸出信息那真是太完美只是了。我們在前面也經常使用到它。
var folder = KnownFolders.PicturesLibrary;
var fileQuery = folder.CreateFileQuery();
var files = await fileQuery.GetFilesAsync();
StringBuilder fileProperties = new StringBuilder();
for (int i = 0; i < files.Count; i++)
{
StorageFile file = files[i];
fileProperties.AppendLine("File name: " + file.Name);
fileProperties.AppendLine("File type: " + file.FileType);
BasicProperties basicProperties = await file.GetBasicPropertiesAsync();
string fileSize = string.Format("{0:n0}", basicProperties.Size);
fileProperties.AppendLine("File size: " + fileSize + " bytes");
fileProperties.AppendLine("Date modified: " + basicProperties.DateModified);
fileProperties.AppendLine(" ");
}
tBlockProp.Text = fileProperties.ToString();
這樣一來就完畢對Name、FileType、Size和DateModified屬性的獲取,但另一類屬性,則比較難以獲取,它們就是“擴展屬性”。
List<string> propertiesName = new List<string>();
propertiesName.Add("System.DateAccessed");
propertiesName.Add("System.FileOwner");
IDictionary<string, object> extraProperties = await file.Properties.RetrievePropertiesAsync(propertiesName);
var propValue = extraProperties[dateAccessedProperty];
if (propValue != null)
fileProperties.AppendLine("Date accessed: " + propValue);
propValue = extraProperties[fileOwnerProperty];
if (propValue != null)
fileProperties.AppendLine("File owner: " + propValue);
最後將fileProperties傳遞給TextBlock就可以。
tBlockProp.Text = fileProperties.ToString();
最後調試App,就會像下圖一樣了。
可是如你所見,文件名稱太長了卻無法自己主動換行,並且數據也顯示不完整。改改XAML中的TextBlock就可以。TextWrapping屬性設置為Wrap,則能夠換行;將TextBlock加入到ScrollViewer內則會顯示出一個滾動欄。
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Width="200" Height="70" Name="btnGetProp" Content="獲取文件屬性" Click="btnGetProp_Click"/>
<ScrollViewer>
<TextBlock Name="tBlockProp" Margin="12" Width="480" FontSize="30" TextWrapping="Wrap"/>
</ScrollViewer>
</StackPanel>
</Grid>
保存、讀取、刪除應用數據
在前面的幾節中,都是關於數據的。這方面的內容事實上還有非常多非常多。省略掉一部分後,也還是有非常多。這一節是非常重要的一部分。它關於如何保存和讀取數據。
先來看看一個大概的背景吧,我這裏寫的非常easy啦。
保存的內容就是這四個框框裏填寫的數據咯。先上XAML代碼。
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<StackPanel Orientation="Vertical">
<Rectangle Name="recRed" Width="200" Height="200" Fill="Red"/>
<Rectangle Name="recGreen" Width="100" Height="400" Fill="Green"/>
</StackPanel>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<StackPanel Orientation="Vertical">
<TextBlock Text="紅色矩形的長" FontSize="25" Margin="12" Width="150" Height="50" />
<TextBlock Text="紅色矩形的寬" FontSize="25" Margin="12" Width="150" Height="50" />
<TextBlock Text="綠色矩形的長" FontSize="25" Margin="12" Width="150" Height="50" />
<TextBlock Text="綠色矩形的寬" FontSize="25" Margin="12" Width="150" Height="50" />
</StackPanel>
<StackPanel Orientation="Vertical">
<TextBox Name="tBoxRedHeight" FontSize="25" Width="150" Height="50" Margin="12"/>
<TextBox Name="tBoxRedWidth" FontSize="25" Width="150" Height="50" Margin="12"/>
<TextBox Name="tBoxGreenHeight" FontSize="25" Width="150" Height="50" Margin="12" />
<TextBox Name="tBoxGreenWidth" FontSize="25" Width="150" Height="50" Margin="12" />
</StackPanel>
</StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Width="150" Height="70" Name="btnSaveAppData" Click="btnSaveAppData_Click" Content="保存應用數據"/>
<Button Width="150" Height="70" Name="btnReadAppData" Click="btnReadAppData_Click" Content="讀取應用數據"/>
</StackPanel>
</StackPanel>
</StackPanel>
</Grid>
單個設置
先來看看單個設置唄,以下就是代碼咯。
Windows.Storage.ApplicationDataContainer localSettings = Windows.Storage.ApplicationData.Current.LocalSettings;
Windows.Storage.StorageFolder localFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
public MainPage()
{
this.InitializeComponent();
}
private void btnSaveAppData_Click(object sender, RoutedEventArgs e)
{
localSettings.Values["RectangleRedHeight"] = tBoxRedHeight.Text;
localSettings.Values["RectangleRedWidth"] = tBoxRedWidth.Text;
localSettings.Values["RectangleGreenHeight"] = tBoxGreenHeight.Text;
localSettings.Values["RectangleGreenWidth"] = tBoxGreenWidth.Text;
}
private void btnReadAppData_Click(object sender, RoutedEventArgs e)
{
Object objRectangleRedHeight = localSettings.Values["RectangleRedHeight"];
Object objRectangleRedWidth = localSettings.Values["RectangleRedWidth"];
Object objRectangleGreenHeight = localSettings.Values["RectangleGreenHeight"];
Object objRectangleGreenWidth = localSettings.Values["RectangleGreenWidth"];
recRed.Height = double.Parse(objRectangleRedHeight.ToString());
recRed.Width = double.Parse(objRectangleRedWidth.ToString());
recGreen.Height = double.Parse(objRectangleGreenHeight.ToString());
recGreen.Width = double.Parse(objRectangleGreenWidth.ToString());
}
首先定義了兩個全局變量,假設看過前面幾篇文章,這個應該就非常清楚了。
顧名思義,第一個是用來保存本地設置的,第二個則是用來訪問本地目錄的。
這裏是單個設置地進行保存的,後面還有2種方式。那麽就來調試吧,註意在點擊了保存數據按鈕之後把App關掉哦,關掉之後再載入,這樣才算是保存了應用數據嘛。你說對不正確呢?
以下就是我的測試結果了。
復合設置
我們的設計都不用變,後臺代碼改動例如以下。
Windows.Storage.ApplicationDataContainer localSettings = Windows.Storage.ApplicationData.Current.LocalSettings;
Windows.Storage.StorageFolder localFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
public MainPage()
{
this.InitializeComponent();
}
private void btnSaveAppData_Click(object sender, RoutedEventArgs e)
{
Windows.Storage.ApplicationDataCompositeValue compositeSettings = new ApplicationDataCompositeValue();
compositeSettings["RectangleRedHeight"] = tBoxRedHeight.Text;
compositeSettings["RectangleRedWidth"] = tBoxRedWidth.Text;
compositeSettings["RectangleGreenHeight"] = tBoxGreenHeight.Text;
compositeSettings["RectangleGreenWidth"] = tBoxGreenWidth.Text;
localSettings.Values["RectangleSettings"] = compositeSettings;
}
private async void btnReadAppData_Click(object sender, RoutedEventArgs e)
{
Windows.Storage.ApplicationDataCompositeValue compositeSettings =
(Windows.Storage.ApplicationDataCompositeValue)localSettings.Values["RectangleSettings"];
if (compositeSettings == null)
{
Windows.UI.Popups.MessageDialog messageDialog =
new Windows.UI.Popups.MessageDialog("你好像沒有保存不論什麽應用數據哦!");
await messageDialog.ShowAsync();
}
else
{
recRed.Height = double.Parse(compositeSettings["RectangleRedHeight"].ToString());
recRed.Width = double.Parse(compositeSettings["RectangleRedWidth"].ToString());
recGreen.Height = double.Parse(compositeSettings["RectangleGreenHeight"].ToString());
recGreen.Width = double.Parse(compositeSettings["RectangleGreenWidth"].ToString());
}
}
使用ApplicationDataCompositeValue 會創建一個復合設置,通過代碼所看到的方式就可以加入數據,最後會將其加入到localSettings中。
讀取數據的時候。相同是先在localSettings中通過鍵值對的方式來取出這個復合設置。假設該設置為空。就會調用MessageDialog控件彈窗通知沒有保存數據。
對於這個控件。能夠訪問這裏:【萬裏征程——Windows App開發】控件大集合2。假設復合設置存在則將他們分別進行類型轉換後復制給對應的矩形的屬性。
在容器中存放數據
在容器存放數據事實上也就這麽回事啦,無非就是先創建一個容器,然後假設創建成功了。就在當中加入對應的數據就可以。
至於載入數據。在這裏我使用了一個bool變量來檢查容器是不是已經創建好了,假設創建好了就能夠將對應的數據取出然後賦值了,假設沒有的話則一樣挑出彈窗。
Windows.Storage.ApplicationDataContainer localSettings = Windows.Storage.ApplicationData.Current.LocalSettings;
Windows.Storage.StorageFolder localFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
public MainPage()
{
this.InitializeComponent();
}
private void btnSaveAppData_Click(object sender, RoutedEventArgs e)
{
Windows.Storage.ApplicationDataContainer containerSettings =
localSettings.CreateContainer("RecSettingsContainer", Windows.Storage.ApplicationDataCreateDisposition.Always);
if (localSettings.Containers.ContainsKey("RecSettingsContainer"))
{
localSettings.Containers["RecSettingsContainer"].Values["RectangleRedHeight"] = tBoxRedHeight.Text;
localSettings.Containers["RecSettingsContainer"].Values["RectangleRedWidth"] = tBoxRedWidth.Text;
localSettings.Containers["RecSettingsContainer"].Values["RectangleGreenHeight"] = tBoxGreenHeight.Text;
localSettings.Containers["RecSettingsContainer"].Values["RectangleGreenWidth"] = tBoxGreenWidth.Text;
}
}
private async void btnReadAppData_Click(object sender, RoutedEventArgs e)
{
bool hasContainerSettings = localSettings.Containers.ContainsKey("RecSettingsContainer");
if(hasContainerSettings)
{
recRed.Height = double.Parse(localSettings.Containers["RecSettingsContainer"].Values["RectangleRedHeight"].ToString());
recRed.Width = double.Parse(localSettings.Containers["RecSettingsContainer"].Values["RectangleRedWidth"].ToString());
recGreen.Height = double.Parse(localSettings.Containers["RecSettingsContainer"].Values["RectangleGreenHeight"].ToString());
recGreen.Width = double.Parse(localSettings.Containers["RecSettingsContainer"].Values["RectangleGreenWidth"].ToString());
}
else
{
Windows.UI.Popups.MessageDialog messageDialog =
new Windows.UI.Popups.MessageDialog("你好像沒有保存不論什麽應用數據哦!");
await messageDialog.ShowAsync();
}
}
接下來就來個執行的截圖咯。還有彈框的截圖^_^
刪除數據
1.對於單個設置和復合設置
localSettings.Values.Remove("compositeSettings");
2.對於復合數據
localSettings.DeleteContainer("containerSettings");
刪除並不難,或者說,這一節都不難。有了這些,我們在做遊戲的時候,就能夠將用戶對遊戲的設置都保存下來啦。
Windows App開發之文件與數據