演练:在 WPF 应用程序中缓存应用程序数据

缓存可以将数据存储在内存中以便快速访问。 再次访问数据时,应用程序可以从缓存获取数据,而不是从原始源检索数据。 这可改善性能和可伸缩性。 此外,数据源暂时不可用时,缓存可提供数据。

.NET Framework 提供了使你能够在 .NET Framework 应用程序中使用缓存的类。 这些类位于 System.Runtime.Caching 命名空间中。

注意

System.Runtime.Caching 是 .NET Framework 4 中的新命名空间。 此命名空间使所有 .NET Framework 应用程序都可以使用缓存。 旧版 .NET Framework 仅在 System.Web 命名空间中提供缓存,因此,需要 ASP.NET 类上的一个依赖项。

本演练介绍如何使用 .NET Framework 中提供的缓存功能作为 Windows Presentation Foundation (WPF) 应用程序的一部分。 在本演练中,你将缓存文本文件的内容。

本演练演示以下任务:

  • 创建 WPF 应用程序项目。

  • 添加对 .NET Framework 4 的引用。

  • 初始化缓存。

  • 添加包含文本文件内容的缓存条目。

  • 为缓存条目提供逐出策略。

  • 监视缓存文件的路径,并就受监视项的变化通知缓存实例。

先决条件

若要完成本演练,你将需要:

  • Visual Studio 2010。

  • 包含少量文本的文本文件。 (将在消息框中显示文本文件的内容。)本演练中演示的代码假定你正在使用以下文件:

    c:\cache\cacheText.txt

    不过,你可以使用任何文本文件并对本演练中的代码稍做更改。

创建 WPF 应用程序项目

首先创建一个 WPF 应用程序项目。

