Collections derived from this class aren't thread safe by default

Posts   
 
    
pat
User
Posts: 215
Joined: 02-Mar-2006
# Posted on: 21-Mar-2010 08:57:57   

Hi,

when I use this code with the Xceed WPF Grid

using (var da = new DataAccessAdapter(false))
{
    var metaData = new LinqMetaData(da);

    IQueryable<MyCoreEntity> q = (from c in metaData.Core
                                  where c.EntityTypeId == 10
                                  select c);
    var _list = ((ILLBLGenProQuery)q).Execute<EntityCollection<MyCoreEntity>>();
    // Bind the grid to the composer collection via DataGridCollectionView.
    DataGridCollectionView dataGridCollectionView = new DataGridCollectionView(_list);
    this.dataGridControl1.SelectedItems.Clear();
    this.dataGridControl1.CurrentItem = null;
    dataGridControl1.ItemsSource = dataGridCollectionView;
}

I get this error:

System.NotSupportedException was unhandled by user code Message="Collections derived from this class aren't thread safe by default. Use your own locking system in your code." Source="SD.LLBLGen.Pro.ORMSupportClasses.NET20" StackTrace: at SD.LLBLGen.Pro.ORMSupportClasses.CollectionCore`1.System.Collections.ICollection.get_SyncRoot() in c:\Myprojects\VS.NET Projects\LLBLGen Pro v2.0\RuntimeLibraries 2.6 .NET 2.x\ORMSupportClasses\Core\CollectionCore.cs:line 811 at Xceed.Wpf.DataGrid.DataGridCollectionView.get_SyncRoot() at Xceed.Wpf.DataGrid.DataGridCollectionView.ForceRefresh(Boolean sendResetNotification, Boolean initialLoad, Boolean setCurrentToFirstOnInitialLoad) at Xceed.Wpf.DataGrid.DataGridCollectionViewBase.DeferRefreshHelper.Dispose() at System.Windows.Controls.ItemCollection.SetCollectionView(CollectionView view) at System.Windows.Controls.ItemCollection.SetItemsSource(IEnumerable value) at System.Windows.Controls.ItemsControl.OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) at System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e) at System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e) at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args) at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, OperationType operationType) at System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, OperationType operationType, Boolean isInternal) at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value) at System.Windows.Controls.ItemsControl.set_ItemsSource(IEnumerable value) at UT.Tara.UI.WPF.Modules.Views.XcGridView.OnInitialized(EventArgs e) in D:\Projects\Tara\System\Trunk\Source\UT.Tara.UI.WPF.Modules\Views\XcGridView.xaml.cs:line 37 at System.Windows.FrameworkElement.TryFireInitialized() at System.Windows.FrameworkElement.EndInit() at System.Windows.Markup.BamlRecordReader.ElementEndInit(Object& element) InnerException:

Does anybody know how to get it to work?

Thanks, Patrick

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 21-Mar-2010 11:30:27   

We could remove the exception but it would give a false sense of 'I'm using a synced object', similar to Dictionary.SyncRoot, which simply returns itself although it's not threadsafe.

I do wonder though why the grid calls SyncRoot as it's a ui element. There's no way making the thread not call that method?

Frans Bouma | Lead developer LLBLGen Pro
pat
User
Posts: 215
Joined: 02-Mar-2006
# Posted on: 21-Mar-2010 23:54:35   

Interesting this throws the exception:

// Throws exception: Collections derived from this class aren't thread safe by default.
var dgcv = new DataGridCollectionView(_list);
dataGridControl1.ItemsSource = dgcv;

This doesn't throw the exception:

// Works
// Bind the grid to the composer collection via DataGridCollectionView.
var dgcvs = new DataGridCollectionViewSource() { Source = _list };
dataGridControl1.ItemsSource = dgcvs.View;

I found the workaround on this thread by the way http://xceed.com/CS/forums/post/21025.aspx

So maybe you don't have to rush to remove the exception.

Thanks, Patrick

pat
User
Posts: 215
Joined: 02-Mar-2006
# Posted on: 22-Mar-2010 01:05:40   

pat wrote:

This doesn't throw the exception:

I spoke too early. As soon as I tried Master / Detail the call to SyncRoot happened again.

Otis wrote:

similar to Dictionary.SyncRoot, which simply returns itself although it's not threadsafe.

Could it be that if MS makes a mistake everybody just has to copy it since everybody else is relying on the mistake to be there?

If that's the case maybe replacing: throw new NotSupportedException( "Collections derived from ...." ); with Console.WriteLine("LLBLGen: NotSupportedException-Collections derived from ...." ); Would be the solution simple_smile

All the best, Patrick

System.NotSupportedException was unhandled Message="Collections derived from this class aren't thread safe by default. Use your own locking system in your code." Source="SD.LLBLGen.Pro.ORMSupportClasses.NET20" StackTrace: at SD.LLBLGen.Pro.ORMSupportClasses.CollectionCore`1.System.Collections.ICollection.get_SyncRoot() in c:\Myprojects\VS.NET Projects\LLBLGen Pro v2.0\RuntimeLibraries 2.6 .NET 2.x\ORMSupportClasses\Core\CollectionCore.cs:line 811 at Xceed.Wpf.DataGrid.DataGridCollectionView.get_SyncRoot() at Xceed.Wpf.DataGrid.DataGridCollectionView.ForceRefresh(Boolean sendResetNotification, Boolean initialLoad, Boolean setCurrentToFirstOnInitialLoad) at Xceed.Wpf.DataGrid.DataGridCollectionViewBase..ctor(IEnumerable collection, DataGridDetailDescription parentDetailDescription, DataGridCollectionViewBase rootDataGridCollectionViewBase) at Xceed.Wpf.DataGrid.DataGridCollectionView..ctor(IEnumerable collection, DataGridDetailDescription parentDetailDescription, DataGridCollectionView rootDataGridCollectionView) at Xceed.Wpf.DataGrid.DataGridCollectionView.CreateDetailDataGridCollectionViewBase(IEnumerable detailDataSource, DataGridDetailDescription parentDetailDescription, DataGridCollectionViewBase rootDataGridCollectionViewBase) at Xceed.Wpf.DataGrid.CustomItemContainerGenerator.CreateDetailsHelper(ItemsGeneratorNode masterNode, Object dataItem) at Xceed.Wpf.DataGrid.CustomItemContainerGenerator.CreateDetailsForItem(Object dataItem) at Xceed.Wpf.DataGrid.CustomItemContainerGenerator.ToggleDetails(Object dataItem) at Xceed.Wpf.DataGrid.DataGridContext.ToggleDetailExpansion(Object dataItem) at Xceed.Wpf.DataGrid.DataRow.OnToggleDetailsExecuted(Object sender, ExecutedRoutedEventArgs e) at System.Windows.Input.CommandBinding.OnExecuted(Object sender, ExecutedRoutedEventArgs e) at System.Windows.Input.CommandManager.ExecuteCommandBinding(Object sender, ExecutedRoutedEventArgs e, CommandBinding commandBinding) at System.Windows.Input.CommandManager.FindCommandBinding(CommandBindingCollection commandBindings, Object sender, RoutedEventArgs e, ICommand command, Boolean execute) at System.Windows.Input.CommandManager.FindCommandBinding(Object sender, RoutedEventArgs e, ICommand command, Boolean execute) at System.Windows.Input.CommandManager.OnExecuted(Object sender, ExecutedRoutedEventArgs e) at System.Windows.UIElement.OnExecutedThunk(Object sender, ExecutedRoutedEventArgs e) at System.Windows.Input.ExecutedRoutedEventArgs.InvokeEventHandler(Delegate genericHandler, Object target) at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target) at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs) at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised) at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args) at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted) at System.Windows.Input.RoutedCommand.ExecuteImpl(Object parameter, IInputElement target, Boolean userInitiated) at System.Windows.Input.RoutedCommand.ExecuteCore(Object parameter, IInputElement target, Boolean userInitiated) at MS.Internal.Commands.CommandHelpers.CriticalExecuteCommandSource(ICommandSource commandSource, Boolean userInitiated) at System.Windows.Controls.Primitives.ButtonBase.OnClick() at System.Windows.Controls.Button.OnClick() at System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e) at System.Windows.UIElement.OnMouseLeftButtonUpThunk(Object sender, MouseButtonEventArgs e) at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget) at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target) at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs) at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised) at System.Windows.UIElement.ReRaiseEventAs(DependencyObject sender, RoutedEventArgs args, RoutedEvent newEvent) at System.Windows.UIElement.CrackMouseButtonEventAndReRaiseEvent(DependencyObject sender, MouseButtonEventArgs e) at System.Windows.UIElement.OnMouseUpThunk(Object sender, MouseButtonEventArgs e) at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget) at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target) at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs) at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised) at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args) at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted) at System.Windows.Input.InputManager.ProcessStagingArea() at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input) at System.Windows.Input.StylusLogic.PromoteMainToMouse(ProcessInputEventArgs e) at System.Windows.Input.StylusLogic.PostProcessInput(Object sender, ProcessInputEventArgs e) at System.Windows.Input.InputManager.ProcessStagingArea() at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input) at System.Windows.Input.StylusLogic.InputManagerProcessInputEventArgs(InputEventArgs input) at System.Windows.Input.StylusLogic.InputManagerProcessInput(Object oInput) at System.Windows.Input.StylusLogic.PreProcessInput(Object sender, PreProcessInputEventArgs e) at System.Windows.Input.InputManager.ProcessStagingArea() at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input) at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport) at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel) at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) at System.Windows.Interop.HwndSource.InputFilterMessage(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, Boolean isSingleParameter) at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler) at System.Windows.Threading.Dispatcher.WrappedInvoke(Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler) at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Boolean isSingleParameter) at System.Windows.Threading.Dispatcher.Invoke(DispatcherPriority priority, Delegate method, Object arg) 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.Threading.Dispatcher.Run() at System.Windows.Application.RunDispatcher(Object ignore) at System.Windows.Application.RunInternal(Window window) at System.Windows.Application.Run(Window window) at System.Windows.Application.Run() at UT.Tara.UI.WPF.App.Main() in D:\Projects\Tara\System\Trunk\Source\UT.Tara.UI.WPF\obj\x86\Debug\App.g.cs:line 48 at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args) at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart() InnerException:

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 22-Mar-2010 10:33:34   

