2009-12-07 2 views
3

Existe-t-il un moyen de spécifier des colonnes DataGrid de manière déclarative à l'aide d'une liaison? (Et pour définir les propriétés des colonnes à l'aide de cette liaison?) Idéalement, j'aurais une liste d'objets (par exemple, des lignes) contenant des données vers ItemsSource et une de leurs propriétés serait un dictionnaire (ou une liste d'objets d'une certaine classe ou peu importe) avec un nom et une valeur. Je voudrais que le DataGrid crée automatiquement ces colonnes supplémentaires sans avoir de code derrière. Est-ce que c'est possible? Ou comment voulez-vous contourner cela?Spécification et affichage des colonnes d'un DataGrid dans WPF de manière déclarative à l'aide d'une liaison?

Le tableau contenant les valeurs supplémentaires peut changer dans le temps mais serait le même pour tous les éléments de la liste.

Il serait possible (et propre) de fournir au DataGrid une liste différente pour en créer les colonnes. Mais pour que je besoin de quelque chose comme ColumnsSource ou quelque chose ...

La seule chose que je pouvais venir avec la création a été une sous-classe de la DataGrid ...

Toutes les idées?

EDIT: Le point réalise cela sans aucun code derrière ...

Répondre

1

Au risque de paraître controversé ...

Je pense que c'est un exemple où la vue n'a vraiment besoin d'un peu d'un code « boost », et la ligne directrice « non code-behind » peut être mis d'un côté - tant que vous vous souvenez de garder vos préoccupations séparées.Par le passé, j'ai créé dynamiquement des contrôles DataGrid en saisissant les données pertinentes du ViewModel et en écrivant une méthode 'BuildDataGrid', similaire à la réponse de Partial, dans le code-behind. Je crois que cela est justifié, parce que le code visait uniquement à compléter la vue, et je n'ai pas mélangé les préoccupations en mettant en œuvre des règles métier - il suffit de rassembler les colonnes et de créer les liaisons de colonnes, selon le cas.

Mais s'il est plus important de garder le code-behind propre, alors je recommanderais votre idée originale de créer un contrôle utilisateur et d'utiliser des DP pour «sous-classer» le contrôle.

+0

Je suppose que c'est la seule façon, je vais garder la question ouverte pendant un moment, peut-être que quelqu'un va trouver quelque chose, sinon accepter cela. Juste un sidenote: La grille est capable de générer des colonnes supplémentaires automatiquement (propriété AutoGenerateColumns). Mais cela ne fonctionnerait pas ou des listes bien sûr. La question est, est-ce que tout ce qui est contraignant fonctionnerait avec les classes qui parlent? Ou mieux - utilise-t-il la réflexion pour générer les colonnes supplémentaires? Je pourrais créer une classe à la volée pour les données, mais cela peut être encore pire en termes de facilité de maintenance et de lisibilité ... –

+0

Je sais que ce n'est pas idéal ... MV-VM a tellement grandi depuis que ce contrôle a été créé à l'origine Je suis sûr qu'il y aura une version à un moment donné dans le futur qui expose Columns comme un DP. Jusque-là, je suppose que nous devons choisir la solution la plus pragmatique .... acclamations, – kiwipom

+1

Je sais que c'est vieux, mais j'ai remarqué que, selon le système d'exploitation (et peut-être si .Net 4.5 est installé ou non, même en ciblant .Net 4.0), le réglage AutoGenerateColumns = true utilise en fait la réflexion avec Windows 7. Ainsi, vous pouvez renvoyer un IEnumerable (ou dynamic) (qui implémente List, implémente, d'ailleurs) et faire que DataGrid génère les colonnes, même à partir d'un type anonyme. Cependant, si vous pensez que cela fonctionnera sous XP, vous devrez, d'une certaine manière, corriger votre propre code pour générer les colonnes dynamiquement. – William

1

Dans votre XAML lier votre DataGrid à un ObservableCollection d'objets d'une certaine classe qui a des propriétés.

XAML:

<WpfToolkit:DataGrid 
     x:Name="MyDataGrid" 
     ItemsSource="{Binding Path=Collection}" 
     HorizontalScrollBarVisibility="Hidden" SelectionMode="Extended" 
     CanUserAddRows="False" CanUserDeleteRows="False" 
     CanUserResizeRows="False" CanUserSortColumns="False" 
     AutoGenerateColumns="False" 
     RowHeaderWidth="25" RowHeight="25"/> 

