演练:在 WPF 应用程序中缓存应用程序数据
缓存使您能够在内存中存储数据以实现快速访问。 当再次访问数据时,应用程序可以从缓存获取数据,而不是从原始源检索数据。 这可以改进性能和伸缩性。 此外,缓存还使数据在数据源临时不可用时可用。
通过 .NET Framework 提供的类,您可以在 .NET Framework 应用程序中使用缓存。这些类位于 System.Runtime.Caching 命名空间中。
注意 |
---|
System.Runtime.Caching 命名空间是 .NET Framework 4 中新增的命名空间。此命名空间使缓存对所有的 .NET Framework 应用程序可用。在 .NET Framework 的早期版本中,缓存仅可用于 System.Web 命名空间,因此在 ASP.NET 类上需要有依赖项。 |
本演练演示如何在 Windows Presentation Foundation (WPF) 应用程序中使用 .NET Framework 中提供的缓存功能。 在本演练中,您将缓存文本文件的内容。
本演练演示以下任务:
创建 WPF 应用程序项目。
添加对 .NET Framework 4 的引用。
初始化缓存。
添加包含文本文件内容的缓存项。
为缓存项提供逐出策略。
监视缓存文件的路径,并向缓存实例通知被监视项的更改情况。
系统必备
若要完成本演练,您需要:
Microsoft Visual Studio 2010。
包含少量文本的文本文件。 (将在消息框中显示文本文件的内容。)本演练中演示的代码假定您使用以下文件:
c:\cache\cacheText.txt
但是,您可以使用任何文本文件,并对本演练中的代码进行少量更改。
创建 WPF 应用程序项目
您将首先创建一个 WPF 应用程序项目。
创建 WPF 应用程序
启动 Visual Studio。
在**“文件”菜单中单击“新建”,再单击“新建项目”**。
将显示**“新建项目”**对话框。
在**“已安装的模板”下,选择要使用的编程语言(“Visual Basic”或“Visual C#”**)。
在**“新建项目”对话框中,选择“WPF 应用程序”**。
注意 如果没有看到“WPF 应用程序”模板,请确保您以支持 WPF 的 .NET Framework 版本为目标。在“新建项目”对话框中,从列表选择 .NET Framework 4。
在**“名称”**文本框中,输入项目的名称。 例如,您可以输入 WPFCaching。
选中**“创建解决方案的目录”**复选框。
单击**“确定”**。
WPF 设计器会在**“设计”视图中打开,并显示 MainWindow.xaml 文件。 Visual Studio 会创建“我的项目”**文件夹、Application.xaml 文件和 MainWindow.xaml 文件。
以 .NET Framework 为目标并添加对缓存程序集的引用
默认情况下,WPF 应用程序以 .NET Framework 4 Client Profile 为目标。 若要在 WPF 应用程序中使用 System.Runtime.Caching 命名空间,应用程序必须以 .NET Framework 4(而不是 .NET Framework 4 Client Profile)为目标,并且必须包含对该命名空间的引用。
因此,下一步是更改 .NET Framework 目标并添加对 System.Runtime.Caching 命名空间的引用。
注意 |
---|
更改 .NET Framework 目标的过程在 Visual Basic 项目和 Visual C# 项目中是不同的。 |
在 Visual Basic 中更改目标 .NET Framework
在**“解决方案资源管理器”中右击项目名称,然后单击“属性”**。
此时会显示应用程序的属性窗口。
单击**“编译”**选项卡。
在该窗口底部,单击**“高级编译选项…”**。
此时会显示**“高级编译器设置”**对话框。
在**“目标 Framework(所有配置)”**列表中,选择 .NET Framework 4。(不要选择 .NET Framework 4 Client Profile。)
单击**“确定”**。
将显示**“目标 Framework 更改”**对话框。
在**“目标 Framework 更改”对话框中,单击“是”**。
项目将关闭,然后重新打开。
通过以下这些步骤添加对缓存程序集的引用:
在**“解决方案资源管理器”中,右击项目名称,然后单击“添加引用”**。
选择**“.NET”选项卡,选择 System.Runtime.Caching,然后单击“确定”**。
在 Visual C# 项目中更改目标 .NET Framework
在**“解决方案资源管理器”中右击项目名称,然后单击“属性”**。
此时会显示应用程序的属性窗口。
单击**“应用程序”**选项卡。
在**“目标 Framework”列表中,选择 .NET Framework 4。 (不要选择“.NET Framework 4 Client Profile”**。)
通过以下这些步骤添加对缓存程序集的引用:
右击**“引用”文件夹,然后单击“添加引用”**。
选择**“.NET”选项卡,选择 System.Runtime.Caching,然后单击“确定”**。
向 WPF 窗口添加按钮
接下来,您将添加一个按钮控件,并为该按钮的 Click 事件创建事件处理程序。 稍后将添加代码,以便在单击该按钮时,会缓存并显示文本文件的内容。
添加按钮控件
在**“解决方案资源管理器”**中,双击 MainWindow.xaml 文件以将其打开。
在**“工具箱”中的“通用 WPF 控件”**下,将一个 Button 控件拖到 MainWindow 窗口中。
在**“属性”**窗口中,将 Button 控件的 Content 属性设置为“Get Cache”。
初始化缓存并缓存某项
接下来,您将添加代码来执行以下任务:
创建一个缓存类实例,也就是说,您将实例化新的 MemoryCache 对象。
指定缓存将使用 HostFileChangeMonitor 对象来监视文本文件中的更改。
读取文本文件并将其内容缓存为缓存项。
显示缓存文本文件的内容。
创建缓存对象
双击刚添加的按钮以在 MainWindow.xaml.cs 或 MainWindow.Xaml.vb 文件中创建一个事件处理程序。
在文件的顶部(在类声明前面),添加以下 Imports (Visual Basic) 或 using (C#) 语句:
using System.Runtime.Caching; using System.IO;
Imports System.Runtime.Caching Imports System.IO
在事件处理程序中,添加以下代码以实例化缓存对象:
ObjectCache cache = MemoryCache.Default;
Dim cache As ObjectCache = MemoryCache.Default
ObjectCache 类是一个提供内存中对象缓存的内置类。
添加以下代码以读取名为 filecontents 的缓存项的内容:
Dim fileContents As String = TryCast(cache("filecontents"), String)
string fileContents = cache["filecontents"] as string;
添加以下代码以检查是否存在名为 filecontents 的缓存项:
If fileContents Is Nothing Then End If
if (fileContents == null) { }
如果指定的缓存项不存在,则您必须读取该文本文件并将其作为一个缓存项添加到缓存。
在 if/then 块中,添加以下代码以创建一个新的 CacheItemPolicy 对象,该对象指定缓存项将在 10 秒后过期。
Dim policy As New CacheItemPolicy() policy.AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(10.0)
CacheItemPolicy policy = new CacheItemPolicy(); policy.AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(10.0);
如果未提供任何逐出或过期信息,则默认值为 InfiniteAbsoluteExpiration,这意味着缓存项永远不会仅基于绝对时间而过期。 相反,缓存项仅当存在内存压力时才过期。 最佳做法是,您应始终明确提供一个绝对过期或可调过期。
在 if/then 块内部,在上一步中所添加的代码后面添加以下代码,以便为要监视的文件路径创建一个集合,并向该集合中添加文本文件的路径:
Dim filePaths As New List(Of String)() filePaths.Add("c:\cache\cacheText.txt")
List<string> filePaths = new List<string>(); filePaths.Add("c:\\cache\\cacheText.txt");
注意 如果要使用的文本文件不是 c:\cache\cacheText.txt,请指定要使用的文本文件所处位置的路径。
在上一步中所添加的代码后面添加以下代码,以便将新的 HostFileChangeMonitor 对象添加到缓存项的更改监视器集合:
policy.ChangeMonitors.Add(New HostFileChangeMonitor(filePaths))
policy.ChangeMonitors.Add(new HostFileChangeMonitor(filePaths));
HostFileChangeMonitor 对象将监视文本文件的路径并向缓存通知是否发生更改。 在此示例中,如果文件的内容发生更改,则缓存项将过期。
在上一步中所添加的代码后面添加以下代码,以读取文本文件的内容:
fileContents = File.ReadAllText("c:\cache\cacheText.txt") & vbCrLf & DateTime.Now.ToString()
fileContents = File.ReadAllText("c:\\cache\\cacheText.txt") + + "\n" + DateTime.Now;
会添加日期和时间戳,以便您能够看到缓存项何时过期。
在上一步中所添加的代码后面添加以下代码,以将文件内容作为 CacheItem 实例插入到缓存对象中:
cache.Set("filecontents", fileContents, policy)
cache.Set("filecontents", fileContents, policy);
通过作为参数传递前面创建的 CacheItemPolicy 对象,来指定有关应如何逐出缓存项的信息。
在 if/then 块的后面添加以下代码,以便在消息框中显示缓存的文件内容:
MessageBox.Show(fileContents)
MessageBox.Show(fileContents);
在**“生成”菜单中,单击“生成 WPFCaching”**以生成项目。
在 WPF 应用程序中测试缓存
您现在可以测试应用程序。
在 WPF 应用程序中测试缓存
按 Ctrl+F5 以运行应用程序。
将显示 MainWindow 窗口。
单击**“Get Cache”**。
文本文件的缓存内容会显示在消息框中。 请注意文件上的时间戳。
关闭该消息框,然后再次单击**“Get Cache”。**
时间戳未更改。 这将指示显示缓存的内容。
等待 10 秒或更长时间,然后单击**“Get Cache”**。
这次将显示一个新的时间戳。 这指示策略让缓存项过期并显示新的缓存内容。
在文本编辑器中,打开创建的文本文件。 不要进行任何更改。
关闭该消息框,然后再次单击**“Get Cache”。**
再次注意时间戳。
对文本文件进行更改,然后保存文件。
关闭该消息框,然后再次单击**“Get Cache”**。
此消息框包含文本文件的更新内容和新的时间戳。 这指示主机文件更改监视器在您更改文件时立即逐出了缓存项,即使绝对超时时间尚未过期也是如此。
注意 您可将逐出时间提高到 20 秒或更长,以允许您在文件中进行更长时间的更改。
代码示例
完成本演练后,您创建的项目的代码与下面的示例类似。
Imports System.Runtime.Caching
Imports System.IO
Class MainWindow
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles Button1.Click
Dim cache As ObjectCache = MemoryCache.Default
Dim fileContents As String = TryCast(cache("filecontents"), _
String)
If fileContents Is Nothing Then
Dim policy As New CacheItemPolicy()
policy.AbsoluteExpiration = _
DateTimeOffset.Now.AddSeconds(10.0)
Dim filePaths As New List(Of String)()
filePaths.Add("c:\cache\cacheText.txt")
policy.ChangeMonitors.Add(New _
HostFileChangeMonitor(filePaths))
' Fetch the file contents.
fileContents = File.ReadAllText("c:\cache\cacheText.txt") & vbCrLf & DateTime.Now.ToString()
cache.Set("filecontents", fileContents, policy)
End If
MessageBox.Show(fileContents)
End Sub
End Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Runtime.Caching;
using System.IO;
namespace WPFCaching
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
ObjectCache cache = MemoryCache.Default;
string fileContents = cache["filecontents"] as string;
if (fileContents == null)
{
CacheItemPolicy policy = new CacheItemPolicy();
policy.AbsoluteExpiration =
DateTimeOffset.Now.AddSeconds(10.0);
List<string> filePaths = new List<string>();
filePaths.Add("c:\\cache\\cacheText.txt");
policy.ChangeMonitors.Add(new
HostFileChangeMonitor(filePaths));
// Fetch the file contents.
fileContents = File.ReadAllText("c:\\cache\\cacheText.txt") + "\n" + DateTime.Now.ToString();
cache.Set("filecontents", fileContents, policy);
}
MessageBox.Show(fileContents);
}
}
}