Skip to content

Instantly share code, notes, and snippets.

@weltkante
Created April 5, 2019 09:07
Show Gist options
  • Save weltkante/e4a616d629e09cf88b25aaf7864080c2 to your computer and use it in GitHub Desktop.
Save weltkante/e4a616d629e09cf88b25aaf7864080c2 to your computer and use it in GitHub Desktop.
2d array wrapper for WPF datagrid binding
public sealed class ArrayBinder : IBindingList, ITypedList
{
private sealed class ArrayColumn : PropertyDescriptor
{
public ArrayBinder Owner { get; }
public int ColumnIndex { get; }
public ArrayColumn(ArrayBinder owner, int index)
: base($"[{index}]", null)
{
Owner = owner;
ColumnIndex = index;
}
public override bool IsReadOnly => !Owner.AllowEdit;
public override Type ComponentType => typeof(ArrayRow);
public override Type PropertyType => typeof(object);
public override object GetValue(object component)
{
var row = component as ArrayRow;
if (row == null || row.Owner != Owner)
throw new ArgumentException();
return Owner._array[row.RowIndex, ColumnIndex];
}
public override void SetValue(object component, object value)
{
if (IsReadOnly)
throw new InvalidOperationException();
var row = component as ArrayRow;
if (row == null || row.Owner != Owner)
throw new ArgumentException();
Owner._array[row.RowIndex, ColumnIndex] = value;
}
public override bool ShouldSerializeValue(object component)
{
return false;
}
public override bool CanResetValue(object component)
{
return false;
}
public override void ResetValue(object component)
{
throw new NotSupportedException();
}
}
private sealed class ArrayRow
{
public ArrayBinder Owner { get; }
public int RowIndex { get; }
public ArrayRow(ArrayBinder owner, int index)
{
Owner = owner;
RowIndex = index;
}
// Workaround: WPF does not honor the PropertyDescriptor GetValue/SetValue implementation, but instead binds directly against the indexer
public object this[int ColumnIndex]
{
get => Owner._array[RowIndex, ColumnIndex];
set
{
if (!Owner.AllowEdit)
throw new InvalidOperationException();
Owner._array[RowIndex, ColumnIndex] = value;
}
}
}
private object[,] _array;
private ArrayRow[] _rows;
private PropertyDescriptorCollection _columns;
public ArrayBinder(object[,] source, bool allowEdit)
{
this.AllowEdit = allowEdit;
_array = source;
_rows = new ArrayRow[source.GetLength(0)];
for (int i = 0; i < _rows.Length; i++)
_rows[i] = new ArrayRow(this, i);
var columns = new ArrayColumn[source.GetLength(1)];
for (int i = 0; i < columns.Length; i++)
columns[i] = new ArrayColumn(this, i);
_columns = new PropertyDescriptorCollection(columns, true);
}
public object this[int index]
{
get => _rows[index];
set => throw new NotSupportedException();
}
public bool AllowNew => false; // adding rows is not possible on a 2d array
public bool AllowEdit { get; set; }
public bool AllowRemove => false; // removing rows is not possible on a 2d array
public bool SupportsChangeNotification => false;
public bool SupportsSearching => false;
public bool SupportsSorting => false;
public bool IsSorted => false;
public PropertyDescriptor SortProperty => null;
public ListSortDirection SortDirection => ListSortDirection.Ascending;
public bool IsReadOnly => true; // we allow editing row values (AllowEdit) not editing the list itself
public bool IsFixedSize => true; // adding/removing rows is not possible on a 2d array
public int Count => _rows.Length;
public object SyncRoot => this;
public bool IsSynchronized => false;
public event ListChangedEventHandler ListChanged { add { } remove { } }
public int Add(object value) => throw new NotSupportedException();
public void AddIndex(PropertyDescriptor property) { }
public object AddNew() => throw new NotSupportedException();
public void ApplySort(PropertyDescriptor property, ListSortDirection direction) => throw new NotSupportedException(); // SupportsSorting is false
public void Clear() => throw new NotSupportedException();
public bool Contains(object value) => IndexOf(value) >= 0;
public void CopyTo(Array array, int index) => _rows.CopyTo(array, index);
public int Find(PropertyDescriptor property, object key) => throw new NotSupportedException(); // SupportsSorting is false
public IEnumerator GetEnumerator() => _rows.GetEnumerator();
public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
{
if (listAccessors != null && listAccessors.Length != 0)
throw new NotSupportedException();
return _columns;
}
public string GetListName(PropertyDescriptor[] listAccessors) => null;
public int IndexOf(object value)
{
var row = value as ArrayRow;
if (row != null && row.Owner == this)
return row.RowIndex;
return -1;
}
public void Insert(int index, object value) => throw new NotSupportedException();
public void Remove(object value) => throw new NotSupportedException();
public void RemoveAt(int index) => throw new NotSupportedException();
public void RemoveIndex(PropertyDescriptor property) { }
public void RemoveSort() { }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment