65.9K
CodeProject 正在变化。 阅读更多。
Home

XAML 中的泛型支持

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.89/5 (5投票s)

2009年6月17日

CPOL

4分钟阅读

viewsIcon

45519

XAML 中的泛型支持。

我已经使用 XAML/WPF 一段时间了,但直到最近我才想到 XAML 中的泛型支持。我不知道是否可行,所以我决定快速研究一下。

幸运的是,WPF 团队考虑到了这一点,并且确实为 WPF 开发人员启用了正确的机制,以完全支持来自 XAML 的泛型。

您需要知道的第一件事是,典型的 WPF 窗口由 2 个分部类组成,即代码隐藏和 XAML。然后在编译时,会形成一个组合文件,称为生成的文件,它是代码隐藏文件和 XAML 文件的组合。

37317/build-thumb.jpg

因此,为了正确支持由代码隐藏和 XAML 组成的文件的泛型,我们**必须**确保文件的两个部分都使用泛型类型参数。当我们看到一个小的例子时,这一点应该会变得更清楚。

为了演示 XAML 中对泛型的支持,让我们考虑一个小例子,它需要以下安排

  1. 我们有一个通用的窗口基类,它是泛型的
  2. 我们继承自通用的窗口基类,但我们需要在代码隐藏和 XAML 中提供泛型参数,以使其成为泛型类型。

基本上这就是我们想要做的。为了演示这一点,我构建了一个小的演示应用程序,它执行以下操作

我有一个名为 LoggingStrategyabstract 基类,它看起来像这样

   1:  using System;
   2:  
   3:  namespace GenericViews
   4:  {
   5:      public abstract class LoggingStrategy
   6:      {
   7:          public abstract void LogText(string textToLog);
   8:      }
   9:  }

然后我有一个特定的类,它重写了 LogText(…) 方法,如下所示

   1:  using System;
   2:  using System.Windows;
   3:  
   4:  namespace GenericViews
   5:  {
   6:      public class MessageBoxLogger : LoggingStrategy
   7:      {
   8:          public override void LogText(string textToLog)
   9:          {
  10:              MessageBox.Show(textToLog);
  11:          }
  12:      }
  13:  }

然后在主要的 App 类中,如果您在 VS2008 中启动一个新的 WPF 应用程序,我已经创建了一个简单的 Dictionary 查找,用于 Type 以获取要使用的正确的日志记录策略。 想法是 Type 将来自视图提供的泛型参数,我们将在稍后看到。

现在,您需要知道的是,有一个针对 Type 的查找,它返回一个 LoggingStrategy 继承的对象。

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Windows;
   4:  
   5:  namespace GenericViews
   6:  {
   7:      public partial class App : Application
   8:      {
   9:          public static Dictionary<Type, LoggingStrategy> Loggers =
  10:              new Dictionary<Type, LoggingStrategy>();
  11:  
  12:  
  13:          static App()
  14:          {
  15:              Loggers.Add(typeof(MessageBoxLogger), new MessageBoxLogger());
  16:          }
  17:      }
  18:  }

因此,我们已经几乎涵盖了所有演示内容,现在只需处理实际的泛型内容。 在附加的演示中,我为视图提供了一个小的基类,并且该基类是泛型的,并且将从 static App Dictionary 中存储的 Dictionary 查找正确的 LoggingStrategy 继承的对象。

这是视图的基类。

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Windows;
   4:  
   5:  namespace GenericViews
   6:  {
   7:      public class ViewBase<T> : Window where T : LoggingStrategy
   8:      {
   9:          public LoggingStrategy CurrentLogger { get; private set; }
  10:  
  11:          public ViewBase()
  12:          {
  13:              CurrentLogger = App.Loggers[typeof(T)];
  14:          }
  15:      }
  16:  }

可以看出,此基类需要一个泛型参数 T 才能工作。 T 必须继承自 LoggingStrategy。然后发生的事情是,泛型参数用于从 static App Dictionary 中存储的 Dictionary 获取正确的 LoggingStrategy 继承的对象。

好的,我们快完成了,我们现在要做的就是创建一个自定义窗口,该窗口继承自 ViewBase<T> 并传递一个泛型参数。

让我们从简单的一部分开始,代码隐藏。 这部分非常简单,我们只需使用标准的泛型内容,就像使用任何其他泛型类一样

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Windows;
   4:  
   5:  
   6:  namespace GenericViews
   7:  {
   8:  
   9:      public partial class MessageLoggingWindow : ViewBase<MessageBoxLogger>
  10:      {
  11:          public MessageLoggingWindow() : base()
  12:          {
  13:              InitializeComponent();
  14:          }
  15:  
  16:          private void Button_Click(object sender, RoutedEventArgs e)
  17:          {
  18:              base.CurrentLogger.LogText(
  19:                  String.Format(“Sometext which was logged at {0}”,
  20:                  DateTime.Now.ToShortTimeString()));
  21:          }
  22:      }
  23:  }

既然简单的部分已经完成,为什么不把我们的精力集中在 XAML 部分呢。

   1:  <local:ViewBase
   2:      x:Class=”GenericViews.MessageLoggingWindow”
   3:      x:TypeArguments=”local:MessageBoxLogger”
   4:      xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
   5:      xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
   6:      xmlns:local=”clr-namespace:GenericViews”>
   7:  …
   8:  …
   9:  </local:ViewBase>

现在,这里到底发生了什么? 实际上,发生了一些事情,让我们来看看。

  1. x:Class:这是类的名称,它与代码隐藏命名空间和类名匹配
  2. xmlns:local:这是一个 namespace 别名,允许我们在 XAML 中使用 local: 来指向 GenericViews namespace 中的类
  3. <local:ViewBase…/>:表示我们使用 GenericViews.ViewBase<T> 作为此新 Window 的基类,但是泛型参数呢? 好了,那是步骤 4。
  4. x:TypeArguments:这是插入泛型值的地方。 因此,我们现在在 XAML 中声明了一个窗口,它实际上是 GenericViews.ViewBase<MessageBoxLogger>

就是这样……我知道我的示例不是完全真实的,但这不是重点,我只是想向您展示如何在 XAML 中创建泛型,为此,这篇文章应该可以做到。

这是一个小的演示应用程序,它创建了一个带有 MessageBoxLogger 的泛型窗口,运行时看起来像这样

37317/image-thumb.png

尽情享用!

注意

该博客的读者还向我指出了 Mike Hillberg 的另一篇文章,其中涵盖了 XAML 中的许多其他泛型支持,请在此处查看,这非常酷。

© . All rights reserved.