在XAML中实现泛型支持

在WPF开发中,经常需要使用泛型来创建灵活且可重用的组件。然而,泛型在XAML中的使用并不像在C#代码中那样直观。幸运的是,WPF团队提供了正确的机制,使得开发者能够在XAML中完全支持泛型。本文将通过一个简单的示例,展示如何在XAML中实现泛型支持。

首先,需要了解一个典型的WPF窗口由两个部分构成:代码后置(code behind)和XAML。在编译时,这两个部分会合并成一个生成的文件。为了在由代码后置和XAML组成的文件中正确支持泛型,必须确保这两个部分都使用了泛型类型参数。下面通过一个示例来说明这一点。

假设有一个通用的窗口基类,它是泛型的。然后继承这个基类,并在代码后置和XAML中提供泛型参数,使其成为泛型类型。为了演示这一点,构建了一个小型演示应用程序,其中包括以下内容:

首先,定义了一个名为LoggingStrategy的抽象基类,如下所示:

using System; namespace GenericViews { public abstract class LoggingStrategy { public abstract void LogText(string textToLog); } }

然后,定义了一个具体的类,它重写了LogText(…)方法,如下所示:

using System; using System.Windows; namespace GenericViews { public class MessageBoxLogger : LoggingStrategy { public override void LogText(string textToLog) { MessageBox.Show(textToLog); } } }

接下来,在WPF应用程序的主App类中,创建了一个简单的Dictionary查找,用于根据Type获取正确的日志策略。这个Type将来自视图提供的泛型参数,稍后会看到。

using System; using System.Collections.Generic; using System.Windows; namespace GenericViews { public partial class App : Application { public static Dictionary Loggers = new Dictionary(); static App() { Loggers.Add(typeof(MessageBoxLogger), new MessageBoxLogger()); } } }

现在已经涵盖了所有演示内容,接下来来处理实际的泛型部分。在附带的演示中,提供了一个小型的视图基类,这个基类是泛型的,并将从static App Dictionary中查找正确的LoggingStrategy继承对象。

using System; using System.Collections.Generic; using System.Windows; namespace GenericViews { public class ViewBase : Window where T : LoggingStrategy { public LoggingStrategy CurrentLogger { get; private set; } public ViewBase() { CurrentLogger = App.Loggers[typeof(T)]; } } }

可以看到,这个基类期望一个泛型参数T,以便工作。T必须继承自LoggingStrategy。然后,泛型参数用于从static App Dictionary中获取正确的LoggingStrategy继承对象。

接下来,需要创建一个自定义窗口,它继承自ViewBase,并传递一个泛型参数。让从简单的代码后置部分开始。这部分非常简单,只需使用标准的泛型,就像使用任何其他泛型类一样:

using System; using System.Collections.Generic; using System.Windows; namespace GenericViews { public partial class MessageLoggingWindow : ViewBase { public MessageLoggingWindow() : base() { InitializeComponent(); } private void Button_Click(object sender, RoutedEventArgs e) { base.CurrentLogger.LogText(String.Format("Some text which was logged at {0}", DateTime.Now.ToShortTimeString())); } } }

现在简单的部分已经完成,让专注于XAML部分。

<local:ViewBase x:Class="GenericViews.MessageLoggingWindow" x:TypeArguments="local:MessageBoxLogger" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:GenericViews" > … </local:ViewBase>

这里发生了什么?实际上有一些事情,让逐一了解。

x:Class:这是类的名称,它与代码后置的命名空间和类名匹配。 xmlns:local:这是一个命名空间别名,允许在XAML中使用local:指向GenericViews命名空间中的类。 <local:ViewBase…/>:意味着使用GenericViews.ViewBase<T>作为这个新窗口的基类,但是等等,泛型参数在哪里?这就是第四步。 x:TypeArguments:这是泛型值插入的地方。所以现在在XAML中声明了一个窗口,它实际上是GenericViews.ViewBase<MessageBoxLogger>

就是这样……知道例子并不完全符合现实世界,但那不是本文的重点,只是想向展示如何在XAML中创建泛型,从这个角度来看,这篇文章应该能够做到。

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

希望喜欢!

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485