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

我觉得这应该很容易,但我的大脑今天早上有问题.

我有自定义UserControl绑定到自定义ItemsSource.我想根据用户定义绘制项目的方式,将其设置为使用匹配的控件绘制每个项目.

例如,我希望能够从使用该控件的类中执行此操作

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来执行此操作?或者有更好的方法来完成这项任务吗?

我还希望能够限制传入的类型只允许其中T:Control,new()的类型

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

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

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>的概念.这将照顾用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代码……

点赞