使用ObservableCollection <object>自动生成列

时间:2018-04-25 10:55:27

标签: c# wpf mvvm observablecollection wpfdatagrid

我正在尝试将一个对象集合绑定到datagrid,因为此属性将根据需求进行更改。

在我的虚拟机中,我有这个属性:

undefined

在我的观点中:

element.first_name && element.first_name.toUpperCase().indexOf(event.toUpperCase())  !== -1

是否可以根据提供的“对象”自动生成列?

前:

private ObservableCollection<object> _productData;

        public ObservableCollection<object> ProductData
        {
            get { return _productData; }
            set { _productData = value; }
        }

1 个答案:

答案 0 :(得分:1)

DataGrid自动生成列的方式非常强大,但遗憾的是它无法按照您希望的方式运行。无论如何,您需要告诉它预期的列。如果你给它一个object类型,它不会反映分配给'对象'的类型,它只会反映'System.object',这会自动生成0列。我不够聪明地解释这整个崩溃。我只是想跳进我提出的解决方案,这应该适合你的目的。

我实际上通过一个有效的例子让自己感到惊讶。这里有一些事情需要一些“抨击”。

我单独离开你的XAML,它仍然是

<DataGrid CanUserAddRows="False"
              ItemsSource="{Binding ProductData, UpdateSourceTrigger=PropertyChanged}"
              IsReadOnly="True"
              AutoGenerateColumns="True"
              Margin="0 2 0 0" />

但是,在ViewModel中,我已做出决定,希望您可以使用,将ProducDataObservableCollection<>更改为DataTable。绑定仍然可以正常工作,UI将适当更新。

您最初的目的是让ObservableCollection类型object更加通用,但在这里我已经实现了Factory Pattern来展示创建多个{{1}的方法没有让事情变得太复杂。你可以把它拿走或留下它的价值。

ViewModel(我正在使用Prism样板,将types替换为BindableBase的实现

INotifyPropertyChanged

DataFactory

public class ViewAViewModel : BindableBase
{
    private DataTable _productData;
    private IDataFactory _dataFactory;

    public ViewAViewModel(IDataFactory dataFactory)
    {
        _dataFactory = dataFactory;
    }

    public DataTable ProductData
    {
        get { return _productData; }
        set { _productData = value; OnPropertyChanged(); }
    }

    public void Load()
    {
        ProductData = _dataFactory.Create(typeof(FooData));
    }
}

基类和数据模型

public interface IDataFactory
{
    DataTable Create(Type t);
}

public class DataFactory : IDataFactory
{
    public DataTable Create(Type t)
    {

        if (t == typeof(FooData))
        {
            return new List<FooData>()
            {
                new FooData() {Id = 0, AlbumName = "Greatest Hits", IsPlatinum = true},
                new FooData() {Id = 1, AlbumName = "Worst Hits", IsPlatinum = false}
            }.ToDataTable();
        }

        if (t == typeof(BarData))
        {
            return new List<BarData>()
            {
                new BarData() {Id = 1, PenPointSize = 0.7m, InkColor = "Blue"},
                new BarData() {Id = 2, PenPointSize = 0.5m, InkColor = "Red"}
            }.ToDataTable();
        }

        return new List<dynamic>().ToDataTable();
    }
}

因此,对于使用情况,您可以将public abstract class ProductData { public int Id { get; set; } } public class FooData : ProductData { public string AlbumName { get; set; } public bool IsPlatinum { get; set; } } public class BarData : ProductData { public decimal PenPointSize { get; set; } public string InkColor { get; set; } } FooDataBarData

派生的任何类型进行交换
ProductData

最后但并非最不重要的是,我在SO上找到了这个小宝石(如果我再次找到它,将会归功于作者)这是一个生成public void LoadFooData() { ProductData = _dataFactory.Create(typeof(FooData)); } 的扩展方法  来自DataTable的列名基于IList<T>的属性。

T

在任何一种情况下,public static class DataFactoryExtensions { public static DataTable ToDataTable<T>(this IList<T> data) { PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T)); DataTable table = new DataTable(); foreach (PropertyDescriptor prop in properties) table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType); foreach (T item in data) { DataRow row = table.NewRow(); foreach (PropertyDescriptor prop in properties) row[prop.Name] = prop.GetValue(item) ?? DBNull.Value; table.Rows.Add(row); } return table; } } public void LoadBarData() { ProductData = _dataFactory.Create(typeof(BarData)); } 都会更新您的用户界面。

根据您对帖子的添加进行更新

使用返回类似示例的列表的方法来实现此目的; INPC

只需像这样更新工厂。 (请注意在使用SomethingThatReturnsClassAList()时更改代码以满足新要求是多么容易?=)

Factory Pattern