【问题标题】:How do you bind Dapper query result to WPF DataGrid如何将 Dapper 查询结果绑定到 WPF DataGrid
【发布时间】:2012-11-08 23:01:17
【问题描述】:

这是我的代码。它会生成具有正确行数的绑定网格,但是 单元格是空的

XAML

<DataGrid
  Name="grid" 
  ItemsSource="{Binding}"
  AutoGenerateColumns="True" />

后面的代码

grid.DataContext = cn.Query("select * from SomeTable");

【问题讨论】:

  • 你试过给它一个类型吗? cn.Query&lt;SomeType&gt;(...);
  • 我需要保持通用,因为网格根据用户输入绑定到不同的类型。

标签: c# .net wpf data-binding dapper


【解决方案1】:

docs,那里的语法——cn.Query("sql")——返回动态类型对象的列表(IEnumerable&lt;dynamic&gt;)。这不适用于 DataGrid 自动列,它会寻找具体成员来生成其列。我建议为 SomeTable 创建一个简单的实体类来映射属性,然后使用cn.Query&lt;SomeTableEntity&gt;("select * from SomeTable");

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      如果您使用 Query 的非通用版本,它会返回数据的动态表示。动态 API 不适用于大多数 UI 数据绑定。最好使用通用的Query&lt;T&gt; API 将数据加载到已定义属性的类型中。

      完全推送中,理论上也可以在数据上实现 ITypedList 并相应地公开属性。但这是相当多的工作,却没有多少收获。

      【讨论】:

        【解决方案4】:

        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;
        

        【讨论】:

          【解决方案5】:

          如果您使用的是 MVVM 模式,我认为这是更好的解决方案:

          在您的 ViewModel 中创建 ObservableCollecion,它将绑定到 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 的好方法。

          【讨论】:

            猜你喜欢
            • 2017-10-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-08-23
            • 2014-10-23
            相关资源
            最近更新 更多