What's a 'DataGridCollectionView' ?

Why don't you bind the collections directly?

Btw, I just realized something: the grid apparently doesn't obey IListSource on the bound collection. This means that the raw collection is bound, but it should bind to the DefaultView, as the collection implements IListSource. XCeed's grid have been a problem in the past, and apparently they've not implemented things properly.

So could you bind the _list.DefaultView instead to the grid? (not through any wrapper, bind it directly, the grid has to support this!)

Frans Bouma | Lead developer LLBLGen Pro
pat
User
Posts: 215
Joined: 02-Mar-2006
# Posted on: 22-Mar-2010 12:52:37   

Otis wrote:

What's a 'DataGridCollectionView' ?

The DataGridCollectionView class allows any collection that implements the IEnumerable interface to be grouped, sorted, and filtered. Contrary to the BindingListCollectionView class, the DataGridCollectionView class will never touch the underlying data source, meaning that the original sorting and filtering present in the data source will not be modified. When sorting, the DataGridCollectionView class also provides an estimated 20% increase in performance. In addition to the sorting speed, a limited number of "resets" make the DataGridCollectionView class a better choice when performance is of the utmost importance.

http://doc.xceedsoft.com/products/XceedWpfDataGrid/Xceed.Wpf.DataGrid~Xceed.Wpf.DataGrid.DataGridCollectionView.html

