我觉得这应该很容易,但我的大脑今天早上有问题.
我有自定义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代码……