我觉得这应该很容易,但我的大脑今天早上遇到了问题。
我将自定义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
答案 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代码......