7

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

XAML

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

背后的代码

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

5 回答 5

5

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

于 2012-11-08T23:05:30.930 回答
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;
    }
于 2012-11-09T00:37:05.697 回答
3

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

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

于 2012-11-08T23:07:48.747 回答
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;
于 2013-02-07T18:04:59.487 回答
0

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

在您的 ViewModel 中创建 ObservableCollecion,它将绑定到ItemSourcein DataGrid

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-02-21T20:29:20.700 回答