2011-05-12 4 views
1

J'ai besoin de lier certaines données à un DataGrid avec un nombre variable de colonnes. Je l'ai fait travailler en utilisant le code suivant:WPF: Comment rendre la liaison DataGrid avec des colonnes dynamiques modifiable?

int n = 0; 
foreach (string title in TitleList) 
{ 
    DataGridTextColumn col = new DataGridTextColumn(); 
    col.Header = title; 
    Binding binding = new Binding(string.Format("DataList[{0}]", n++)); 
    binding.Mode = BindingMode.TwoWay; 
    col.Binding = binding; 
    grid.Columns.Add(col); 
} 

où DataList est déclarée comme:

public ObservableCollection<double> DataList { get; set; } 

et titleList est déclarée comme:

public ObservableCollection<string> TitleList { get; set; } 

Le problème est que, même si je spécifié Liaison TwoWay, c'est vraiment unidirectionnel. Lorsque je clique sur une cellule pour essayer de modifier, j'ai une exception "'EditItem' n'est pas autorisé pour cette vue". Ai-je manqué quelque chose dans l'expression de liaison?

P.S. J'ai trouvé un article de Deborah "Populating a DataGrid with Dynamic Columns in a Silverlight Application using MVVM". Cependant, j'ai eu du mal à le faire fonctionner pour mon cas (en particulier, je ne peux pas faire fonctionner la liaison d'en-tête). Même si cela a fonctionné, je suis toujours confronté à des problèmes tels que des styles de cellule incohérents. C'est pourquoi je me demande si je pourrais faire fonctionner mon code ci-dessus - avec un petit tweak?

EDIT: J'ai trouvé un autre message qui peut être lié à mon problème: Implicit Two Way binding. Il semble si vous liez à une liste de chaîne à une zone de texte en utilisant

<TextBox Text="{Binding}"/> 

Vous obtiendrez une erreur comme « deux voies de liaison nécessite le chemin ou XPath ». Mais le problème peut être facilement résolu en utilisant

<TextBox Text="{Binding Path=DataContext, RelativeSource={RelativeSource Self}}"/> 

ou

<TextBox Text="{Binding .}"/> 

Quelqu'un peut-il me donner un indice si mon problème peut être résolu de la même manière?

+0

je modifier ma réponse le problème est votre type de collection double. – blindmeis

Répondre

2

Vous liez-vous à un indexeur? pouvez-vous nous montrer à quoi ressemble votre propriété DataList? J'ai fait la même chose il y a un certain temps avec une propriété indexée.

public SomeObjectWithIndexer DataList 
{get; set;} 


public class SomeObjectWithIndexer 
{ 
     public string this 
     { 
      get { ... } 
      set { ... }//<-- you need this one for TwoWay 
     } 
} 

EDIT: la raison pour laquelle vous ne pouvez pas éditer votre propriété, c'est que vous essayez d'éditer un "champ double". Une solution de contournement serait d'envelopper votre double dans une classe avec INotifyPropertyChanged.

public class DataListItem 
{ 
    public double MyValue { get; set;}//with OnPropertyChanged() and stuff 
} 

alors vous pouvez utiliser un

ObservableCollection<DataListItem> 

et vous pouvez modifier votre valeur.la question wether l'indice sont toujours le même séjour encore autour :)

Binding binding = new Binding(string.Format("DataList[{0}].MyValue", n++)); 

EDIT2: exemple de travail: juste pour montrer twoway travaille

public class DataItem 
{ 
    public string Name { get; set; } 
    public ObservableCollection<DataListItem> DataList { get; set; } 

    public DataItem() 
    { 
     this.DataList = new ObservableCollection<DataListItem>(); 
    } 
} 

Wrapper pour double:

public class DataListItem 
{ 
    private double myValue; 
    public double MyValue 
    { 
     get { return myValue; } 
     set { myValue = value; }//<-- set breakpoint here to see that edit is working 
    } 
} 

commande usager avec une grille de données

<UserControl x:Class="WpfStackoverflow.IndexCollectionDataGrid" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     mc:Ignorable="d" 
     d:DesignHeight="300" d:DesignWidth="300"> 
<DataGrid ItemsSource="{Binding MyList}" AutoGenerateColumns="False"> 
    <DataGrid.Columns> 
     <DataGridTextColumn Header="Name" Binding="{Binding Path=Name}" /> 
     <DataGridTextColumn Header="Index1" Binding="{Binding Path=DataList[0].MyValue, Mode=TwoWay}" /> 
     <DataGridTextColumn Header="Index2" Binding="{Binding Path=DataList[1].MyValue, Mode=TwoWay}" /> 
    </DataGrid.Columns> 
</DataGrid> 
</UserControl> 

.cs

public partial class IndexCollectionDataGrid : UserControl 
{ 
    public IndexCollectionDataGrid() 
    { 
     InitializeComponent(); 
     this.MyList = new ObservableCollection<DataItem>(); 

     var m1 = new DataItem() {Name = "test1"}; 
     m1.DataList.Add(new DataListItem() { MyValue = 10 }); 
     m1.DataList.Add(new DataListItem() { MyValue = 20 }); 

     var m2 = new DataItem() { Name = "test2" }; 
     m2.DataList.Add(new DataListItem() { MyValue = 100 }); 
     m2.DataList.Add(new DataListItem() { MyValue = 200 }); 

     this.MyList.Add(m1); 
     this.MyList.Add(m2); 

     this.DataContext = this; 
    } 

    public ObservableCollection<DataItem> MyList { get; set; } 
} 

j'espère que vous obtenez dans la bonne direction avec cet exemple.

+0

@blindmeis: Merci pour la réponse. Ma liste de données est déclarée comme ObservableCollection . – newman

+0

hmm est-ce que l'index d'une ObservableCollection est toujours le même? – blindmeis

+0

@blindmeis: J'ai essayé votre suggestion en convertissant le double en un objet avec INotifyChanged implemneted et j'ai eu la même erreur. Donc, je ne suis pas sûr si c'est un problème d'indexeur. – newman