C# 基于datasource c在运行时自动创建表单#
我希望在运行时创建一个表单,它将读取任何数据源的列,并根据列和数据类型创建字段,就像datagridviews插入行一样 致以最良好的祝愿,C# 基于datasource c在运行时自动创建表单#,c#,.net,datagridview,C#,.net,Datagridview,我希望在运行时创建一个表单,它将读取任何数据源的列,并根据列和数据类型创建字段,就像datagridviews插入行一样 致以最良好的祝愿, 标记使用控件数据绑定。它将为您完成所有的工作。您正在做的事情听起来很像PropertyGrid已经在工作了,本质上是: foreach(PropertyDescriptor prop in TypeDescriptor.GetProperties(obj)) { object val = prop.GetValue(obj); string
标记使用控件数据绑定。它将为您完成所有的工作。您正在做的事情听起来很像
PropertyGrid
已经在工作了,本质上是:
foreach(PropertyDescriptor prop in TypeDescriptor.GetProperties(obj)) {
object val = prop.GetValue(obj);
string s = prop.Converter.ConvertToString(val);
Control cont = // TODO: create some control and set x/y
cont.Text = s;
this.Controls.Add(cont);
}
为避免大量对齐工作,使用Dock
设置位置可能会有所帮助:
using(Form form = new Form())
using (PropertyGrid grid = new PropertyGrid())
{
form.Text = obj.ToString(); // why not...
grid.Dock = DockStyle.Fill;
form.Controls.Add(grid);
grid.SelectedObject = obj;
form.ShowDialog(this);
}
不过,我想知道在简单的环境中使用
PropertyGrid
是否更容易。或者有一些类似的方法。我不完全理解你的问题。您是否希望创建一个Windows窗体,为作为其数据源提供给窗体的对象的所有字段/属性提供输入字段(文本框、复选框等)
您可能必须为此使用反射(请参阅System.reflection
命名空间)。例如,要获取所有属性的列表,请执行以下操作:
using System.Reflection;
....
public object DataSource;
...
Debug.Assert( DataSource != null );
var properties = DataSource.GetType().GetProperties();
然后,您将为每个属性实例化一个输入控件:
foreach ( var property in properties )
{
// extract some information about each property:
string propertyName = property.Name;
Type propertyType = property.PropertyType;
bool propertyReadOnly = !property.CanWrite;
// create input controls based on this information:
// ...
}
然而,将属性类型可靠地映射到正确的输入控件可能相当棘手;例如,当遇到类型为未知类的属性时,或者当属性是值的集合时,您将怎么做?在某些情况下,您可能需要在表单内部创建子表单;在其他情况下,一个列表框可能就足够了。我最近构建了一个示例项目,该项目使用ASP.NET的动态数据程序集来为WPF网格执行此操作,但我相信您可以将此概念应用于WinForms。动态数据提供了比反射或数据库更丰富的元数据,但它确实需要实体数据模型或LINQ到SQL数据模型
基本上,您只需参考System.Web.DymamicData,也许您可以在我的课堂上找到一些有用的内容:
public class DynamicDataGridBuilder<TContext, TEntity> where TEntity : EntityObject
{
readonly MetaModel model = new MetaModel();
public DynamicDataGridBuilder()
{
model.RegisterContext(typeof(TContext), new ContextConfiguration { ScaffoldAllTables = true });
}
public void BuildColumns(DataGrid targetGrid)
{
MetaTable metaTable = model.GetTable(typeof(TEntity));
// Decision whether to auto-generated columns still rests with the caller.
targetGrid.Columns.Clear();
foreach (var metaColumn in metaTable.Columns.Where(x => x.GetType().Name == "MetaColumn" && x.Scaffold))
{
switch (metaColumn.ColumnType.Name)
{
case "Boolean":
targetGrid.Columns.Add(new DataGridCheckBoxColumn { Binding = new Binding(metaColumn.Name), Header = metaColumn.DisplayName });
break;
default:
targetGrid.Columns.Add(new DynamicDataGridTextColumn { MetaColumn = metaColumn, Binding = new Binding(metaColumn.Name), Header = metaColumn.DisplayName });
break;
}
}
}
}
公共类DynamicDataGridBuilder,其中tenty:EntityObject
{
只读元模型模型=新元模型();
公共动态网格生成器()
{
RegisterContext(typeof(TContext),新ContextConfiguration{ScaffoldAllTables=true});
}
公共void BuildColumns(DataGrid targetGrid)
{
MetaTable MetaTable=model.GetTable(typeof(tenty));
//是否自动生成列仍取决于调用方。
targetGrid.Columns.Clear();
foreach(metaTable.Columns.Where(x=>x.GetType().Name==“metaColumn”&&x.Scaffold)中的var metaColumn)
{
开关(metaColumn.ColumnType.Name)
{
案例“布尔”:
添加(新DataGridCheckBoxColumn{Binding=newbinding(metaColumn.Name),Header=metaColumn.DisplayName});
打破
违约:
targetGrid.Columns.Add(新的DynamicDataGridTextColumn{MetaColumn=MetaColumn,Binding=new Binding(MetaColumn.Name),Header=MetaColumn.DisplayName});
打破
}
}
}
}
TContext是对象模型的类型,TEntity是该模型中要为其生成控件的实体/类的类型。好的,下面是我的想法
public partial class Form2 : Form
{
private Boolean isBrowsable(PropertyInfo info)
{
return info.GetCustomAttributes(typeof(BrowsableAttribute), false).Length>-1;
}
public Form2()
{
InitializeComponent();
}
public Form2(Boolean showCheckBoxes)
{
InitializeComponent();
_showCheckBoxes = true;
}
private Boolean _showCheckBoxes;
private Object _reflection;
private TableLayoutPanel _table = new TableLayoutPanel{Dock=DockStyle.Fill, CellBorderStyle = TableLayoutPanelCellBorderStyle.Single};
public Object SelectedObject
{
get
{
return _reflection;
}
set
{
//clear all controls from the table
_table.Controls.Clear();
foreach (var property in _reflection.GetType().GetProperties())
{
if (isBrowsable(property))
{
if ((property.PropertyType == typeof(int)) || (property.PropertyType == typeof(string)))
{
var textField = new TextBox { Dock = DockStyle.Fill, AutoSize = true };
textField.DataBindings.Add("Text", _reflection, property.Name);
_table.Controls.Add(textField, 2, _table.RowCount += 1);
var propertyLabel = new Label
{
Text = property.Name,
Dock = DockStyle.Fill,
TextAlign = ContentAlignment.MiddleLeft
};
_table.Controls.Add(propertyLabel, 1, _table.RowCount);
if (_showCheckBoxes)
{
var checkBox = new CheckBox
{
AutoSize = true,
Name = property.Name,
Dock = DockStyle.Left,
CheckAlign = ContentAlignment.TopLeft
};
_table.Controls.Add(checkBox, 0, _table.RowCount);
}
}
}
}
//add one extra row to finish alignment
var panel = new Panel { AutoSize = true };
_table.Controls.Add(panel, 2, _table.RowCount += 1);
_table.Controls.Add(panel, 1, _table.RowCount);
if (_showCheckBoxes)
{
_table.Controls.Add(panel, 0, _table.RowCount);
}
Controls.Add(_table);
if (!Controls.Contains(_table))
Controls.Add(_table);
}
}
public Boolean Execute(Object reflection)
{
SelectedObject = reflection;
return ShowDialog() == DialogResult.OK;
}
}
谢谢大家 它应该很简单,只需循环列集合并实例化新控件。对于数据绑定,它最好使用TypeDescriptor
/PropertyDescriptor
,以支持ICustomTypeDescriptor
,TypeDescriptionProvider
,ITypedList
,等等,这就是上述propertygrid在内部的工作方式吗?是的,没错。理想情况下,我想做的是显示一个表单,其中包含一个datagrid,允许用户选择一行并返回数据绑定对象(数据源由外部源指定)。然后,数据源应该可以通过其任何一个属性(使用linq)进行过滤,因此外部源将调用类似Customer selectedCustomer的东西=(Customer)new SearchResult().Execute(DALConnector.Dc.Customers);公共部分类SearchResult:Form{public Object Execute(Object dataSource){SearchResults.dataSource=dataSource;if(ShowDialog()==DialogResult.OK){if(SearchResults.CurrentRow!=null)return SearchResults.CurrentRow.DataBoundItem;}返回null;}不,不会。数据绑定只在有控件要绑定的情况下工作。propertygrid如何获取名称和数据类型。这正是我需要的,只是我想制作一个自定义格式。我想它可以扩展它….?prop.Name、prop.DisplayName、prop.PropertyType等。这太棒了!我发现了一些问题:属性SelectedObject的Setter没有使用它的值param。您只是通过构造函数设置目标对象。而且,您只能有一个构造函数:public Form2(object reflection=null,Boolean showcheckbox=false)