创建 WPF 应用程序

  1. 启动 Visual Studio。

  2. 在“文件”菜单中,单击“新建”,然后单击“新建项目”

    随即显示“新建项目”对话框。

  3. 在“已安装的模板”下,选择要使用的编程语言(Visual Basic 或 Visual C#)。

  4. 在“新建项目”对话框中,选择“WPF 应用程序”

    注意

    如果未显示“WPF 应用程序”模板,请确保以支持 WPF 的 .NET Framework 版本为目标。 在“新建项目”对话框中,从列表中选择 .NET Framework 4。

  5. 在“名称”文本框中,输入项目的名称。 例如,可以输入 WPFCaching

  6. 选择“为解决方案创建目录”复选框

  7. 单击“确定”。

    WPF 设计器会在“设计”视图中打开并显示 MainWindow.xaml 文件。 Visual Studio 会创建“我的项目”文件夹、Application.xaml 文件和 MainWindow.xaml 文件。

以 .NET Framework 为目标并添加对缓存程序集的引用

默认情况下,WPF 应用程序以 .NET Framework 4 客户端配置文件为目标。 若要在 WPF 应用程序中使用 System.Runtime.Caching 命名空间,应用程序必须以 .NET Framework 4(而不是 .NET Framework 4 客户端配置文件)为目标,并且必须包含对该命名空间的引用。

因此,下一步是更改 .NET Framework 目标并添加对 System.Runtime.Caching 命名空间的引用。

注意

更改 .NET Framework 目标的过程在 Visual Basic 项目和 Visual C# 项目中有所不同。

在 Visual Basic 中更改目标 .NET Framework

  1. 在解决方案资源管理器中,右键单击项目名称,然后单击“属性”

    随即显示应用程序的属性窗口。

  2. 单击“编译” 选项卡。

  3. 在窗口底部,单击“高级编译选项…”

    随即显示“高级编译器设置”对话框

  4. 在“目标框架(所有配置)”列表中,选择“.NET Framework 4”。 (请勿选择“.NET Framework 4 客户端配置文件”。)

  5. 单击“确定”。

    随即显示“目标框架更改”对话框。

  6. 在“目标框架更改”对话框中,单击“是”

    项目将关闭,然后重新打开。

  7. 按照以下步骤添加对缓存程序集的引用:

    1. 在解决方案资源管理器中,右键单击项目名称,然后单击“添加引用”

    2. 选择“.NET”选项卡,选择 System.Runtime.Caching,然后单击“确定”

在 Visual C# 项目中更改目标 .NET Framework

  1. 在解决方案资源管理器中,右键单击项目名称,然后单击“属性”

    随即显示应用程序的属性窗口。

  2. 单击“应用程序” 选项卡。

  3. 在“目标框架”列表中,选择“.NET Framework 4”。 (请勿选择“.NET Framework 4 客户端配置文件”。)

  4. 按照以下步骤添加对缓存程序集的引用:

    1. 右键单击“引用”文件夹,然后单击“添加引用”

    2. 选择“.NET”选项卡,选择 System.Runtime.Caching,然后单击“确定”

向 WPF 窗口添加按钮

接下来,添加按钮控件并为按钮的 Click 事件创建事件处理程序。 稍后将添加代码,以便在单击按钮时,缓存并显示文本文件的内容。

添加按钮控件

  1. 在解决方案资源管理器中,双击 MainWindow.xaml 文件将其打开。

  2. 从工具箱的“常用 WPF 控件”下,将 Button 控件拖到 MainWindow 窗口中。

  3. 在“属性”窗口中,将 Button 控件的 Content 设置为“获取缓存”

初始化缓存并缓存条目

接下来,添加代码以执行以下任务:

  • 创建缓存类实例,即实例化新的 MemoryCache 对象。

  • 指定缓存使用 HostFileChangeMonitor 对象来监视文本文件中的更改。

  • 读取文本文件,并将其内容缓存为缓存条目。

  • 显示缓存文本文件的内容。

创建缓存对象

  1. 双击刚刚添加的按钮,以便在 MainWindow.xaml.cs 或 MainWindow.Xaml.vb 文件中创建事件处理程序。

  2. 在文件顶部(类声明之前),添加以下 Imports (Visual Basic) 或 using (C#) 语句:

    using System.Runtime.Caching;
    using System.IO;
    
    Imports System.Runtime.Caching
    Imports System.IO
    
  3. 在事件处理程序中,添加以下代码以实例化缓存对象:

    ObjectCache cache = MemoryCache.Default;
    
    Dim cache As ObjectCache = MemoryCache.Default
    

    ObjectCache 类是提供内存中对象缓存的内置类。

  4. 添加以下代码以读取名为 filecontents 的缓存条目的内容:

    Dim fileContents As String = TryCast(cache("filecontents"), String)
    
    string fileContents = cache["filecontents"] as string;
    
  5. 添加以下代码以检查名为 filecontents 的缓存条目是否存在:

    If fileContents Is Nothing Then
    
    End If
    
    if (fileContents == null)
    {
    
    }
    

    如果指定的缓存条目不存在,则必须读取文本文件并将其作为缓存条目添加到缓存中。

  6. 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,这意味着缓存条目永远不会仅基于绝对时间过期。 相反,缓存条目仅在存在内存压力时才会过期。 作为最佳做法,应始终显式提供绝对过期或可调过期。

  7. 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,请指定要使用的文本文件的路径。

  8. 在上一步添加的代码后面,添加以下代码以将新的 HostFileChangeMonitor 对象添加到缓存条目的更改监视器集合中:

    policy.ChangeMonitors.Add(New HostFileChangeMonitor(filePaths))
    
    policy.ChangeMonitors.Add(new HostFileChangeMonitor(filePaths));
    

    HostFileChangeMonitor 对象监视文本文件的路径,并在发生更改时通知缓存。 在此示例中,如果文件内容发生更改,缓存条目将过期。

  9. 在上一步添加的代码后面,添加以下代码以读取文本文件的内容:

    fileContents = File.ReadAllText("c:\cache\cacheText.txt") & vbCrLf & DateTime.Now.ToString()
    
    fileContents = File.ReadAllText("c:\\cache\\cacheText.txt") + "\n" + DateTime.Now;
    

    系统添加了日期和时间时间戳,以便你能够看到缓存条目何时过期。

  10. 在上一步添加的代码后面,添加以下代码以将文件的内容作为 CacheItem 实例插入缓存对象:

    cache.Set("filecontents", fileContents, policy)
    
    cache.Set("filecontents", fileContents, policy);
    

    可通过将之前创建的 CacheItemPolicy 对象作为参数传递,指定有关应如何逐出缓存条目的信息。

  11. if/then 块后面添加以下代码,以在消息框中显示缓存的文件内容:

    MessageBox.Show(fileContents)
    
    MessageBox.Show(fileContents);
    
  12. 在“生成”菜单中,单击“生成 WPFCaching”以生成项目

在 WPF 应用程序中测试缓存

现在可以测试此应用程序。

在 WPF 应用程序中测试缓存

  1. 按 Ctrl+F5 运行应用程序。

    随即显示 MainWindow 窗口。

  2. 单击“获取缓存”

    来自文本文件的缓存内容显示在消息框中。 请注意文件上的时间戳。

  3. 关闭消息框,然后再次单击“获取缓存”

    时间戳不变。 这表明显示的是缓存内容。

  4. 等待 10 秒或更长时间,然后再次单击“获取缓存”

    这次显示一个新的时间戳。 这表明该策略让缓存条目过期并显示新的缓存内容。

  5. 在文本编辑器中,打开创建的文本文件。 暂时不要进行任何更改。

  6. 关闭消息框,然后再次单击“获取缓存”

    再次注意时间戳。

  7. 对文本文件进行更改,然后保存文件。

  8. 关闭消息框,然后再次单击“获取缓存”

    此消息框包含来自文本文件的更新内容和新时间戳。 这表明主机文件更改监视器在你更改文件时立即逐出缓存条目,即使绝对超时期限尚未到期也是如此。

    注意

    你可以将逐出时间增加到 20 秒或更长时间,以便有更多时间对文件进行更改。

代码示例

完成本演练后,你创建的项目的代码将类似于以下示例。

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);
        }
    }
}
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

另请参阅