Ensuite, vous pouvez créer vos colonnes programme en C#/VBA et lier chaque colonne individuelle à une propriété de la classe à laquelle l'ObservableCollection contient des objets de celui-ci. En ajoutant des objets de la classe, vous ajouterez des lignes à la grille de données. En d'autres termes, chaque objet de la classe dans ObservableCollection sera une ligne et les propriétés de la classe seront les colonnes.

Voici un exemple de la façon dont vous pouvez lier vos colonnes ... programme C#:

ObservableCollection<IData> datagridData = new ObservableCollection<IData>(); 
Binding items = new Binding(); 
PropertyPath path = new PropertyPath("Name"); // 'Name' is actually the name of the variable representing the property 
items.Path = path; 

MyDataGrid.Columns.Add(new DataGridTextColumn() 
{ 
    Header = "Names", 
    Width = 275, 
    Binding = items 
}); 
//repeat the creation of columns 
//... 
//- Add some objects to the ObservableCollection 
//- Then bind the ItemsSource of the datagrid to the ObservableCollection 
datagridData .Add(new Data("Bob", string.Empty)); 
MyDataGrid.DataContext = new DataModel{ MyData = datagridData }; 

* Edit: Désolé à ce sujet! Voici comment vous pouvez obtenir la même chose tout en XAML:

<WpfToolkit:DataGrid 
     x:Name="MyDataGrid" 
     ItemsSource="{Binding Path=Collection}" 
     HorizontalScrollBarVisibility="Hidden" SelectionMode="Extended" 
     CanUserAddRows="False" CanUserDeleteRows="False" 
     CanUserResizeRows="False" CanUserSortColumns="False" 
     AutoGenerateColumns="False" 
     RowHeaderWidth="25" RowHeight="25"> 

      <WpfToolkit:DataGridTextColumn 
         Header="Names" Width="2*" 
         Binding="{Binding Path=Name}"/> 
      <WpfToolkit:DataGridTextColumn 
         Header="Names" Width="2*" 
         Binding="{Binding Path=Age}"/> 

     </WpfToolkit:DataGrid.Columns> 
</WpfToolkit:DataGrid> 

Edit 2: Voici ce que le code de la ObservableCollection et la classe peut ressembler en C#:

public class DataModel 
    { 
     public ObservableCollection<IData> MyData{ get; set; } 
    } 

public interface IData 
    { 
     string Name{ get; set; } 
     string Age{ get; set; } 
    } 

public class Data : IData 
    { 
     public Data(string name, string age) 
     { 
      Name= name; 
      Age= age; 
     } 

     public string Name{ get; set; } 
     public string Age{ get; set; } 
    } 
+0

Ouais c'est presque parfait avec juste une minuscule exception ... que je ne voulais pas l'écrire par programme. C'est pourquoi il y a "déclarative" dans le titre. Je vais mettre à jour la question pour la rendre plus claire. Mais merci pour votre contribution! –

+0

Encore une fois, j'ai peur. Les colonnes de cet exemple sont codées en dur, pas générées par une liaison. (Le contenu des colonnes est lié à une propriété, c'est bien, mais les colonnes elles-mêmes ne le sont pas ...) En outre, la grille peut avoir des colonnes codées en dur mais le reste des colonnes doit être généré à partir d'une liste. (L'IData aurait une autre propriété, disons un Disctionary et les colonnes supplémentaires seraient les clés de ce disco.) Et je ne pense pas que ce soit possible, donc je suis en train de chercher un moyen de le contourner.) –

0

je pense que vous avoir à sous-classer la grille. Les colonnes ne sont pas une propriété pouvant être liée. Si vous ne pouvez pas lier, vous ne pouvez pas jouer avec le xaml de manière dynamique.

En ce qui concerne l'utilisation des éléments pour créer les colonnes, est-ce que cela signifie que s'il n'y avait pas d'éléments dans la grille, il n'y aurait pas de colonnes?

Si vous possédez une sous-classe de la grille contenant une propriété columns à laquelle vous pouvez vous lier, l'emplacement de modification dynamique des colonnes se trouve dans votre modèle de vue.

+0

Vous pouvez lier Les colonnes! – Partial

+1

ouais ... comment? c'est un public ObservableCollection Columns {get; } propriété. Si vous ne pouvez pas le définir, comment pouvez-vous lier? –

+0

id aiment voir un exemple si vous en avez un ... sinon id comme un upvote –

Questions connexes