Auto قم بتوليد الأعمدة باستخدام ObservableCollection <object>

أحاول ربط datagrid مجموعة من الكائنات حيث سيتم تغيير هذه الخاصية بالاعتماد على متطلبات/s.

في جهاز VM الخاص بي ، لدي هذا الموقع:

private ObservableCollection _productData;

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

وفي عرضي:


هل من الممكن إنشاء أعمدة استنادًا إلى "الكائن" الذي تم توفيره؟

مثلا:

ProductData = new ObservableCollection(SomethingThatReturnsClassAList());
0
في الواقع ، هم ليسوا ... ليس لديهم نفس الواجهة ...
وأضاف المؤلف Jack Frost, مصدر
حاولت البحث في ExpandoObject و DynamicObject لكنني غير متأكد من كيفية تنفيذها. فكرت في الحصول على كافة الخصائص بعد ProductData = جديد ObservableCollection <�كائن> (SomethingThatReturnsClassAList (& zwnj؛))؛ بواسطة ProductDat [0] .GetType() لكنني لا أعرف ماذا أفعل بعد ذلك.
وأضاف المؤلف Jack Frost, مصدر
نعم ، لأنه بمجرد إنشاء المجموعة ، سيكون كل شيء كما هو. يمكن أن يكون SomethingThatReturnsClassAList() أيضا SomethingThatReturnsClassBList() وغيرها. لذلك ، سيكون كل شيء من نفس النوع بمجرد إرجاع الأسلوب قائمة ...
وأضاف المؤلف Jack Frost, مصدر
إجابة قصيرة ، لا يمكنك القيام بذلك باستخدام هذه الطريقة. راجع stackoverflow.com/questions/882214/data-binding-dynamic-data
وأضاف المؤلف Adam Vincent, مصدر
هل تريد إنشاء أعمدة استنادًا إلى نوع العنصر الأول في مجموعة المصدر؟
وأضاف المؤلف mm8, مصدر
إذا كانت جميع الكائنات الموجودة في هذه المجموعة من نفس الفئة دائمًا ، فيجب عليك استخدام فئة templated لتخزين المجموعة
وأضاف المؤلف Krzysztof Skowronek, مصدر
ثم كيف تتخيل وجودهم في datagrid؟ هذا الكثير من الأعمدة والخلايا الفارغة
وأضاف المؤلف Krzysztof Skowronek, مصدر

1 إجابة

الطريقة DataGrid Auto Generates Columns قوية جدًا ، ولكنها للأسف لا تعمل بالطريقة التي تريدها. بطريقة أو بأخرى ، تحتاج إلى معرفة ما هي الأعمدة التي تتوقعها. إذا قمت بإعطائه نوع كائن ، فإنه لن ينعكس على أي نوع يتم تعيينه إلى "الكائن" ، سوف ينعكس فقط على "System.object" ، والتي سوف تقوم بربطك 0 الأعمدة التي تم إنشاؤها تلقائيًا. أنا لست ذكية بما فيه الكفاية لشرح هذه الكارثة كاملة. أريد فقط أن أقفز إلى الحل الذي توصلت إليه ، والذي يجب أن يعمل بشكل جيد لأغراضك.

أنا فعلا فاجأت نفسي من خلال تقديم مثال عملي. هناك بعض الأشياء التي تحدث هنا والتي تحتاج إلى بعض "التقسيم".

تركت XAML وحده ، ما زال


However, in the ViewModel, I've made a decision that hopefully you can work with, to changed ProducData from an ObservableCollection<> to a DataTable. The binding will still work the same, and the UI will update appropriately.

كان هدفك الأصلي هو جعل ObservableCollection من نوع الكائن لجعل الأشياء أكثر عمومية ، ولكن هنا قمت بتطبيق Factory Pattern لإظهار طريقة لإنشاء أنواع متعددة دون جعل الأمور معقدة للغاية. يمكنك أخذه أو تركه لما يستحق.

ViewModel (أنا أستخدم Prism boilerplate ، استبدل BindableBase مع تطبيقك INotifyPropertyChanged


public class ViewAViewModel : BindableBase
{
    private DataTable _productData;
    private IDataFactory_dataFactory;

    public ViewAViewModel(IDataFactorydataFactory)
    {
        _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()
            {
                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()
            {
                new BarData() {Id = 1, PenPointSize = 0.7m, InkColor = "Blue"},
                new BarData() {Id = 2, PenPointSize = 0.5m, InkColor = "Red"}
            }.ToDataTable();
        }

        return new List().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 </​​code> بـ BarData </​​code> ، أو أي نوع مشتق من ProductData </​​code>

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

Last but not least, I found this little gem somewhere on SO (If I find it again, will credit the author) This is an extension method to generate the DataTable from an IList with column names based on the properties of T.

public static class DataFactoryExtensions
{
    public static DataTable ToDataTable(this IList 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 على تحديث واجهة المستخدم.

تحديث استنادًا إلى إضافتك إلى المشاركة

To implement this using a method that returns a list like your example; 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().ToDataTable();
    }
}
0
وأضاف
مرحبا ادم! هذا يبدو رائعا! على الرغم من أنني تمكنت من الحصول عليها عن طريق إضافة OnPropertyChanged على ProductData. لم يتم اختباره بعد على كيفية حفظ التغييرات على البيانات ، إذا كان ذلك غير ممكن ، سأحاول بالتأكيد هذا واحد! في الوقت الحالي ، سوف أشاركه. شكر!!
وأضاف المؤلف Jack Frost, مصدر