DataType存储和使用具有特定限制的泛型类型?

时间:2014-08-15 14:38:18

标签: c# winforms .net-3.5

我觉得这应该很容易,但我的大脑今天早上遇到了问题。

我将自定义UserControl绑定到自定义ItemsSource。我想根据用户定义绘制项目的方式,使用匹配的Control来设置每个项目。

例如,我希望能够从使用控件的类

执行此操作
var data = new List<object>();
data.Add(new MyClassA());
data.Add(new MyClassB());
data.Add(new MyClassB());

myCustomControl.ItemsSource = myObjectArray;

myCustomControl.ResourceLibrary = {
    { MyClassA, ctlClassA },
    { MyClassB, ctlClassB }
}

在我的自定义控件中,这些内容

foreach(var item in ItemsSource)
{
    var key = item.GetType();

    if (ResourceLibrary.ContainsKey(key))
    {
        var ctlType = ResourceLibrary[key];
        if (ctlType != null)
        {
            var ctl = new ctlType();
            // Do something with control
        }
    }
}

我可以使用哪种数据类型ResourceLibrary允许我这样做?或者有更好的方法来完成这项任务吗?

我还希望能够将传入的类型限制为仅允许类型where T : Control, new()

我正在使用WinForms,C#和.Net 3.5

1 个答案:

答案 0 :(得分:2)

在最基本的层面上,我认为这样的事情可能有所帮助:

public class DataTemplateManager
{
    private readonly Dictionary<Type, Type> dataTemplates = new Dictionary<Type, Type>();

    public void Add<TModel, TView>() where TView : Control, new()
    {
        dataTemplates.Add(typeof (TModel), typeof (TView));
    }

    public void Add(Type modelType, Type viewType)
    {
        if (!typeof (Control).IsAssignableFrom(viewType))
            throw new InvalidOperationException("viewType must derive from System.Windows.Forms.Control");

        dataTemplates.Add(modelType, viewType);
    }

    public Control Resolve(object model)
    {
        if (model == null)
            return null;

        var type = model.GetType();

        if (!dataTemplates.ContainsKey(type))
            return null;

        var viewType = dataTemplates[type];

        var control = Activator.CreateInstance(viewType);

        return control as Control;
    }
}

然后只需将此类型的属性放入您的控件中:

public class MyControl: Control
{
    public DataTemplateManager DataTemplateManager {get; private set;}

    public MyControl()
    {
        this.DataTemplateManager = new DataTemplateManager();
    }
}

然后您可以这样使用:

myControl1.DataTemplateManager.Add<MyModel1, MyView1>();
myControl1.DataTemplateManager.Add<MyModel2, MyView2>();
myControl1.DataTemplateManager.Add<MyModel3, MyView3>();

并使用Resolve()方法,如下所示:

foreach(var item in ItemsSource)
{
    var ctl = this.DataTemplateManager.Resolve(item);

    //.. do something with ctl     
}

此外,我可以考虑添加非常有用的功能,例如IBinder<TModel,TView>的概念,它将处理do something with ctl..部分:

public interface IBinder<TModel,TView>
{
     void Bind(TModel model, TView view);
}

public class MyBinder: IBinder<MyModel1,MyView1>
{
    public void Bind(MyModel1 model, MyView1 view)
    {
         view.SomeProperty = model.SomeOtherProperty;
         //.. And so on.
    }
}

然后:

myControl.DataTemplateManager.AddBinder<TModel1,TView1,MyBinder>();

并在Resolve()方法中使用它。

请注意,这不会处理继承或泛型。如果你需要支持这些场景,那么认为会更复杂一点,但它仍然可行。

顺便说一句,我试图尽可能抽象。否则人们可能会认为我正在编写winforms代码......