采集到的数据顺利显示到UI上并不代表万事大吉!还得存储,不然退出应用后,采集到的数据就会像师爷的屁股一去不返!
msdn上有个分布存储的小例子。边学边做,小试牛刀。
isolated storage:windowsphone中无法直接访问设备的文件系统,也就是不能像PC上那样直接访问硬盘,看到C盘D盘,有什么东西。个人认为这种方式真的很不方便。听说win8也改头换面弃明投暗,也不再直接访问硬盘。。。虽然不习惯还是硬着头皮去习惯吧。用zune将音乐同步到手机上后无法通过目录的方式直接看到文件的位置,但系统会很快地识别到同步到手机上的文件,只要格式正确,是不会给你落下的,所以习惯了这种方式之后还是可以习惯的。
但这种方式并不意味着无法找到你的数据了!silverlight提供了另外一种保存和访问数据的方式,叫做isolated storage,分布式存储。这种方式在存储数据时将创建一种虚拟文件系统,这个文件系统只能由本应用程序访问,其他应用程序无法访问。很明显这种方式还是存在着访问限制,但是至少是把数据存储下来了,退出应用再次进入,数据还在那里!
使用分布式存储有两种方法:一是最简单的键/值对方法,利用IsolatedStorageSettings类实现;二是将数据保存成文件,利用IsolatedStorageFile类实现。这两个类在System.IO.IsolatedStorage命名空间中,使用时注意添加一个using语句。
首先来看键/值对方法
键/值对方法用到了IsolatedStorageSettings,这个类就像一个字典,可以存储你对象,例如string。比较适合存储少量数据。
一般使用Add、Contains、Remove方法。其中Add就是向字典中添加键、值对,contains是判断是否包含某个特定的键值对。remove是删除。
一个简单的小例子:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<TextBox Height="72" HorizontalAlignment="Left" Margin="0,29,0,0" Name="txtInput" Text="INPUT DATA" VerticalAlignment="Top" Width="460" />
<Button x:Name="Savebtn" Content="Save Data" Height="72" HorizontalAlignment="Left" Margin="106,122,0,0" VerticalAlignment="Top" Width="239" Click="Savebtn_Click" />
<Button x:Name="Displaybtn" Content="Display Data" Height="72" HorizontalAlignment="Left" Margin="106,211,0,0" VerticalAlignment="Top" Width="239" Click="Displaybtn_Click" />
<Button Content="Remove Data" Height="72" HorizontalAlignment="Left" Margin="106,301,0,0" Name="Removebtn" VerticalAlignment="Top" Width="239" Click="Removebtn_Click" />
<TextBlock Height="75" HorizontalAlignment="Left" Margin="96,427,0,0" Name="txtDisplay" Text="USER DATA:" VerticalAlignment="Top" Width="249" />
</Grid>
</Grid>
上面的xaml文件在主页面中添加了一个textBox,以接受用户的输入,一个textBlock以显示存储的数据,以及三个按钮分别是存储、显示和删除。下面是C#代码:
private void Savebtn_Click(object sender, RoutedEventArgs e)
{
IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings;
if (!settings.Contains("userData"))//设userData为键,设成啥都行
{ //判断是否存在这个键,如果不存在则利用Add方法增加这个键和值
settings.Add("userData", txtInput.Text);//值就是输入的字符
}
else
{
settings["userData"] = txtInput.Text;//如果已经存在这个键,即将这个键对应的值改为当前的字符。调用格式settings["key string"]
}
settings.Save();//保存
}
private void Displaybtn_Click(object sender, RoutedEventArgs e)
{
txtDisplay.Text = "USER DATA:";
if (IsolatedStorageSettings.ApplicationSettings.Contains("userData"))//为了确保存在,在显示之前再判断一次,是个好习惯
{
txtDisplay.Text += IsolatedStorageSettings.ApplicationSettings["userData"] as string;
}
}
private void Removebtn_Click(object sender, RoutedEventArgs e)
{
if (IsolatedStorageSettings.ApplicationSettings.Contains("userData"))
{
IsolatedStorageSettings.ApplicationSettings.Remove("userData");//删除这个键/值对
}
}
查看IsolatedStorageSettings的定义,发现有一个获取特定键值的方法,可以与display中的txtDisplay.Text += IsolatedStorageSettings.ApplicationSettings["userData"] as string;语句实现相同的功能:
private void Displaybtn_Click(object sender, RoutedEventArgs e)
{
txtDisplay.Text = "USER DATA:";
if (IsolatedStorageSettings.ApplicationSettings.Contains("userData"))
{
//txtDisplay.Text += IsolatedStorageSettings.ApplicationSettings["userData"] as string;
string txtvalue;
IsolatedStorageSettings.ApplicationSettings.TryGetValue<string>("userData", out txtvalue);
txtDisplay.Text += txtvalue;
}
}
上面是对数据的存储操作,下面看看对文件的操作吧。
想要利用分布式存储保存文件,需要用到IsolatedStorageFile类,这个类提供一个分布式存储的区域,以存放文件和目录。存文件的时候,会用到IsolatedStorageFileStream类,来读取和写入到文件中。这两个类中的主要方法和属性,就右键看Definiton好了。
上述两个类在使用完毕后,要释放资源,在C#中有垃圾回收器,可以自动释放资源,但最好是在使用完毕后就主动将其释放。一般的方法是利用try-catch结构,在用到这个类的语句块结束时,主动调用Dispose方法。但是msdn的例子中提供了一种更加方便的方法:使用using语句。using语句的一个功能是在语句块结束时自动调用dispose方法。这一点在下面的代码中可以看到,这是一种很好的方式,方便又清晰。
下面代码的功能是首先从device上选择一张图片,将这张图片存储到Images目录中,再次打开应用程序时,页面上显示的是上次选中的图片。
<StackPanel x:Name="ContentPanelstack" Grid.Row="1" Margin="12,0,12,0">
<Button Name="btnSaveFile"
Content="Save Image"
Height="100" Width="300"
Click="btnSaveFile_Click" />
<Button x:Name="btnDisplayFile"
Content="Display Saved Image"
Height="100" Width="300"
Click="btnDisplayFile_Click" />
<Image Name="userImage" Source="Images/zhan.jpg" />
</StackPanel>
public partial class MainPage : PhoneApplicationPage
{
private PhotoChooserTask photoTask;
// Constructor
public MainPage()
{
InitializeComponent();
photoTask = new PhotoChooserTask();
IsolatedStorageFile disoriginal = IsolatedStorageFile.GetUserStoreForApplication();
if (disoriginal.DirectoryExists("Images"))
{
BitmapImage original_bitmap = GetSavedImage();
if (original_bitmap != null)
{
userImage.Source = original_bitmap;
}
}
}
void photoTask_Completed(object sender, PhotoResult e)
{
if (e.TaskResult == TaskResult.OK)
{
BitmapImage bmp = new BitmapImage();
bmp.SetSource(e.ChosenPhoto);
SaveToFile(bmp);
}
}
private void btnSaveFile_Click(object sender, RoutedEventArgs e)
{
photoTask.Show();
}
private void SaveToFile(BitmapImage image)
{
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
{
WriteableBitmap bmImage = new WriteableBitmap(image);
if (!store.DirectoryExists("Images"))
{
store.CreateDirectory("Images");
}
using (IsolatedStorageFileStream isoStream =
store.OpenFile(@"Images\zhan.jpg", FileMode.OpenOrCreate))
{
Extensions.SaveJpeg(
bmImage,
isoStream,
bmImage.PixelWidth,
bmImage.PixelHeight,
0,
100);
}
}
}
private BitmapImage GetSavedImage()
{
BitmapImage image;
using (IsolatedStorageFile store =
IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream isoStream =
store.OpenFile(@"Images\zhan.jpg", FileMode.Open))
{
image = new BitmapImage();
image.SetSource(isoStream);
}
}
return image;
}
private void btnDisplayFile_Click(object sender, RoutedEventArgs e)
{
BitmapImage bitmap = GetSavedImage();
if (bitmap != null)
{
userImage.Source = bitmap;
}
}
}
与msdn上的例子相比,我在初始化方法中添加了重新这是图片显示的代码:
IsolatedStorageFile disoriginal = IsolatedStorageFile.GetUserStoreForApplication();
if (disoriginal.DirectoryExists("Images"))
{
BitmapImage original_bitmap = GetSavedImage();
if (original_bitmap != null)
{
userImage.Source = original_bitmap;
}
}
1、这段代码的意思是打开应用后首先检查分布式存储空间中有没有文件存在,如果有,说明是上次存储的文件,将其显示在mainpage中。
2、注意其中几个using语句的用法,不这么写也能实现功能,单位了养成良好的编程习惯,建议使用using语句