Otis wrote:

So could you bind the _list.DefaultView instead to the grid? (not through any wrapper, bind it directly, the grid has to support this!)

dataGridControl1.ItemsSource = _list.DefaultView;

Doesn't change it at all. The grid is still so slow that if you scroll once and then try to scroll again it stops responding for a couple of seconds.

Doing it with a DataTable it's very fast by the way...

I really wonder why MS invented the DataTable in the first place. If they had just gone with plain BindingList object collections from the beginning then binding would have just work with them disappointed

Thanks, Patrick

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 22-Mar-2010 13:38:00   

Hmm. If it's slow, it's indeed XCeed's fault, as the view is simply returning the entities enumerated, and that's very fast. Binding the view should solve the problem of the SyncRoot

Frans Bouma | Lead developer LLBLGen Pro
pat
User
Posts: 215
Joined: 02-Mar-2006
# Posted on: 22-Mar-2010 14:47:55   

Otis wrote:

Binding the view should solve the problem of the SyncRoot

That is correct.

// Throws syncRoot var dgcv = new DataGridCollectionView(_list); dataGridControl1.ItemsSource = dgcv;

// Works var dgcv = new DataGridCollectionView(_list.DefaultView); dataGridControl1.ItemsSource = dgcv;

But as soon as I try to open a detail view the sync root exception comes again.

