Native type binding source / How to fill a DevExpress GridControl with a List of strings?

别来无恙 提交于 2020-05-18 19:09:19

问题


I normally have no problem with binding a DataSource to a GridControl. I usually so something like this:

myGrid.DataSource = myList // BindingList<ComplexObject>
colMyStrings.FieldName = "PropertyNameOfComplexObject";

and it works fine. I can add and delete rows from the grid and they will get added to / deleted from the DataSource "myList". So I basically always see what's in my List.

But now I don't have a List<ComplexObject>, where the Generic Type has Properties, but I have a List filled with strings.

BindingList<string>

When I try to bind the List to my grid, it wont get that the strings themselves are what i want bound to the rows of my column and since string doesn't have any properties, there is nothing I can fill the columns .FieldName with.

I know I could use a wrapper class to solve this problem, but I don't find this solution to be very nice.

Is there a way to tell the column, that the data it should use is the Objects, in this case the strings, themselves?

Update 1

This is something I tried. I thought if I could make my own GridControl and override the setter for the DataSource Property, I could make an internal Wrapper so that anyone who uses it wont need do so. This kind of works. I can add my DataSource BindingList<string> now, but for some reason I cant edit the values. I don't know why.

Here is the code:

public partial class NativeTypeGrid : DevExpress.XtraGrid.GridControl
{
    public NativeTypeGrid()
    {
        InitializeComponent();
    }

    public override object DataSource
    {
        get
        {
            return base.DataSource;
        }
        set
        {
            if (value is IBindingList)
            {
                Type GenericType;
                IBindingList myList = (IBindingList) value;
                BindingList<Wrapper> wrappedList = new BindingList<Wrapper>();
                GenericType = myList.GetType().GetGenericArguments()[0];
                if(GenericType.IsPrimitive || GenericType == typeof(string))
                {
                    for(int i = 0; i < myList.Count; i++)
                    {
                        object obj = myList[i];
                        wrappedList.Add(new Wrapper(ref obj));
                    }

                    base.DataSource = wrappedList;
                }
                else
                {
                    base.DataSource = value;
                }
            }
            else
            {
                base.DataSource = value;
            }
        }
    }

    internal class Wrapper
    {
        private object _NativeTypeProperty;

        public Wrapper()
        {
            _NativeTypeProperty = "SomeValueForInitialization";
        }

        public Wrapper(ref object nativeType)
        {
            _NativeTypeProperty = nativeType;
        }

        public object NativeTypeProperty
        {
            get { return _NativeTypeProperty; }
            set { _NativeTypeProperty = value; }
        }
    }
}

Update 2

I already figured out why it won't get any by the user added objects. Of course it doesn't work since adding an Object to the DataSource uses the basic/empty constructor, which in turn means that my DataSource doesn't have that connection to the original List, which is the one I want the new objects to be in. I will work on this and update again.

Update 3

Couldn't think of any better solution, so I went with the initial approach and built a wrapper class for my strings. Looks a little bit like this:

class StringWrapper{
    public String MyString{ get; set;}
}

myGrid.DataSource = new BindingList<StringWrapper>();

I would still be happy to use another approach.


回答1:


You can set the "Column" as Column.FieldName.
Here is example:

var myList = new List<string>() { "String 0", "String 1", "String 2" };

myGrid.DataSource = myList;
colMyStrings.FieldName = "Column";

However you cannot add or modify the values in GridView, because DevExpress team does not implemented the properly usage of this case and you can only delete values.

But if you want to manipulate with your list by using GridControl, then you need to create list wrapper, not string wrapper. For this purpose you can implement IBindingList interface which is allowed as DataSource according to documentation.
Here is example of simple list wrapper that implements IBindingList interface:

public class ListWrapper<T> : IBindingList
{
    private IList<T> _wrappedList;

    public ListWrapper(IList<T> wrappedList)
    {
        _wrappedList = wrappedList;
    }

    #region IBindingList implementation
    #region Necessary members
    public object this[int index]
    {
        get { return new Wrapper(this, index); }//This wrapper have the Value property which is used as FieldName.
        set { Insert(index, value); }
    }

    public object AddNew()
    {
        _wrappedList.Add(default(T));

        return new Wrapper(this, Count - 1);
    }

