2009-05-19 3 views
5

Voglio legare le colonne della mia WPF DataGrid per alcuni oggetti in un dizionario come questo:Come posso associare Wpf DataGridColumn a un oggetto?

Binding Path = Objects [i]

dove Objects è il mio dizionario di oggetti, in modo che ogni cella rappresenterà un elemento Object. Come lo posso fare?

Suppongo di dover creare un modello per la mia cella, cosa che ho fatto, ma come ottenere il risultato del binding di colonna nel modello? So che per impostazione predefinita il contenuto di un DataGridCell è un TextBlock e la sua proprietà Text viene impostata attraverso il risultato del binding di colonne, ma se quel risultato è un oggetto, suppongo di dover creare un ContentTemplate. Come faccio a farlo, poiché le cose che ho provato non mostrano nulla.

Qui è quello che ho provato:

<Style x:Key="CellStyle" TargetType="{x:Type dg:DataGridCell}"> 
    <Setter Property="Template"> ---it should realy be ContentTemplate? 
     <Setter.Value> 
     <ControlTemplate> 
      <controls:DataGridCellControl CurrentObject="{Binding }"/> -- I would expect to get the object like this for this column path : Path=Objects[i] but is not working 
     </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
    </Style> 

Così, per farmi completamente chiaro, voglio entrare in CurrentObject proprietà della mia DataGridCellControl dell'oggetto corrente che dovrebbe comportare se ho impostato la colonna vincolante nel mio griglia di dati come questa Path = Objects [i].

Grazie per qualsiasi suggerimento,

John.

risposta

0

Prova questo:

<ListView x:Name="listViewUsers" SelectionMode="Single" 
           ItemsSource="{Binding ElementName=window1, Path=Users, Mode=TwoWay}" MouseDoubleClick="listViewUsers_MouseDoubleClick"> 
         <ListView.View> 
          <GridView x:Name="gridViewUsers" AllowsColumnReorder="False"> 
           <GridViewColumn> 
            <GridViewColumn.CellTemplate> 
             <DataTemplate> 
              <Image Source="{Binding Path=IsAdministrator, Converter={StaticResource boolToImage}, ConverterParameter='Images/admin18.gif|Images/user18.gif'}" /> 
             </DataTemplate> 
            </GridViewColumn.CellTemplate> 
           </GridViewColumn> 
           <GridViewColumn Header="User Name" DisplayMemberBinding="{Binding Path=UserName}" Width="140" /> 
           <GridViewColumn Header="Full Name" DisplayMemberBinding="{Binding Path=FullName}" Width="140" /> 
           <GridViewColumn Header="Phone Number" DisplayMemberBinding="{Binding Path=PhoneNumber}" Width="110" /> 
           <GridViewColumn Header="Access Type" DisplayMemberBinding="{Binding Path=AccessType}" Width="110"> 
           </GridViewColumn> 
           <GridViewColumn> 
            <GridViewColumn.CellTemplate> 
             <DataTemplate> 
              <Image Cursor="Hand" ToolTip="Delete User" Stretch="None" Source="Images/trash12.gif" MouseUp="DeleteUser" /> 
             </DataTemplate> 
            </GridViewColumn.CellTemplate> 
           </GridViewColumn> 
          </GridView> 
         </ListView.View> 
        </ListView> 

