我正在尝试将一个对象集合绑定到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; }
}
答案 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中,我已做出决定,希望您可以使用,将ProducData
从ObservableCollection<>
更改为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; }
}
与FooData
或BarData
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