ここに私のコードです。正しい行数を持つ連結グリッドを生成しますが、セルは空です。Dapperクエリ結果をWPF DataGridにバインドするには
XAML
<DataGrid
Name="grid"
ItemsSource="{Binding}"
AutoGenerateColumns="True" />
docsから
grid.DataContext = cn.Query("select * from SomeTable");
ここに私のコードです。正しい行数を持つ連結グリッドを生成しますが、セルは空です。Dapperクエリ結果をWPF DataGridにバインドするには
XAML
<DataGrid
Name="grid"
ItemsSource="{Binding}"
AutoGenerateColumns="True" />
docsから
grid.DataContext = cn.Query("select * from SomeTable");
の背後にあるコード、そこにあなたの構文 - cn.Query("sql")
は - 動的な型付けされたオブジェクト(IEnumerable<dynamic>
)のリストを返します。これは、列を生成する具体的なメンバーを探すDataGridの自動列に対しては機能しません。プロパティをマップしてcn.Query<SomeTableEntity>("select * from SomeTable");
を使用するために、SomeTableの単純なエンティティクラスを作成することをお勧めします。
クエリの非汎用バージョンを使用すると、データの動的表現が返されます。動的APIは、ほとんどのUIデータバインディングには適していません。プロパティを定義した型にデータをロードするには、汎用のQuery<T>
APIを使用することが望ましいでしょう。
完全プッシュでは、データにITypedListを実装し、それに応じてプロパティを公開することも理論的に可能です。しかしそれほど多くの利益のためにはかなり多くの仕事があります。
私は答えがそうだと思います:それは不可能です。ここにはハックのある回避策があります。
...
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;
}
私はこれがあまりにもハッキーではない、とかなり良い解決策だと思います。 –
ありがとう、私はこの同じ問題を抱えていた、これはトリックでした。 – Tofystedeth
それは純粋LINQのでは不可能です! OLDデータセットを再利用し、System.Data.DataSetExtensionsを使用してlinqに変換することができます。 (エレガントしかし、それは動作しません)あなたはMVVMパターンを使用している場合は、私はこれがあると思いSystem.Data.DataSetExtensions
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;
経由
// 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メタデータバックLINQに
System.Data.DataTable l_dt = l_ds.Tables[0].Clone();
をより良い解決策:
ViewModelでObservableCollecionを作成します。これはにバインドされます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);
}
}
最終段階、そして最も重要な、あなたのObservableCollectionにIEnumerableをを追加しますこれは、関数を作成します。
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の良いアプローチだと思います。
タイプを指定してみましたか? 'cn.Query(...);' –
mxmissile
グリッドはユーザの入力に基づいて異なるタイプにバインドされているので、汎用性を保つ必要があります。 –