Dove in ItemsSource = "{Binding ElementName = Window1, Path = Users, Mode = TwoWay}"

  • ElementName è il nome della finestra in XAML (aggiungi x: Name = "window1" al tag Window come con qualsiasi altro ontrol

  • Gli utenti sono una lista, dovrebbero funzionare allo stesso modo con Dizionario

  • Mode = TwoWay significa che se la griglia viene modificato, l'elenco otterrà modificato troppo, e viceversa (binding bidirezionale)

EDIT:

Prova questo:

XAML:

<ListView x:Name="listViewTest" ItemsSource="{Binding}"> 
<ListView.View> 
    <GridView x:Name="gridViewTest"> 

    </GridView> 
</ListView.View> 
</ListView> 

C#:

0.123.516,410617 millions
public class TheClass 
    { 
     public int Col1, Col2, Col3; 
     public Dictionary<int, OtherColumns> otherColumns = new Dictionary<int,OtherColumns>(); 
    } 

    public class OtherColumns 
    { 
     public string ColumnName; 
     public int Value; 
    } 

E chiamare questo metodo in Window_Loaded:

private void PopulateListView() 
     { 
      TheClass c = new TheClass(); 

      c.Col1 = 10; 
      c.Col2 = 20; 
      c.Col3 = 30; 


      c.otherColumns.Add(0, new OtherColumns() { ColumnName = "Col4", Value = 40 }); 
      c.otherColumns.Add(1, new OtherColumns() { ColumnName = "Col5", Value = 50 }); 
      c.otherColumns.Add(3, new OtherColumns() { ColumnName = "Col6", Value = 60 }); 

      DataTable table = new DataTable(); 

// adding regular columns 
      table.Columns.Add("Col1", typeof(int)); 
      table.Columns.Add("Col2", typeof(int)); 
      table.Columns.Add("Col3", typeof(int)); 

// adding dynamic columns 
      foreach (KeyValuePair<int, OtherColumns> pair in c.otherColumns) 
      { 
       table.Columns.Add(pair.Value.ColumnName, typeof(int)); 
      } 

      DataRow row = table.NewRow(); 

// adding regular column values to the DataTable 
      row["Col1"] = c.Col1; 
      row["Col2"] = c.Col2; 
      row["Col3"] = c.Col3; 

// adding dynamic column values to the DataTable 
      foreach (KeyValuePair<int, OtherColumns> pair in c.otherColumns) 
      { 
       row[pair.Value.ColumnName] = pair.Value.Value; 
      } 

      table.Rows.Add(row); 

      // Start binding the table. 
      gridViewTest.Columns.Clear(); 

      System.Windows.Controls.GridViewColumn gvc; 
      Binding binding; 

      foreach (DataColumn column in table.Columns) 
      { 
       gvc = new System.Windows.Controls.GridViewColumn(); 
       binding = new System.Windows.Data.Binding(); 
       binding.Path = new PropertyPath(column.ColumnName); 
       binding.Mode = BindingMode.OneWay; 
       gvc.Header = column.Caption; 
       gvc.DisplayMemberBinding = binding; 
       gridViewTest.Columns.Add(gvc); 
      } 

      listViewTest.DataContext = table; 
     } 

Non sto dicendo che è la soluzione migliore, ma potrebbe aiutare. Fammi sapere.

+0

Grazie Carlo per il replay, È un modo simile di farlo con WPF DataGrid? Cordiali saluti, John –

+0

Oh, e qualcos'altro, creo dinamicamente le mie colonne, quindi avrò bisogno di un CellTemplate globale applicabile a tutte le celle. Qualche idea su come posso farcela? –

+0

Forse dovresti semplicemente creare la tabella dati fuori dal dizionario e associare il datagrid a tale datatable, pensi che questo ti potrebbe aiutare? – Carlo

0

Ho creato alcune classi di supporto per utilizzare DataGrid come una sorta di DataTable. In altre parole, volevo la formattazione, l'ordinamento e l'aspetto lucido di DataGrid senza dover pre-fab di alcune classi in anticipo. Il motivo principale per cui volevo questo era per una suite di test, volevo essere in grado di creare un numero arbitrario di colonne e in fase di esecuzione.Ecco quello che ho ottenuto

public class DataRow 
{ 
    internal List<object> Items = new List<object>(); 

    public object this[string value] 
    { 
     get { return Items[Convert.ToInt32(value)]; } 
    } 

    public string GetString(int index) 
    { 
     return Items[index].ToString(); 
    } 

    public object GetObject(int index) 
    { 
     return Items[index]; 
    } 

    public DataRow(params object[] values) 
    { 
     if (values == null || values.Length < 1) 
      throw new Exception("You must pass in some values"); 

     Items.AddRange(values);    
    } 
} 

public class GridConstructor 
{ 
    public List<DataRow> Rows = new List<DataRow>(); 
    private DataRow headers; 

    public GridConstructor(DataRow head) 
    { 
     headers = head; 
    } 

    public void BuildInto(DataGrid grid) 
    { 
     grid.AutoGenerateColumns = false; 
     grid.Columns.Clear(); 
     int totalCols = 0; 

     Type headType = headers.GetType(); 

     for (int i = 0; i < headers.Items.Count; i++) 
     { 
      grid.Columns.Add(GetCol(headers.GetString(i), String.Concat("[", i.ToString(),"]"))); 
      totalCols++; 
     }      

     int finalWidth = totalCols * (int)grid.ColumnWidth.Value + 15; 
     grid.Width = finalWidth; 

     grid.ItemsSource = Rows; 
    } 

    private DataGridTextColumn GetCol(string header, string binding) 
    { 
     DataGridTextColumn col = new DataGridTextColumn(); 
     col.IsReadOnly = true;    
     col.Header = header; 
     col.Binding = new Binding(binding); 

     return col; 
    } 

    public DataGrid Create(int colSize) 
    { 
     DataGrid grid = new DataGrid(); 
     grid.ColumnWidth = colSize; 
     grid.CanUserAddRows = false; 
     grid.AlternationCount = 2; 
     BuildInto(grid); 
     return grid; 
    } 
} 

Mettendo questo insieme, questo è un uso del campione:

void SimpleTest_Loaded(object sender, RoutedEventArgs e) 
    {    
     DataRow headers = new DataRow("Level", "Weapon Type", "vs None", "vs Leather", "vs Studded", "vs Brigandine");    
     GridConstructor gridConstructor = new GridConstructor(headers);    

     var weaponType = "Slash"; 
     for (int level = 1; level < 10; level++) 
     { 
      int damage = DiceCup.RollMulti(8, level); 
      int damCloth = damage - DiceCup.RollMulti(2, level); 
      int damLeather = damage - DiceCup.RollMulti(3, level); 
      int damStudded = damage - DiceCup.RollMulti(4, level); 
      int damBrigandine = damage - DiceCup.RollMulti(5, level); 

      DataRow row = new DataRow(level, weaponType, damage, damCloth, damLeather, damStudded, damBrigandine); 
      gridConstructor.Rows.Add(row);     
     } 

     //Create the grid. 
     var grid = gridConstructor.Create(100); 


     //Create a chart. 
     Chart chart = new Chart(); 
     chart.Height = 200; 
     chart.LegendTitle = "Legend"; 
     chart.Title = "Slash vs Armor Types";      
     chart.DataContext = gridConstructor.Rows;    


     //Create our series, or lines. 
     LineSeries slashVsNone = new LineSeries(); 
     slashVsNone.Title = "vs None"; 
     slashVsNone.DependentValueBinding = new Binding("[2]"); 
     slashVsNone.IndependentValueBinding = new Binding("[0]"); 
     slashVsNone.ItemsSource = gridConstructor.Rows;    
     chart.Series.Add(slashVsNone); 

     //Presentation is a stackpanel on the page.    
     presentation.Children.Add(grid); 
     presentation.Children.Add(chart);    
    } 

E l'output:

alt text http://quiteabnormal.com/images/codeSample.jpg

Si prega di notare che la colorazione griglia è da universale stili impostati sulla pagina. Se usi il metodo GridConstructor.BuildInto() puoi specificare una griglia che hai pre-formattato in Blend o somesuch.

Solo una cosa, GridConstructor fa alcune supposizioni sulle impostazioni iniziali della colonna. Puoi modificare la classe per renderla più personalizzabile, se preferisci, ma questo è ciò di cui avevo bisogno, quindi volevo essere in grado di farlo senza problemi.