如何将Dapper查询结果绑定到WPF DataGrid?

7
这是我的代码。它生成一个带有正确行数的边界网格,但是单元格为空
XAML
<DataGrid
  Name="grid" 
  ItemsSource="{Binding}"
  AutoGenerateColumns="True" />

代码后台
grid.DataContext = cn.Query("select * from SomeTable");

1
你尝试给它一个类型了吗?cn.Query<SomeType>(...); - mxmissile
我需要保持通用性,因为网格根据用户输入绑定到不同的类型。 - Seth Reno
5个回答

5
所以我想答案是:这是不可能的。以下是一个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;
    }

5
文档中可以看到,你的语法--cn.Query("sql")--返回一个动态类型的对象列表(IEnumerable<dynamic>)。这对于DataGrid自动生成列来说是不起作用的,因为它需要具体的成员来生成列。我建议创建一个简单的实体类来映射SomeTable的属性,然后使用cn.Query<SomeTableEntity>("select * from SomeTable");

3

如果您使用非泛型版本的Query,则返回数据的动态表示形式。动态API不适用于大多数UI数据绑定。最好使用通用的Query<T> API将数据加载到具有定义属性的类型中。

完全推送下,理论上也可以对数据实现ITypedList并相应地公开属性。但是这需要花费很多功夫,而收益却不是很大。


0

使用纯 Linq 是不可能的!但可以通过重用旧数据集并使用 System.Data.DataSetExtensions 转换回 Linq。虽然不太优雅,但它能够工作。

// 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);

克隆元数据

System.Data.DataTable l_dt = l_ds.Tables[0].Clone();    

通过 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;

0
如果您正在使用MVVM模式,我认为这是更好的解决方案:
在您的ViewModel中创建ObservableCollection,它将绑定到DataGrid中的ItemSource:
public ObservableCollection<T> bindableCollection;

然后,从您的数据库中获取数据,例如:

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);

    }
}

最后一步,也是最重要的一步,创建一个函数,将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;
}

我认为这是MVVM的好方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接