XAML 中的泛型支持






4.89/5 (5投票s)
XAML 中的泛型支持。
我已经使用 XAML/WPF 一段时间了,但直到最近我才想到 XAML 中的泛型支持。我不知道是否可行,所以我决定快速研究一下。
幸运的是,WPF 团队考虑到了这一点,并且确实为 WPF 开发人员启用了正确的机制,以完全支持来自 XAML 的泛型。
您需要知道的第一件事是,典型的 WPF 窗口由 2 个分部类组成,即代码隐藏和 XAML。然后在编译时,会形成一个组合文件,称为生成的文件,它是代码隐藏文件和 XAML 文件的组合。
因此,为了正确支持由代码隐藏和 XAML 组成的文件的泛型,我们**必须**确保文件的两个部分都使用泛型类型参数。当我们看到一个小的例子时,这一点应该会变得更清楚。
为了演示 XAML 中对泛型的支持,让我们考虑一个小例子,它需要以下安排
- 我们有一个通用的窗口基类,它是泛型的
- 我们继承自通用的窗口基类,但我们需要在代码隐藏和 XAML 中提供泛型参数,以使其成为泛型类型。
基本上这就是我们想要做的。为了演示这一点,我构建了一个小的演示应用程序,它执行以下操作
我有一个名为 LoggingStrategy
的 abstract
基类,它看起来像这样
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>
现在,这里到底发生了什么? 实际上,发生了一些事情,让我们来看看。
x:Class
:这是类的名称,它与代码隐藏命名空间和类名匹配xmlns:local
:这是一个namespace
别名,允许我们在 XAML 中使用 local: 来指向GenericViews namespace
中的类<local:ViewBase…/>
:表示我们使用GenericViews.ViewBase<T>
作为此新 Window 的基类,但是泛型参数呢? 好了,那是步骤 4。x:TypeArguments
:这是插入泛型值的地方。 因此,我们现在在 XAML 中声明了一个窗口,它实际上是GenericViews.ViewBase<MessageBoxLogger>
就是这样……我知道我的示例不是完全真实的,但这不是重点,我只是想向您展示如何在 XAML 中创建泛型,为此,这篇文章应该可以做到。
这是一个小的演示应用程序,它创建了一个带有 MessageBoxLogger
的泛型窗口,运行时看起来像这样
尽情享用!
注意
该博客的读者还向我指出了 Mike Hillberg 的另一篇文章,其中涵盖了 XAML 中的许多其他泛型支持,请在此处查看,这非常酷。