2017-05-23 126 views
0

私は2つの静的列(名前と年齢)を持つDataGridを持っています。データグリッドに追加する列の数を動的に追加できるようにするには、あらかじめいくつの列が追加されているかわからないためです。また、結果のDataGridを編集可能にしたいと思います。追加のDataGrid列を動的に生成するWPF

DataGrid DataContext(MyDataオブジェクトのObservableCollection)に使用したいMyDataクラスを作成しました。

public class MyData 
{ 
    public string NameCol { get; set; } 
    public string AgeCol { get; set; } 
    public List<string> CitiesList { get; set; } 

} 

ダイナミック列のヘッダーは、 'Country1'、 'C​​ountry2'、...、 'CountryN'です。これらの列のそれぞれのエントリは、これらの国の都市です。

私は、引数としてcountryNamesのリストと自分のDataGridをとるメソッドを持っています。イラストために、私はに渡しています:

List<string> CountryNames = new List<string>() {"France", "Kenya", "Japan"}; 

と私は呼び出しています:

public void AddNewColumnsAndData(List<string> countryNames, DataGrid dgr) 
    { 
     foreach (string countryname in countryNames) 
     { 
      Binding bdg = new Binding(); //Not sure what appropriate argument should go in the Binding Constructor 
      bdg.NotifyOnTargetUpdated = true; 
      bdg.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; 
      bdg.Mode = BindingMode.TwoWay;//Not sure if there are other bdg Properties I should be setting 

      DataGridTextColumn newCityCol = new DataGridTextColumn(); 
      newCityCol.Header = countryname; 
      newCityCol.Binding = bdg; 

      dgr.Columns.Add(newCityCol); 
     }; 
     List<string> myCityList1 = new List<string>() {"Paris", "Nairobi", "Tokyo"}; 
     List<string> myCityList2 = new List<string>() { "Strasbourg", "Mombasa", "Kyoto" }; 
     MyData firstrow = new MyData 
          { 
           NameCol = "John", 
           AgeCol = "45", 
           CityColList = myCityList1 
          }; 
     MyData secondrow = new MyData 
     { 
      NameCol = "Mary", 
      AgeCol = "34", 
      CityColList = myCityList2 
     }; 

     ObservableCollection<MyData> datacollection = new ObservableCollection<MyData>(); 
     datacollection.Add(firstrow); 
     datacollection.Add(secondrow); 

     dgr.DataContext = datacollection; 

    } 

XAML私のDataGridの:

AddNewColumnsAndData(CountryNames, this.dgr); 

は以下AddNewColumnsAndData()メソッドの実装を参照してください。 2つの静的な列「名前」と「年齢」:

<DataGrid x:Name="dgr" ItemsSource="{Binding}" AutoGenerateColumns="False" CanUserAddRows="False"> 
        <DataGrid.Columns> 
         <DataGridTextColumn Header="Name" Binding="{Binding NameCol, NotifyOnTargetUpdated=True, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/> 
         <DataGridTextColumn Header="Age" Binding="{Binding AgeCol, NotifyOnTargetUpdated=True, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/> 
        </DataGrid.Columns> 
       </DataGrid> 

残念ながら、これはあまり効果がありません。私はこのエラーが発生しています: "タイプ 'System.InvalidOperationException'の例外:双方向バインディングは、パスまたはXPathが必要です。" これは、バインディングのプロパティを設定する方法を変更する必要があることを示しています。

「bdg.Mode = BindingMode.TwoWay;」とコメントアウトすると、プログラムは正常に動作しますが、DataGridを編集することはできません。また、Countryヘッダーの下にあるCity名の代わりに、MyNameSpace.MyDataが貼り付けられます。

私の質問は次のとおりです。セルに市の名前が正しく表示されるようにバインディングを適切に設定する方法と、結果として得られるDataGridを編集可能にする方法を教えてください。

答えて

0
int citiesListIndex = 0; 
foreach (string countryname in countryNames) 
{ 
    // This is the Path. You're binding to CitiesList[0] 
    // CitiesList[1], etc. 
    string propertyPath = $"CitiesList[{citiesListIndex}]"; 

    // Pass path to constructor. 
    Binding bdg = new Binding(propertyPath); 

    // No-op 
    //bdg.NotifyOnTargetUpdated = true; 

    // Is this a read-only column? If it's read-only, this is a no-op 
    bdg.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; 

    // Is this a read-only column? If it's read-only, this is a no-op 
    bdg.Mode = BindingMode.TwoWay; 

    DataGridTextColumn newCityCol = new DataGridTextColumn(); 
    newCityCol.Header = countryname; 
    newCityCol.Binding = bdg; 

    dgr.Columns.Add(newCityCol); 

    ++citiesListIndex; 
} 

ここがその理由です。ここで

はXAML

にバインド
Binding="{Binding NameCol, NotifyOnTargetUpdated=True, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/> 

NameColPath財産であるのです。 XAMLでは、これは一つのパラメータを持つBinding(String path)コンストラクタを呼び出します。

{Binding NameCol} 

BindingMarkupExtensionから継承するので、これは動作します。あなた自身のMarkupExtensionサブクラスを書くことができます。例えば、厳密に型付けされた定数パラメータを持つvalueconvertersを書くのは本当に便利な方法です。

あなたはデフォルトのコンストラクタを使用して、個別にPathを設定することができます:あなたがこれを行うことができない理由

{Binding Path=NameCol} 

これは、次のとおりです。

{Binding Mode=TwoWay, NameCol} 

を...理由は無名の "パラメータ" と名前付きの「パラメータ」は異なります。コンストラクタのパラメータが最初に来て、プロパティの初期化(もしあれば)が続く。

これは同じことを行いますが、その後いくつかのプロパティを設定します。

{Binding NameCol, NotifyOnTargetUpdated=True, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay} 

それは面白いな構文です。

+0

ありがとう@Ed Plukett。すべての列を編集可能(非読み取り専用)にする必要があります。質問、行をコメントアウトする理由 //bdg.NotifyOnTargetUpdated = true; ? – Nodame

+0

また、上記はほとんどの部分で機能します。私が持っている唯一の問題は、「動的に追加された」列のDataGridを編集すると、編集内容が表示されないようです。私が紛失しているかもしれないBindingプロパティはありますか? – Nodame

+0

@ Nodeここで、TargetUpdatedイベントを処理していますか? –

関連する問題