The generic (assuming the datasource implements IList) solution I came up with which allows you to paste from Excel when the gridview is empty or populated while adding rows if over running existing rows, for anyone googling a solution. I used CsvHelper to reliably parse the string from the clipboard to a dynamic object. The properties are them mapped in order when it is possible to convert to the property so that it supports partial columns. I wanted to use AutoMapper for that part, but doing an optimistic index based mapping with it looks to be more of a hassle than just doing it manually.
public
class
CustomGrid : RadGridView
{
protected
override
RadGridViewElement CreateGridViewElement()
{
return
new
CustomRadGridViewElement();
}
public
override
string
ThemeClassName =>
typeof
(RadGridView).FullName;
}
public
class
CustomRadGridViewElement : RadGridViewElement
{
protected
override
MasterGridViewTemplate CreateTemplate()
{
return
new
CustomMasterGridViewTemplate();
}
protected
override
Type ThemeEffectiveType =>
typeof
(RadGridViewElement);
}
public
class
CustomMasterGridViewTemplate : MasterGridViewTemplate
{
public
static
bool
CanChangeType(
object
value, Type conversionType)
{
if
(conversionType ==
null
)
{
return
false
;
}
if
(value ==
null
)
{
return
false
;
}
IConvertible convertible = value
as
IConvertible;
if
(convertible ==
null
)
{
return
false
;
}
return
true
;
}
public
override
void
Paste()
{
if
(Clipboard.ContainsData(DataFormats.Text))
{
var dataSource =
this
.Owner.DataSource
as
IList;
if
(dataSource !=
null
)
{
string
data = Clipboard.GetData(DataFormats.Text).ToString();
if
(!
string
.IsNullOrWhiteSpace(data))
{
using
(TextReader reader =
new
StringReader(data))
{
var csv =
new
CsvReader(reader,
new
Configuration(){HasHeaderRecord =
false
, Delimiter =
"\t"
});
IEnumerable<
object
> records =
null
;
var type = dataSource.GetType().GetGenericArguments().Single();
try
{
records = csv.GetRecords<dynamic>().ToList();
var count = records.Count();
}
catch
{ }
if
(records !=
null
)
{
var rowIndex = 0;
if
(
this
.Owner.SelectedCells.Any())
rowIndex =
this
.Owner.SelectedCells.Select(c => c.RowInfo.Index).Min();
if
(
this
.Owner.SelectedRows.Any())
rowIndex =
this
.Owner.SelectedRows.Select(r => r.Index).Min();
if
(rowIndex == -1)
rowIndex =
this
.Owner.RowCount;
foreach
(var record
in
records)
{
if
(dataSource.Count == rowIndex)
{
dataSource.Add(Activator.CreateInstance(type));
}
var propertyValues = (IDictionary<
string
,
object
>)record;
var properties = dataSource[rowIndex].GetType().GetProperties();
var propertyIndex = 0;
foreach
(var propertyValue
in
propertyValues)
{
while
(!CanChangeType(propertyValue.Value, properties[propertyIndex].PropertyType) && propertyIndex < properties.Length)
{
propertyIndex++;
}
if
(propertyIndex < properties.Length)
{
var value = Convert.ChangeType(propertyValue.Value, properties[propertyIndex].PropertyType);
properties[propertyIndex].SetValue(dataSource[rowIndex], value);
}
}
rowIndex++;
}
this
.Refresh();
return
;
}
}
}
}
}
base
.Paste();
}
}