Thanks, Patrick

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 22-Mar-2010 14:55:06   

pat wrote:

Otis wrote:

Binding the view should solve the problem of the SyncRoot

That is correct.

// Throws syncRoot var dgcv = new DataGridCollectionView(_list); dataGridControl1.ItemsSource = dgcv;

// Works var dgcv = new DataGridCollectionView(_list.DefaultView); dataGridControl1.ItemsSource = dgcv;

But as soon as I try to open a detail view the sync root exception comes again. Thanks, Patrick

ah, that's logical of course as the grid then again just binds to the collection, ignoring completely the IListSource implementation, creating the same mess.

It's weird though, as DataView works because DataTable implements IListSource, but it seems XCeed has implemented a separate code path for DataTable.

I could of course remove the exception however that won't make it faster, as it seems slow regardless if the view is bound directly or the collection. disappointed

I'll wait till what XCeed has to say. They had bugs in the past which were fixed, so it might be they'll fix it again. Please let me know if I have to provide material to XCeed.

Frans Bouma | Lead developer LLBLGen Pro
JRR avatar
JRR
User
Posts: 125
Joined: 07-Dec-2005
# Posted on: 14-Jul-2010 19:34:04   

Hi Frans,

I am running in to the same issue where my grid is calling get_SyncRoot. I can't stop my grids, because I am using design-time databinding with related collections using datamembers.

System.NotSupportedException was unhandled by user code Message=Collections derived from this class aren't thread safe by default. Use your own locking system in your code. Source=SD.LLBLGen.Pro.ORMSupportClasses.NET20 StackTrace: at SD.LLBLGen.Pro.ORMSupportClasses.CollectionCore`1.System.Collections.ICollection.get_SyncRoot() in c:\Myprojects\VS.NET Projects\LLBLGen Pro v3.0\Frameworks\LLBLGen Pro\RuntimeLibraries\ORMSupportClasses\Core\CollectionCore.cs:line 810 at System.Windows.Forms.BindingSource.get_SyncRoot() at DevExpress.Data.DataControllerBase.CreateHelper() InnerException:

I would like to suggest a modification to the CollectionCore.cs file: a conditional that checks AppConfig for a setting for "SurpressSyncRootException" (or something close to that).

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 15-Jul-2010 11:36:24   

I'll return false for IsSynchronized and return the collection itself with SyncRoot (like Dictionary does too). For v2.6 and v3.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 15-Jul-2010 11:47:58   

The orm support classes of both v2.6 and 3.0 which fix this are attched.

Frans Bouma | Lead developer LLBLGen Pro