动态生成其他DataGrid列WPF

时间:2017-05-23 19:21:47

标签: c# wpf xaml datagrid

我有一个带有2个静态列(名称和年龄)的DataGrid。我希望能够动态地向我的DataGrid添加可变数量的附加列,因为我事先不知道将有多少额外的列。我还希望结果DataGrid可以编辑。

我创建了一个'MyData'类,我想用它作为我的DataGrid DataContext(作为MyData Objects的ObservableCollection)。

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

}

我要添加的动态列标题是'Country1','Country2',...,'CountryN'。这些列中的每个条目都是这些国家的城市。

我有一个方法,将countryNames列表和我的DataGrid作为参数。为了便于说明,我正在传递:

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

我正在打电话:

AddNewColumnsAndData(CountryNames, this.dgr);

请参阅下面的AddNewColumnsAndData()方法的实现:

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;

    }

我的DataGrid的XAML,带有两个静态列'Name'和'Age':

<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'的异常:双向绑定需要Path或XPath。” 这告诉我,我需要改变我设置绑定属性的方式。

当我注释掉'bdg.Mode = BindingMode.TwoWay;'时行,该程序运行正常,但是,我无法编辑DataGrid,而不是国家标题下面的城市名称,它被粘贴MyNameSpace.MyData。

我的问题是:如何正确设置绑定,以便单元格正确显示城市名称,以及如何使我生成的DataGrid可编辑?

1 个答案:

答案 0 :(得分: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}

这是有效的,因为Binding继承自MarkupExtension。您可以编写自己的MarkupExtension子类。例如,用强类型常量参数编写值转换器是一种非常方便的方法。

您可以使用默认构造函数,并单独设置Path

{Binding Path=NameCol}

这就是你不能这样做的原因:

{Binding Mode=TwoWay, NameCol}

...因为未命名的“参数”和命名的“参数”是不同的。首先是构造函数参数,然后是属性初始化(如果有)。

这样做相同,但随后设置了一些属性:

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

这是一个有趣的语法。