Автоматически генерировать столбцы с ObservableCollection <object> - PullRequest
0 голосов
/ 25 апреля 2018

Я пытаюсь привязать к сетке данных коллекцию объектов, где это свойство будет меняться в зависимости от требований / с.

В моей виртуальной машине у меня есть это свойство:

private ObservableCollection<object> _productData;

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

А на мой взгляд:

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

Можно ли автоматически генерировать столбцы на основе предоставленного "объекта"?

Пример:

ProductData = new ObservableCollection<object>(SomethingThatReturnsClassAList());

1 Ответ

0 голосов
/ 26 апреля 2018

Способ 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();
    }
}
...