"Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index"
I'm thinking the issue is that I'm binding to a collection for each GridViewDataColumn and export method is not sure how to handle that.
After further testing it appears the exporting a jagged grid is the problem.
If your data happens to look like this:
------------------------
Col1, Col2, Col3
value, value, value
value, value, null
value, null, null
radGridView.AutoGenerateColumns = false;
radGridView.GridViewGroupPanel.Visibility = Visibility.Collapsed;
table = dataReceiver.GetCurrentViewData();
int index = 0;
foreach (ColumnInfo col in table.Columns)
{
GridViewDataColumn column = new GridViewDataColumn();
column.DataMemberBinding = new Binding("Values[" + index.ToString() + "]");
column.Header = col.ColumnName;
column.UniqueName = col.ColumnName;
radGridView.Columns.Add(column);
index++;
}
radGridView.ItemsSource = table.Rows;
string xml = radGridView.ToExcelML(); //throws error here
if (dialog.ShowDialog() == true)
{
using (Stream stream = dialog.OpenFile())
{
//This throws the same error
radGridView.Export(stream,
new GridViewExportOptions()
{
Format = ExportFormat.ExcelML,
ShowColumnHeaders = true,
ShowColumnFooters = false,
ShowGroupFooters = false,
});
}
}
Below is the Class I'm binding to the RadGrid:
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.Runtime.Serialization;
namespace RadGridExportTest
{
[DataContract]
public partial class ValueTable
{
/// <summary>
/// DataKey
/// </summary>
[DataMember]
public string Key { get; set; }
/// <summary>
/// Gets or sets the table name
/// </summary>
[DataMember]
public string TableName { get; set; }
/// <summary>
/// Gets or sets the merge key columninfo
/// </summary>
[DataMember]
public ColumnInfo MergeKey { get; set; }
/// <summary>
/// Gets the Columns list
/// </summary>
[DataMember]
public ObservableCollection<ColumnInfo> Columns { get; private set; }
/// <summary>
/// Gets the Rows list
/// </summary>
[DataMember]
public ObservableCollection<RowInfo> Rows { get; private set; }
/// <summary>
/// Gets the index of the column name from the columns collection
/// </summary>
/// <param name="columnName"></param>
/// <returns></returns>
public int IndexOf(string columnName)
{
int index = -1;
for (int i = 0; i < Columns.Count; i++)
{
if (this.Columns[i].ColumnName == columnName)
{
index = i;
break;
}
}
return index;
}
/// <summary>
/// ValueTable constructor
/// </summary>
public ValueTable()
{
Columns = new ObservableCollection<ColumnInfo>();
Rows = new ObservableCollection<RowInfo>();
}
}
[DataContract]
public partial class RowInfo
{
/// <summary>
/// Gets the number of elements
/// </summary>
[DataMember]
public int Elements { get; private set; }
/// <summary>
/// Gets the values for the row
/// </summary>
[DataMember]
public ObservableCollection<object> Values { get; private set; }
/// <summary>
/// Constructor, initializes rowValues
/// </summary>
public RowInfo()
{
this.Values = new ObservableCollection<object>();
}
/// <summary>
/// Unfortunately this doesn't work in Wcf
/// </summary>
/// <param name="column"></param>
/// <returns></returns>
public object this[int column]
{
get
{
if (this.Elements < column)
return null;
return this.Values[column];
}
}
/// <summary>
/// Add a column value to the row, index of the rowValues collection is the column index
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public int Add(object obj)
{
this.Values.Add(obj);
this.Elements = this.Values.Count;
return this.Elements;
}
}
[DataContract]
public partial class ColumnInfo : IEquatable<ColumnInfo>
{
private string _columnName;
private TypeCode _columnType;
/// <summary>
/// Name of column
/// </summary>
[DataMember]
public string ColumnName
{
get { return _columnName; }
set { _columnName = value; }
}
/// <summary>
/// Data type of column
/// </summary>
[DataMember]
public TypeCode ColumnType
{
get { return _columnType; }
set { _columnType = value; }
}
/// <summary>
/// Default constructor
/// </summary>
public ColumnInfo()
{
ColumnName = String.Empty;
ColumnType = TypeCode.String;
}
/// <summary>
/// Constructors with name and type
/// </summary>
/// <param name="columnName"></param>
/// <param name="columnType"></param>
public ColumnInfo(string columnName, TypeCode columnType)
{
ColumnName = columnName;
ColumnType = columnType;
}
/// <summary>
/// Returns a clone of the current object, a new instance with same values
/// </summary>
/// <returns></returns>
public ColumnInfo Clone()
{
ColumnInfo clone = new ColumnInfo();
clone.ColumnName = this.ColumnName;
clone.ColumnType = this.ColumnType;
return clone;
}
/// <summary>
/// Equality comparator
/// </summary>
/// <param name="columnObj"></param>
/// <returns></returns>
public bool Equals(ColumnInfo columnObj)
{
if ((object)columnObj == null)
return false;
return ColumnName.Equals(columnObj.ColumnName);
}
/// <summary>
/// Comparison
/// </summary>
/// <param name="columnObj"></param>
/// <returns></returns>
public int CompareTo(object columnObj)
{
if (columnObj is ColumnInfo)
{
ColumnInfo colInfo = (ColumnInfo)columnObj;
return ColumnName.CompareTo(colInfo.ColumnName);
}
throw new ArgumentException("object is not a ColumnInfo");
}
/// <summary>
/// For logging
/// </summary>
/// <returns></returns>
public override string ToString()
{
return String.Format("Column Name [{0}], Type [{1}]", ColumnName, ColumnType);
}
}
}