2012-11-08 18 views
7

Hier ist mein Code. Es erzeugt ein gebundenes Gitter mit der richtigen Anzahl von Zeilen, jedoch sind die Zellen leer.Wie binden Sie Dapper-Abfrageergebnis an WPF DataGrid

XAML

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

-Code hinter

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

Haben Sie versucht, ihm einen Typ zu geben? 'cn.Query (...);' – mxmissile

+0

Ich muss es generisch halten, da das Grid abhängig von Benutzereingaben an verschiedene Typen gebunden ist. –

Antwort

5

Vom docs, Ihre Syntax dort - cn.Query("sql") - gibt eine Liste der dynamischen typisierte Objekte (IEnumerable<dynamic>). Das funktioniert nicht für die DataGrid-Autospalten, die nach konkreten Mitgliedern suchen, um ihre Spalten zu generieren. Ich würde empfehlen, eine einfache Entitätsklasse für SomeTable zu erstellen, um die Eigenschaften zuzuordnen und dann cn.Query<SomeTableEntity>("select * from SomeTable"); zu verwenden.

3

Wenn Sie die nicht generische Version von Query verwenden, wird eine dynamische Darstellung der Daten zurückgegeben. Die dynamische API ist für die meisten UI-Datenbindungen nicht geeignet. Es wäre vorzuziehen, die allgemeine API Query<T> zu verwenden, um die Daten in Typen mit definierten Eigenschaften zu laden.

Bei einem vollständigen Push, wäre es theoretisch auch möglich, ITypedList auf den Daten zu implementieren und die Eigenschaften entsprechend offen legen. Aber das ist ziemlich viel Arbeit für nicht so viel Gewinn.

5

Also ich denke die Antwort ist: es ist nicht möglich. Hier ist eine hacky Problemumgehung.

 ... 
     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; 
    } 
+0

Ich würde sagen, das ist nicht so hacky, und eine ziemlich gute Lösung. –

+0

Danke, ich hatte das gleiche Problem und das hat den Trick gemacht. – Tofystedeth

0

Es ist nicht möglich, mit reinem Linq! Es ist möglich, OLD-Dataset erneut zu verwenden und mithilfe von System.Data.DataSetExtensions wieder in linq zu konvertieren. (Nicht elegant, aber es funktioniert)

// 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 Metadaten

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

zurück zu Linq über 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; 
0

Wenn Sie MVVM Muster verwenden, ich denke, das ist bessere Lösung:

Erstellen Sie ObservableCollecion in Ihrem ViewModel, das angebunden wirdin DataGrid:

public ObservableCollection<T> bindableCollection; 

Dann holen Daten aus Ihrer Datenbank, Beispiel:

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

    } 
} 

Die letzten Schritt, und die wichtigsten, create-Funktion, die auf Ihren ObservableCollection IEnumerable hinzufügen wird:

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

Ich denke, das ist ein guter Ansatz für MVVM.

Verwandte Themen