Associate a complex object with a DataTable in C #

I have DataTablewith complex objects.

For instance,

class ComplexDataWrapper
{
    public string Name{ get; set; }

    public ComplexData Data{ get; set; }

    public ComplexDataWrapper(ComplexData data)
    {
        this.Data = data;
        this.Name = "Something";
    }

    public override string ToString()
    {
        return Name;
    }
}

And now I want to snap cells from DataTableto objects. ComplexDataWrapper So, I'm trying something like this:

...
var column = new DataColumn() { ColumnName = columnName, DataType = typeof(ComplexDataWrapper)};
row[column] = new ComplexDataWrapper(data);

But I want to bind to only one property, for example Name. And in gridview ( DataTableis the data source for this view) I want to change this property (Name).

var complexDataWrapper = row[column] as ComplexDataWrapper;

complexDataWrapper is always NULL.

I know that something is missing me.

So my questions are: how can I snap my cell DataTableto a complex object? Plus in the form of a grid. I want to edit only one property of a complex object.

Thank. I hope everything is clear.

+5
source share
2 answers

, : DataTable ? .

(, obj.Prop1.Prop2). , WinForms - (, control.DataBindings.Add(...)), list, DataGridView ,

, - ( ) , , PropertyDescriptor, , , . , , "" , .

"" , / , - , :

public class ChildPropertyDescriptor : PropertyDescriptor
{
    public static PropertyDescriptor Create(PropertyDescriptor sourceProperty, string childPropertyPath, string displayName = null)
    {
        var propertyNames = childPropertyPath.Split('.');
        var propertyPath = new PropertyDescriptor[1 + propertyNames.Length];
        propertyPath[0] = sourceProperty;
        for (int i = 0; i < propertyNames.Length; i++)
            propertyPath[i + 1] = propertyPath[i].GetChildProperties()[propertyNames[i]];
        return new ChildPropertyDescriptor(propertyPath, displayName);
    }
    private ChildPropertyDescriptor(PropertyDescriptor[] propertyPath, string displayName)
        : base(propertyPath[0].Name, null)
    {
        this.propertyPath = propertyPath;
        this.displayName = displayName;
    }
    private PropertyDescriptor[] propertyPath;
    private string displayName;
    private PropertyDescriptor RootProperty { get { return propertyPath[0]; } }
    private PropertyDescriptor ValueProperty { get { return propertyPath[propertyPath.Length - 1]; } }
    public override Type ComponentType { get { return RootProperty.ComponentType; } }
    public override bool IsReadOnly { get { return ValueProperty.IsReadOnly; } }
    public override Type PropertyType { get { return ValueProperty.PropertyType; } }
    public override bool CanResetValue(object component) { var target = GetTarget(component); return target != null && ValueProperty.CanResetValue(target); }
    public override object GetValue(object component) { var target = GetTarget(component); return target != null ? ValueProperty.GetValue(target) : null; }
    public override void ResetValue(object component) { ValueProperty.ResetValue(GetTarget(component)); }
    public override void SetValue(object component, object value) { ValueProperty.SetValue(GetTarget(component), value); }
    public override bool ShouldSerializeValue(object component) { var target = GetTarget(component); return target != null && ValueProperty.ShouldSerializeValue(target); }
    public override AttributeCollection Attributes { get { return ValueProperty.Attributes; } }
    public override string Category { get { return ValueProperty.Category; } }
    public override TypeConverter Converter { get { return ValueProperty.Converter; } }
    public override string Description { get { return ValueProperty.Description; } }
    public override bool IsBrowsable { get { return ValueProperty.IsBrowsable; } }
    public override bool IsLocalizable { get { return ValueProperty.IsLocalizable; } }
    public override string DisplayName { get { return displayName ?? RootProperty.DisplayName; } }
    public override object GetEditor(Type editorBaseType) { return ValueProperty.GetEditor(editorBaseType); }
    public override PropertyDescriptorCollection GetChildProperties(object instance, Attribute[] filter) { return ValueProperty.GetChildProperties(GetTarget(instance), filter); }
    public override bool SupportsChangeEvents { get { return ValueProperty.SupportsChangeEvents; } }
    public override void AddValueChanged(object component, EventHandler handler)
    {
        var target = GetTarget(component);
        if (target != null)
            ValueProperty.AddValueChanged(target, handler);
    }
    public override void RemoveValueChanged(object component, EventHandler handler)
    {
        var target = GetTarget(component);
        if (target != null)
            ValueProperty.RemoveValueChanged(target, handler);
    }
    private object GetTarget(object source)
    {
        var target = source;
        for (int i = 0; target != null && target != DBNull.Value && i < propertyPath.Length - 1; i++)
            target = propertyPath[i].GetValue(target);
        return target != DBNull.Value ? target : null;
    }
}

, , , , . , PropertyDescriptor , runtime ComponentType, PropertyType, GetValue SetValue ( ).

. . "", .

, , ITypedList:

, , , .

, "" . ? , . , ( ).

, , IList ( ), , ITypedList :

public static class ListDataView
{
    public static IList Create(object dataSource, string dataMember, Func<PropertyDescriptor, PropertyDescriptor> propertyMapper)
    {
        var source = (IList)ListBindingHelper.GetList(dataSource, dataMember);
        if (source == null) return null;
        if (source is IBindingListView) return new BindingListView((IBindingListView)source, propertyMapper);
        if (source is IBindingList) return new BindingList((IBindingList)source, propertyMapper);
        return new List(source, propertyMapper);
    }

