Способ 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
.Привязка все равно будет работать так же, и пользовательский интерфейс будет обновляться соответствующим образом.
Первоначально вы хотели сделать ObservableCollection
типа object
, чтобы сделать вещи более общими, но здесь я реализовал Factory Pattern
, чтобы показать способ создания нескольких types
без усложнения.Вы можете взять его или оставить его таким, какой он стоит.
ViewModel (я использую шаблон Prism, замените BindableBase
на реализацию INotifyPropertyChanged
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));
}
}
DataFactory
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
public void LoadFooData()
{
ProductData = _dataFactory.Create(typeof(FooData));
}
И последнее, но не менее важное: я нашел этот маленький драгоценный камень где-то на SO (если я найду его снова, я буду благодарен автору) Это метод расширения для генерации 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
обновит ваш пользовательский интерфейс.
Обновление на основе вашего добавления вpost
Чтобы реализовать это с помощью метода, который возвращает список, как ваш пример; SomethingThatReturnsClassAList()
Просто обновите фабрику, как это. (Обратите внимание, как легко изменить ваш код, чтобы соответствовать новым требованиямкогда вы используете Factory Pattern
? =)
public class DataFactory : IDataFactory
{
public DataTable Create(Type t)
{
if (t == typeof(FooData))
{
return SomethingThatReturnsClassAList().ToDataTable();
}
if (t == typeof(BarData))
{
return SomethingThatReturnsClassBList().ToDataTable();
}
return new List<dynamic>().ToDataTable();
}
}