- Home
- LLBLGen Pro
- LLBLGen Pro Runtime Framework
Collections derived from this class aren't thread safe by default
Joined: 02-Mar-2006
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
Joined: 17-Aug-2003
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?
Joined: 02-Mar-2006
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
Joined: 02-Mar-2006
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
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:
Joined: 17-Aug-2003
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!)
Joined: 02-Mar-2006
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.
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
Thanks, Patrick
Joined: 17-Aug-2003
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
Joined: 02-Mar-2006
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
Joined: 17-Aug-2003
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.
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.
Joined: 07-Dec-2005
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).