    private class List : IList, ITypedList
    {
        private readonly IList source;
        private readonly Func<PropertyDescriptor, PropertyDescriptor> propertyMapper;
        public List(IList source, Func<PropertyDescriptor, PropertyDescriptor> propertyMapper) { this.source = source; this.propertyMapper = propertyMapper; }
        // IList
        public object this[int index] { get { return source[index]; } set { source[index] = value; } }
        public int Count { get { return source.Count; } }
        public bool IsFixedSize { get { return source.IsFixedSize; } }
        public bool IsReadOnly { get { return source.IsReadOnly; } }
        public bool IsSynchronized { get { return source.IsSynchronized; } }
        public object SyncRoot { get { return source.SyncRoot; } }
        public int Add(object value) { return source.Add(value); }
        public void Clear() { source.Clear(); }
        public bool Contains(object value) { return source.Contains(value); }
        public void CopyTo(Array array, int index) { source.CopyTo(array, index); }
        public IEnumerator GetEnumerator() { return source.GetEnumerator(); }
        public int IndexOf(object value) { return source.IndexOf(value); }
        public void Insert(int index, object value) { source.Insert(index, value); }
        public void Remove(object value) { source.Remove(value); }
        public void RemoveAt(int index) { source.RemoveAt(index); }
        // ITypedList
        public string GetListName(PropertyDescriptor[] listAccessors) { return ListBindingHelper.GetListName(source, listAccessors); }
        public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
        {
            var properties = ListBindingHelper.GetListItemProperties(source, listAccessors);
            if (propertyMapper != null)
                properties = new PropertyDescriptorCollection(properties.Cast<PropertyDescriptor>()
                    .Select(propertyMapper).Where(p => p != null).ToArray());
            return properties;
        }
    }

    private class BindingList : List, IBindingList
    {
        private IBindingList source;
        public BindingList(IBindingList source, Func<PropertyDescriptor, PropertyDescriptor> propertyMapper) : base(source, propertyMapper) { this.source = source; }
        private ListChangedEventHandler listChanged;
        public event ListChangedEventHandler ListChanged
        {
            add
            {
                var oldHandler = listChanged;
                if ((listChanged = oldHandler + value) != null && oldHandler == null)
                    source.ListChanged += OnListChanged;
            }
            remove
            {
                var oldHandler = listChanged;
                if ((listChanged = oldHandler - value) == null && oldHandler != null)
                    source.ListChanged -= OnListChanged;
            }
        }
        private void OnListChanged(object sender, ListChangedEventArgs e)
        {
            var handler = listChanged;
            if (handler != null)
                handler(this, e);
        }
        public bool AllowNew { get { return source.AllowNew; } }
        public bool AllowEdit { get { return source.AllowEdit; } }
        public bool AllowRemove { get { return source.AllowRemove; } }
        public bool SupportsChangeNotification { get { return source.SupportsChangeNotification; } }
        public bool SupportsSearching { get { return source.SupportsSearching; } }
        public bool SupportsSorting { get { return source.SupportsSorting; } }
        public bool IsSorted { get { return source.IsSorted; } }
        public PropertyDescriptor SortProperty { get { return source.SortProperty; } }
        public ListSortDirection SortDirection { get { return source.SortDirection; } }
        public object AddNew() { return source.AddNew(); }
        public void AddIndex(PropertyDescriptor property) { source.AddIndex(property); }
        public void ApplySort(PropertyDescriptor property, ListSortDirection direction) { source.ApplySort(property, direction); }
        public int Find(PropertyDescriptor property, object key) { return source.Find(property, key); }
        public void RemoveIndex(PropertyDescriptor property) { source.RemoveIndex(property); }
        public void RemoveSort() { source.RemoveSort(); }
    }

    private class BindingListView : BindingList, IBindingListView
    {
        private IBindingListView source;
        public BindingListView(IBindingListView source, Func<PropertyDescriptor, PropertyDescriptor> propertyMapper) : base(source, propertyMapper) { this.source = source; }
        public string Filter { get { return source.Filter; } set { source.Filter = value; } }
        public ListSortDescriptionCollection SortDescriptions { get { return source.SortDescriptions; } }
        public bool SupportsAdvancedSorting { get { return source.SupportsAdvancedSorting; } }
        public bool SupportsFiltering { get { return source.SupportsFiltering; } }
        public void ApplySort(ListSortDescriptionCollection sorts) { source.ApplySort(sorts); }
        public void RemoveFilter() { source.RemoveFilter(); }
    }
}

, , , IBindingList IBindingListView. , , ( List<T> BiundingList<T> ITypedList), GetItemProperties, propertyMapper .

DataTable Complex Complex.Name:

class ComplexData
{
    public int Value { get; set; }
}

class ComplexDataWrapper
{
    public string Name { get; set; }
    public ComplexData Data { get; set; } = new ComplexData();
}

static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        var form = new Form();
        var gridView = new DataGridView { Dock = DockStyle.Fill, Parent = form };
        gridView.DataSource = ListDataView.Create(GetData(), null, p =>
        {
            if (p.PropertyType == typeof(ComplexDataWrapper))
                return ChildPropertyDescriptor.Create(p, "Name", "Complex Name");
            return p;
        });
        Application.Run(form);
    }

    static DataTable GetData()
    {
        var dt = new DataTable();
        dt.Columns.Add("Id", typeof(int));
        dt.Columns.Add("Complex", typeof(ComplexDataWrapper));
        for (int i = 1; i <= 10; i++)
            dt.Rows.Add(i, new ComplexDataWrapper { Name = "Name#" + i, Data = new ComplexData { Value = i } });
        return dt;
    }
}

, PropertyDescriptor ITypedList , .

+3

, , .

gridView , datatable, .

, , , .

+2

All Articles