[英]How do you bind Dapper query result to WPF DataGrid
Here's my code. 这是我的代码。 It produces a bound grid with the correct number of rows, however the cells are empty . 它生成具有正确行数的绑定网格,但单元格为空 。
XAML XAML
<DataGrid
Name="grid"
ItemsSource="{Binding}"
AutoGenerateColumns="True" />
Code behind 代码背后
grid.DataContext = cn.Query("select * from SomeTable");
From the docs , your syntax there -- cn.Query("sql")
-- returns a list of dynamic-typed objects ( IEnumerable<dynamic>
). 从文档中 ,你的语法cn.Query("sql")
- 返回一个动态类型对象列表( IEnumerable<dynamic>
)。 That won't work for the DataGrid auto-columns, which looks for concrete members to generate its columns. 这对于DataGrid自动列不起作用,后者查找具体成员生成其列。 I'd suggest creating a simple entity class for SomeTable to map the properties and then using cn.Query<SomeTableEntity>("select * from SomeTable");
我建议为SomeTable创建一个简单的实体类来映射属性,然后使用cn.Query<SomeTableEntity>("select * from SomeTable");
. 。
So I guess the answer is: it's not possible. 所以我猜答案是:这是不可能的。 Here's a hacky workaround. 这是一个hacky解决方法。
...
var items = cn.Query("select * from SomeTable");
grid.DataContext = ConvertToDataTable(items);
}
public DataTable ConvertToDataTable(IEnumerable<dynamic> items) {
var t = new DataTable();
var first = (IDictionary<string, object>)items.First();
foreach (var k in first.Keys)
{
var c = t.Columns.Add(k);
var val = first[k];
if (val != null) c.DataType = val.GetType();
}
foreach (var item in items)
{
var r = t.NewRow();
var i = (IDictionary<string, object>)item;
foreach (var k in i.Keys)
{
var val = i[k];
if (val == null) val = DBNull.Value;
r[k] = val;
}
t.Rows.Add(r);
}
return t;
}
If you use the non-generic version of Query, it returns a dynamic representation of the data. 如果使用非泛型版本的Query,则返回数据的动态表示。 The dynamic API is not suitable for most UI data-bindings. 动态API不适合大多数UI数据绑定。 It would be preferable to use the generic Query<T>
API to load the data into types that have defined properties. 最好使用通用Query<T>
API将数据加载到具有已定义属性的类型中。
At a complete push , it would also theoretically be possible to implement ITypedList on the data and expose the properties accordingly. 完全推动 ,理论上也可以在数据上实现ITypedList并相应地公开属性。 But that is quite a lot of work for not so much gain. 但这并没有太大的收获。
It is not possible with pure Linq ! 纯粹的Linq是不可能的! It is possible reusing OLD dataset and convert back to linq using System.Data.DataSetExtensions. 可以重用OLD数据集并使用System.Data.DataSetExtensions转换回linq。 (Not Elegant but it works) (不优雅,但它的工作原理)
// Steal concrete connection from Linq
ModelDEmoWPFContainer l_ctx = new ModelDEmoWPFContainer();
var l_connection = (System.Data.EntityClient.EntityConnection)l_ctx.Connection)
.StoreConnection;
System.Data.SqlClient.SqlCommand l_cmd =
new System.Data.SqlClient.SqlCommand(query_arg);
l_cmd.Connection = (System.Data.SqlClient.SqlConnection) l_connection;
System.Data.SqlClient.SqlDataAdapter l_da =
new System.Data.SqlClient.SqlDataAdapter(l_cmd);
System.Data.DataSet l_ds = new System.Data.DataSet();
l_da.Fill(l_ds);
CLONE metadata CLONE元数据
System.Data.DataTable l_dt = l_ds.Tables[0].Clone();
back to linq via System.Data.DataSetExtensions 通过System.Data.DataSetExtensions返回linq
var dt = (from data in l_ds.Tables[0].AsEnumerable()
select data).ToList();
foreach (DataColumn column in l_dt.Columns)
{
var binding = new Binding(string.Format("[{0}]", column.Ordinal));
datagrid.Columns.Add(new DataGridTextColumn()
{ Header = column.ColumnName, Binding = binding });
}
datagrid.ItemsSource = dt;
If you are using MVVM pattern, I think this is better solution: 如果您使用的是MVVM模式,我认为这是更好的解决方案:
Create ObservableCollecion in your ViewModel, which will be binded to ItemSource
in DataGrid
: 在ViewModel中创建ObservableCollecion,它将绑定到DataGrid
ItemSource
:
public ObservableCollection<T> bindableCollection;
Then, fetch data from your database, example: 然后,从数据库中获取数据,例如:
public void RefreshDataGrid(){
using (var conn = new SqlConnection(ConfigurationManager.ConnectionStrings[
"RecipeManager.Properties.Settings.RecipeManagerConnectionString"].ConnectionString)){
var fetchedData = conn.Query<Flavour>("select * from [Flavour]");
ConvertToDataTable(fetchedData);
}
}
Last step, and the most important, create function, which will add IEnumerable to your ObservableCollection: 最后一步,也是最重要的创建函数,它将IEnumerable添加到你的ObservableCollection中:
private void ConvertToObservableCollection(IEnumerable<Flavour> items){
ObservableCollection<Flavour> flavours = new ObservableCollection<Flavour>();
foreach (var item in items){
Flavour flavour = item as Flavour;
flavours.Add(new Flavour(flavour.Name,flavour.Company,flavour.Shop,flavour.Amount));
}
Flavours = flavours;
}
I think, that this is good approach for mvvm. 我认为,这是mvvm的好方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.