    public void RemoveAt(int index)
    {
        _wrappedList.RemoveAt(index);
    }

    public int Count { get { return _wrappedList.Count; } }

    public IEnumerator GetEnumerator()
    {
        return new ListWrapperEnumerator(this);
    }

    private class Wrapper
    {
        private readonly ListWrapper<T> _listWrapper;
        private readonly int _index;

        public Wrapper(ListWrapper<T> listWrapper, int index)
        {
            _listWrapper = listWrapper;
            _index = index;
        }

        public T Value
        {
            get { return _listWrapper._wrappedList[_index]; }
            set { _listWrapper._wrappedList[_index] = value; }
        }
    }

    private class ListWrapperEnumerator : IEnumerator
    {
        private readonly ListWrapper<T> _listWrapper;
        private int _currentIndex;

        public ListWrapperEnumerator(ListWrapper<T> listWrapper)
        {
            _listWrapper = listWrapper;

            Reset();
        }

        public object Current
        {
            get { return _listWrapper[_currentIndex]; }
        }

        public bool MoveNext()
        {
            return _currentIndex++ < _listWrapper.Count;
        }

        public void Reset()
        {
            _currentIndex = -1;
        }
    }
    #endregion
    #region Optional members
    private bool GetValue(object value, out T result)
    {
        if (value is T)
        {
            result = (T)value;

            return true;
        }

        var wrapper = value as Wrapper<T>;
        if (wrapper != null)
        {
            result = wrapper.Value;

            return true;
        }

        result = default(T);
        return false;
    }

    public int Add(object value)
    {
        T result;

        if (GetValue(value, out result))
        {
            _wrappedList.Add(result);
            return _wrappedList.Count - 1;
        }

        return -1;
    }

    public void Clear()
    {
        _wrappedList.Clear();
    }

    public bool Contains(object value)
    {
        T result;

        if (GetValue(value, out result))
            return _wrappedList.Contains(result);

        return false;
    }

    public void CopyTo(Array array, int index)
    {
        for (int listIndex = 0; listIndex < _wrappedList.Count; listIndex++)
        {
            int arrayIndex = listIndex + index;

            if (arrayIndex >= array.Length)
                return;

            array.SetValue(_wrappedList[listIndex], arrayIndex);
        }
    }

    public int IndexOf(object value)
    {
        T result;

        if (GetValue(value, out result))
            return _wrappedList.IndexOf(result);

        return -1;
    }

    public void Insert(int index, object value)
    {
        T result;

        if (GetValue(value, out result))
            _wrappedList.Insert(index, result);
    }

    public void Remove(object value)
    {
        T result;

        if (GetValue(value, out result))
            _wrappedList.Remove(result);
    }
    #endregion
    #region Settings
    public bool AllowEdit { get { return true; } }

    public bool AllowNew { get { return true; } }

    public bool AllowRemove { get { return true; } }

    public bool IsFixedSize { get { return false; } }

    public bool IsReadOnly { get { return false; } }

    public bool SupportsChangeNotification { get { return false; } }

    public bool SupportsSearching { get { return false; } }

    public bool SupportsSorting { get { return false; } }
    #endregion
    #region Not used members
    public void AddIndex(PropertyDescriptor property) { }

    public void ApplySort(PropertyDescriptor property, ListSortDirection direction) { }

    public int Find(PropertyDescriptor property, object key) { return -1; }

    public void RemoveIndex(PropertyDescriptor property) { }

    public void RemoveSort() { }

    public bool IsSorted { get { return false; } }

    public bool IsSynchronized { get { return false; } }

    public ListSortDirection SortDirection { get { return default(ListSortDirection); } }

    public PropertyDescriptor SortProperty { get { return null; } }

    public object SyncRoot { get { return null; } }

    public event ListChangedEventHandler ListChanged;
    #endregion
    #endregion
}

You can use this wrapper as follows:

var myList = new BindingList<string>() { "String 0", "String 1", "String 2" });

myGrid.DataSource = new ListWrapper<string>(myList);
colMyStrings.FieldName = "Value";


来源:https://stackoverflow.com/questions/32646177/native-type-binding-source-how-to-fill-a-devexpress-gridcontrol-with-a-list-of

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!