We're using Andrew Davey's BindingListView<T>
class via sourceforge to bind collections to a DataGridView
and allow sorting and filtering.
This works fine for normal collections. In one case however the collection we're binding to is an Interface type and we get this error if we try to sort on it:
Invalid type owner for DynamicMethod
The error is deep in Andrew Davies' code so it's hard for us to know where to start.
private static Comparison<T> BuildValueTypeComparison(PropertyInfo pi, ListSortDirection direction)
{
MethodInfo getMethod = pi.GetGetMethod();
Debug.Assert(getMethod != null);
DynamicMethod dm = new DynamicMethod("Get" + pi.Name, typeof(int), new Type[] { typeof(T), typeof(T) }, typeof(T), true);
//^^^ ======== Here's the line reporting the error=========== ^^^
ILGenerator il = dm.GetILGenerator();
// Get the value of the first object's property.
il.Emit(OpCodes.Ldarg_0);
il.EmitCall(OpCodes.Call, getMethod, null);
// Box the value type
il.Emit(OpCodes.Box, pi.PropertyType);
// Get the value of the second object's property.
il.Emit(OpCodes.Ldarg_1);
il.EmitCall(OpCodes.Call, getMethod, null);
// Box the value type
il.Emit(OpCodes.Box, pi.PropertyType);
// Cast the first value to IComparable and call CompareTo,
// passing the second value as the argument.
il.Emit(OpCodes.Castclass, typeof(IComparable));
il.EmitCall(OpCodes.Call, typeof(IComparable).GetMethod("CompareTo"), null);
// If descending then multiply comparison result by -1
// to reverse the ordering.
if (direction == ListSortDirection.Descending)
{
il.Emit(OpCodes.Ldc_I4_M1);
il.Emit(OpCodes.Mul);
}
// Return the result of the comparison.
il.Emit(OpCodes.Ret);
// Create the delegate pointing at the dynamic method.
return (Comparison<T>)dm.CreateDelegate(typeof(Comparison<T>));
}
Do not give up and go to use DataSet! You are heading the right direction! Now, let's first take a look at the function signature:
DynamicMethod(string name,
Type returnType,
Type[] parameterTypes,
Type owner,
bool skipVisibility)
Error is “Invalid type owner for DynamicMethod"
The error message is trying to tell you, Type owner
is not what the function is expecting. It wants a Class type. You are probably passing an Interface type into the Type owner. It is impossible to create dynamic methods on an Interface.
1.Error Example
Maybe you are using Dependency Injection, and you may like to use Interface.
However, this code will hit Runtime Error.
var viewModelList = GetViewModels(); //returns an IList<IViewModel> <-- has i !!
var blv = new BindingListView<IViewModel>(viewModelList);
2.Working Example
Try to redesign your code to use Concrete Type.
Now, this code will NOT hit Runtime Error
var viewModelList = GetViewModels(); //returns an IList<ViewModel> <-- has no i !!
var blv = new BindingListView<ViewModel>(viewModelList);
Then, your Sorting and Filtering on DataGridView
will work automagically :)
EDIT ---------------------------------------------
P.S. About trying to redesign your code:
If you are using a MVVM/MVP pattern, think about the following logic. The IList<IViewModel>
should stay on the "VM+P" side. Purpose of using IViewModel is mainly because I want to be able to replace it with, say, MockingViewModel : IViewModel
for unit testing the "VM+P" side of logics.
Now, the BindingListView<ViewModel>
should really be on the "V" side, that is, the YourView : System.Windows.Form { ... }
. And it will be binded to the binding source from there YourBindingSource.DataSource = blv;
Since I won't be unit testing a WinForm, any logic in it I will try to refactor them into presenters and viewmodels and keep the View as thin as possible. So, I would just use ViewModel in BindingListView, not the interface IViewModel.
So the BindingListView<ConcreteViewModel>
will naturally make sense to me that it doesn't accept a model Interface.
Refer to this question about MVVM MVP design and unit testing WinForm: Should I unit-test my view in MVP(or VM) or how to keep the code in the view to a minimum?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With