Search code examples
entity-framework-6catelsyncfusion

Catel UIVisualizerService issue with Syncfusion sfDatagrid


I have created a project that makes use of Catel, Entity Framework 6 and Syncfusion Community Edition. Specifically I am using the sfDataGrid from Syncfusion.

I have come across an issue that has me completely stumped, maybe someone out there could point me in the right direction.

I have a Catel UserControl with a sfDataGrid in it. The ViewModel has an ObservableCollection (Catel Property) of the data I am using as the ItemsSource for the sfDataGrid. I have filtering enabled on the sfDataGrid. Here is the code for the sfDataGrid:

<sync:SfDataGrid
                x:Name="ItemsDataGrid"
                ItemsSource="{Binding MyItems, Mode=OneWay}"
                SelectedItem="{Binding MyItem, Mode=TwoWay}"
                AutoGenerateColumns="False"
                AllowFiltering="True"
                AllowResizingColumns="True"
                GridCopyOption="IncludeHeaders"
                GridPasteOption="None"
                ShowGroupDropArea="True"
                ShowRowHeader="True"
                DataFetchSize="50">
<!-- Columns -->
</sync:SfDataGrid>

I add a new Item to the collection on a different view and then I save it to the datacontext and refresh the list:

private async void OnNewMyItemExecute()
        {
            MyItem= new MyItem();

            MyItemsRepository.Add(MyItem);

            var myItemsViewModel = TypeFactory
                .Default
                .CreateInstanceWithParametersAndAutoCompletion<myItemsViewModel >(MyItem); //the construction has parameters for IUIVisualizerService, IPleaseWaitService, etc.

            if (await _UIVisualizerService.ShowDialogAsync(myItemsViewModel) ?? true)
            {
                var myItem= myItemsViewModel.MyItem;

                await InitializeAsync();

                MyItem = myItem;
            }
            else
            {
                _UnitOfWorkService.Rollback(); //just undo some changes
                MyItem = null;
            }

            UnitOfWork.SaveChanges();
        }

Creating a new Item is not a problem at all, the thing that is weird is that after I created a new Item and then attempt to filter grid on any column of the sfDataGrid (click the filter button in the column header, a filter popup opens, enter a value in the criteria textbox and click 'OK'), I get this:

MyProject.vshost.exe Warning: 0 : 17:57:49:075 => [WARNING] [Catel.Services.UIVisualizerService] [8] An error occurred, returning null since we don't know the result | [TargetInvocationException] System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidCastException: Unable to cast object of type 'MyProject.Domain.MyItem' to type 'System.Data.Entity.DynamicProxies.MyItem_4CA6F59AB53174892ED9EFBC1D3CC07B862579FC3C5733C6CF4DE857907CFF9C'. at lambda_method(Closure , MyItem ) --- End of inner exception stack trace --- at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor) at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments) at System.Delegate.DynamicInvokeImpl(Object[] args) at System.Delegate.DynamicInvoke(Object[] args) at Syncfusion.Data.QueryableCollectionView.<>c__DisplayClass3.b__1(Object o) at Syncfusion.Data.QueryableCollectionView.FilterRecord(Object record) at Syncfusion.Data.EnumerableRecordsWrapper..ctor(IEnumerable source, CollectionViewAdv view) at Syncfusion.Data.EnumerableRecordsWrapper.CreateNew(IEnumerable source, CollectionViewAdv view) at Syncfusion.Data.QueryableCollectionView.CreateRecords() at Syncfusion.Data.CollectionViewAdv.EnsureInitialized() at Syncfusion.Data.CollectionViewAdv.get_Records() at Syncfusion.Data.CollectionViewAdv.EnsureRecordsInitialized() at Syncfusion.Data.CollectionViewAdv.Refresh() at Syncfusion.Data.QueryableCollectionView.RefreshFilter() at Syncfusion.Data.CollectionViewAdv.ApplyFilters() at Syncfusion.Data.CollectionViewAdv.set_FilterPredicates(ObservableCollection1 value) at Syncfusion.UI.Xaml.Grid.GridModel.FilterColumn(GridColumn column, List1 filterPredicates) at Syncfusion.UI.Xaml.Grid.GridFilterControl.RefreshFilter() at Syncfusion.UI.Xaml.Grid.GridFilterControl.b__10(Object s, RunWorkerCompletedEventArgs e) at System.ComponentModel.BackgroundWorker.OnRunWorkerCompleted(RunWorkerCompletedEventArgs e) at System.ComponentModel.BackgroundWorker.AsyncOperationCompleted(Object arg) at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs) at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler) at System.Windows.Threading.DispatcherOperation.InvokeImpl() at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Windows.Threading.DispatcherOperation.Invoke() at System.Windows.Threading.Dispatcher.ProcessQueue() at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o) at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs) at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler) at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs) at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam) at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg) at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame) at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
at System.Windows.Window.ShowHelper(Object booleanBox) at System.Windows.Window.Show() at System.Windows.Window.ShowDialog() --- End of inner exception stack trace --- at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor) at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters) at Catel.Services.UIVisualizerService.<>c__DisplayClass23_0.b__0() in C:\CI_WS\Ws\86058\Source\Catel\src\Catel.MVVM\Catel.MVVM.Shared\Services\UIVisualizerService.cs:line 499

This is the method of UIVisualizerService with Line 499:

protected virtual bool? ShowWindow(FrameworkElement window, bool showModal)
        {
            if (showModal)
            {
                var showDialogMethodInfo = window.GetType().GetMethodEx("ShowDialog");
                if (showDialogMethodInfo != null)
                {
                    // Child window does not have a ShowDialog, so not null is allowed
                    bool? result = null;

                    window.Dispatcher.InvokeIfRequired(() =>
                    {
                        // Safety net to prevent crashes when this is the main window
                        try
                        {
                            result = showDialogMethodInfo.Invoke(window, null) as bool?; //Line 499
                        }
                        catch (Exception ex)
                        {
                            Log.Warning(ex, "An error occurred, returning null since we don't know the result");
                        }
                    });

                    return result;
                }

                Log.Warning("Method 'ShowDialog' not found on '{0}', falling back to 'Show'", window.GetType().Name);
            }

I have tried opening MyItemsView with .ShowAsync(), .ShowDialogAsync() and before I upgraded to Catel 4.4 I also used .ShowDialog(), but it made no difference. I could turn Proxy Creation off in EF, but that would cause a lot of changes I have to make in my project (no more lazy loading for me, and that is not an option). I do believe the problem being the new Item I add not being a Dynamic Proxy, and getting it to be a Dynamic Proxy would probably solve the issue, but I have tried loading all the data from the DbContext again, but it also does not solve the problem.

Any advice would be appreciated.


Solution

  • The issue is this:

    System.InvalidCastException: Unable to cast object of type 'MyProject.Domain.MyItem' to type 'System.Data.Entity.DynamicProxies.MyItem_4CA6F59AB53174892ED9EFBC1D3CC07B862579FC3C5733C6CF4DE857907CFF9C'. 
    

    The reason is, of course, that you are trying to cast a base type to a derived type (which it simply isn't). That this eventually results in the window closing is because an exception happens, but that isn't the real problem.

    This exception occurs in the FilterRecord method of the grid. I am not sure if that is something you have written yourself or something that is inside syncfusion, but that is the place to look.

    The reason you have generated proxies is because you enabled (or it's enabled by default) the proxy generation of the Entity Framework DbContext.