我有一个我想要构建的控件框架的概念。使这个想法与众不同的是,我不打算采用“一刀切”的方法或“一个控制来统治所有人”的方法。
作为一个例子,Telerik做了一个非常好的网格控件,ComponentOne,Xceed等也是如此。但是,它们都是巨大的控件,有数百或数千种方法和属性,复杂的对象模型层次结构等等...这些网格往往对你所需要的东西有点过分,但你仍然需要承担学习整个网格的艰巨任务来做一些简单的事情。
我的概念更像是一种“混合”的方式。在哪里创建一个非常简单的控件,然后构建可以“加载”到控件点菜的功能。例如,您有一个简单的网格,并且您希望为每个网格添加带有页眉和页脚的网格“部分”。
好的,问题出在哪里?做这样的事情的传统方式是通过多重继承,C#不支持。即使它确实支持它,我仍然认为MI增加了比它解决的问题更多的问题。
因此,我正在征求SO的意见,以了解如何解决这个问题。 MEF会成为潜在的解决方案吗?
编辑:
我遇到的一点是,可以使用表达式树从各种表达式构建控件。我不得不考虑更多,但这是一个有趣的概念。
另一个可能的选项可能是“控制生成器”,它根据所选功能生成一个程序集。这似乎更复杂,但T4可能是可管理的。
答案 0 :(得分:3)
一些选项
考虑装饰者模式;小对象,它们可以扩展在运行时可以构建的相当极简的类的行为。 Dotnet框架中的规范示例将围绕IO流(例如StreamReader / Writer,TextStreamReader / Writer,FileStreamReader / Writer);在OO UI框架中也很常见,典型示例看起来像var window=new HorizontalScrollingWindowDecorator(new VerticalScrollingWindowDecorator(new Window));
状态,策略,命令和复合模式为处理行为组合提供了各种替代方案,而无需大量控制流程。例如,您将某些类型的行为委托给对象的当前状态(您的一些类方法基本上调用当前对象State的方法)。您还可以将行为委派给命令对象,或使用复合命令构建复杂命令。单继承通常会引导您支持对象的组合而不是继承,这些都是用于组合行为的经典模式,这些模式适用于单继承。
当特定实例需要实现一些小的行为时,您可以使用委托作为函数式编程中常见的“中间漏洞”模式。
您可以使用PostSharp或类似的面向方面的编程工具来执行运行时或编译时的行为编织,尤其适用于几个不同类的行为所需的行为,这些行为与该课程的主要责任。
答案 1 :(得分:2)
就我个人而言,我认为多重继承对于实现这种设计来说是一种糟糕的方式。似乎多数继承在大多数时候都是一个糟糕的设计。继承是组件之间关系的僵化。
组合更加灵活,在这种情况下,MEF将是一个非常好的起点。
控件的基类将是行为的容器 - 本质上是MEF容器。
它仍然存在其他类如何与控件交互的问题。有很多选择。例如基本控件上的标准接口,消息传递,甚至在C#4.0中使用动态绑定。
答案 2 :(得分:1)
我想尝试回答,而不是评论这是否值得解决。
我没有尝试过这个组件,但理论上有Decorator Pattern:您可以在运行时添加插件来拦截控件(键盘和鼠标)输入和(屏幕)输出。
答案 3 :(得分:1)
WPF通过允许您将逻辑元素的可视表示与数据模板合成来解决此问题。 Control类本身不是混合使用功能来创建一个新的Control类,而是通过结合各种类型的内容来提供可扩展性点,并使用丰富的模板系统来安排和可视化内容。
换句话说,仍然可以说是“一个控制来统治它们”,但控制是一个骨架,而不是一个完全充实的身体。脚手架提供了一个易于理解的框架,在其中添加功能,模板系统提供了用于充实控件部件的粘合剂。
关于MEF,MEF购买的是发现和注入扩展代码。它很有价值,但并没有直接解决你所描述的问题。您的问题与代码的发现关系不大,更多的是与代码组合的机制有关,以创建一致的整体控件。 MEF可以帮助执行一些胶合,但它只是问题的一小部分。
答案 4 :(得分:0)
您是否想构建一个Add-In类型的框架?我肯定会指向Managed Extensibility Framework。可以在.Net 4.0中使用WinForms或WPF。
答案 5 :(得分:0)
如果您对已经实现了mixin的框架感兴趣,请查看re-motion框架(https://www.re-motion.org/)。令人惊讶的是,mixins在这个框架中可以轻松实现,
以下是“Hello World”级别的参考申请。
使用从webseite下载的程序集,在VS2010中创建一个类库和一个控制台应用程序,在这两个项目中添加对assmblies remotion.dll和remotion.interfaces.dll的引用。
using System;
namespace Domain
{
public class Person
{
public Person()
{
}
public Person(Person person)
{
FirstName = person.FirstName;
LastName = person.LastName;
BirthDay = person.BirthDay;
}
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime BirthDay { get; set; }
}
}
using System;
using Remotion.Mixins;
namespace Domain
{
public interface IEmployeeMixin
{
int Salary { get; set; }
DateTime? HireDate { get; set; }
}
[Extends(typeof(Person))]
public class EmployeeMixin : IEmployeeMixin
{
public int Salary { get; set; }
public DateTime? HireDate { get; set;}
public EmployeeMixin()
{
// set default values
Salary = 1000;
HireDate = DateTime.Now;
}
}
}
using Domain;
using Remotion.Reflection;
using Remotion.Mixins;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
Person p = new Person();
p.FirstName = "John";
p.LastName = "Doe";
var employee = (IEmployeeMixin)ObjectFactory.Create<Person>(ParamList.Create(p));
System.Console.WriteLine("Fullname: {0}", ((Person)employee).FirstName + " " + ((Person)employee).LastName);
System.Console.WriteLine("Salary: {0}", employee.Salary);
System.Console.ReadKey();
}
}
}
基于这个参考实现,应该很容易理解,这个mixin是如何在这个框架中实现的。如果您想获得有关此框架(它是一个完整的DDD开发框架)或mixins的更多信息,请不要犹豫。我可以为您提供更多文档。
的Stefan