Text x-thread error with grid on multiple windows on unique threads

Grids for WPF Forum

Posted 6 years ago by Darcy Davidson
Version: 17.2.0665
Platform: .NET 4.7
Environment: Windows 10 (64-bit)
Avatar

Hi,

I am getting a cross thread access exception (on a textbox) when I set the DataObject on the property grid.  It occurs only when I spawn each WPF parent window on a new thread, like so:

Dim newWindowThread As Thread = New Thread(New ThreadStart(Sub()
Dim w As New Window1()
w.Show()
Threading.Dispatcher.Run()
End Sub))
newWindowThread.SetApartmentState(ApartmentState.STA)
newWindowThread.IsBackground = True
newWindowThread.Start()

Window1 just has a property grid on it, and on the loaded event I set the DataObject to a simple test class with a single integer property.  The first instance does not error, but the 2nd instance does.

[Modified 6 years ago]

Comments (7)

Posted 6 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi Darcy,

If you are having a PropertyGrid instance work on a data object from another thread, I could see that causing this kind of error.  UI controls generally can only work on data in their same thread.

If it's something else and you only have each PropertyGrid editing objects in their same thread, then we'd need a sample project from you to debug with.  In that case, please make a new simple sample project that shows it and send that to our support address.  Exclude any bin/obj folders from the ZIP you send and rename the .zip file extension so it doesn't get spam blocked.  Then we'll have a look to see what's causing it with that, and use it to ensure any changes we make fix the problem for you.


Actipro Software Support

Posted 6 years ago by Darcy Davidson
Avatar

Thanks, sample project sent to support email.

Answer - Posted 6 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Thanks for the sample.  It took a while because VS didn't provide much to go on, but we narrowed it down a Style we set on the TextBox in the value template so that it's ContextMenu has a SelectAll option.  Normal WPF TextBox context menus don't have a "Select All" menu item and we wanted to ensure our editors had one. 

To do this, we effectively set a ContextMenu instance on that embedded TextBox via a Style.Setter.  While it normally works great, it seems to be bad in this case because of the multiple threads and the ContextMenu Setter fails when on a different thread than the first UI thread.  Unfortunately there doesn't seem to be a way to alter the default on-the-fly context menu that TextBox generates, other than to specifically set a ContextMenu instance.

To work around it for most properties, you'd have to set the PropertyGrid.DefaultStringValueTemplate property to:

<DataTemplate>
	<TextBox Text="{Binding ValueAsString, Mode=TwoWay, ValidatesOnExceptions=True, ValidatesOnDataErrors=True, NotifyOnValidationError=True, Converter={StaticResource NoOpConverter}}" 
				IsReadOnly="{Binding IsReadOnly}" Style="{StaticResource {x:Static themes:SharedResourceKeys.EmbeddedTextBoxStyleKey}}"
				/>
</DataTemplate>

The only change in the above from the default is the Style property going right to the base Style instead of the one that set the ContextMenu.

The DefaultBrushValueTemplate, DefaultColorValueTemplate, and DefaultExtendedStringValueTemplate properties are also affected but those use more complex DataTemplates.  We can send those to you offline (via the ticket system) if you use Brush, Color, or extended string properties.  It looks like the edit boxes in our Editors product also do the same thing with setting the ContextMenu in a Style.Setter.

We had to spend a while looking for a true workaround since it's not possible to intercept the built-in TextBox context menu and other workarounds we thought of had various drawbacks.  I think we finally have a good workaround ready to go for the next build now though, and it works with your sample scenario.


Actipro Software Support

Posted 6 years ago by Darcy Davidson
Avatar

Your team provides the best support of anybody we deal with.  Thanks!

Posted 6 years ago by Darcy Davidson
Avatar

I am back to this.  The latest release solved the issues noted above, but I have now encountered two new cases.  One of the call stacks is informative, and is related to the Charting control which I am currently evaluating.  The other call stack is not very informative.  It seems to be related to the Int64EditBox and the TimeSpanEditBox, as I cannot reproduce the issue if I remove these two controls.  I also cannot reproduce if I remove theming.  Call stacks for each case follow.  Thanks.

at System.Windows.Threading.Dispatcher.VerifyAccess()
at System.Windows.DependencyObject.GetValue(DependencyProperty dp)
at ActiproSoftware.Windows.Controls.Charts.Primitives.SeriesBase.get_ItemsSource()
at ActiproSoftware.Windows.Controls.Charts.Primitives.XYSeriesBase.GetItemsSourceAsEnumerable()
at ActiproSoftware.Windows.Controls.Charts.Primitives.XYSeriesBase.GetElementType()
at ActiproSoftware.Windows.Controls.Charts.Primitives.XYSeriesBase.GetXPathResolver()
at ActiproSoftware.Windows.Controls.Charts.Primitives.XYSeriesBase.GetXType()
at ActiproSoftware.Windows.Controls.Charts.Primitives.AxisPlotterProvider.#och(XYSeriesBase #4Rf)
at ActiproSoftware.Windows.Controls.Charts.Primitives.AxisPlotterProvider.#pch()
at ActiproSoftware.Windows.Controls.Charts.Primitives.AxisPlotterProvider.Refresh()
at ActiproSoftware.Windows.Controls.Charts.Primitives.XYChartPlotter.#Wgh()
at ActiproSoftware.Windows.Controls.Charts.Primitives.XYChartPlotter.#Kwh(Size #Nvh)
at ActiproSoftware.Windows.Controls.Charts.Primitives.ChartPanel.MeasureOverride(Size availableSize)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.Border.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.Control.MeasureOverride(Size constraint)
at ActiproSoftware.Windows.Controls.Charts.XYChart.MeasureOverride(Size availableSize)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.ContextLayoutManager.UpdateLayout()
at System.Windows.ContextLayoutManager.UpdateLayoutCallback(Object arg)
at System.Windows.Media.MediaContext.FireInvokeOnRenderCallbacks()
at System.Windows.Media.MediaContext.RenderMessageHandlerCore(Object resizedCompositionTarget)
at System.Windows.Media.MediaContext.RenderMessageHandler(Object resizedCompositionTarget)
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.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 MS.Internal.CulturePreservingExecutionContext.Run(CulturePreservingExecutionContext 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 CS_DriverBaseWPF.Startup._Lambda$__30-0() in C:\dev-vso\Cameleon-Dev\Common\CS_DriverBaseWPF\Startup.vb:line 134
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.Threading.ThreadHelper.ThreadStart()

 

at System.Windows.Threading.Dispatcher.VerifyAccess()
at System.Windows.FrameworkTemplate.Seal()
at System.Windows.StyleHelper.UpdateTemplateCache(FrameworkElement fe, FrameworkTemplate oldTemplate, FrameworkTemplate newTemplate, DependencyProperty templateProperty)
at System.Windows.Controls.ContentPresenter.OnTemplateChanged(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, Boolean coerceWithCurrentValue, OperationType operationType)
at System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType, Boolean isInternal)
at System.Windows.Controls.ContentPresenter.EnsureTemplate()
at System.Windows.Controls.ContentPresenter.OnPreApplyTemplate()
at System.Windows.FrameworkElement.ApplyTemplate()
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.Grid.MeasureCell(Int32 cell, Boolean forceInfinityV)
at System.Windows.Controls.Grid.MeasureCellsGroup(Int32 cellsHead, Size referenceSize, Boolean ignoreDesiredSizeU, Boolean forceInfinityV, Boolean& hasDesiredSizeUChanged)
at System.Windows.Controls.Grid.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.Border.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.Control.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at ActiproSoftware.Windows.Controls.Grids.Primitives.TreeListViewRowPanelBase.#Gzj(Size #3se, TreeListViewItem #cwf, Int32 #Czj, FrameworkElement #Dzj, FrameworkElement #QDj)
at ActiproSoftware.Windows.Controls.Grids.Primitives.TreeListViewItemRowPanel.MeasureOverride(Size availableSize)
at ActiproSoftware.Windows.Controls.Grids.Primitives.PropertyGridItemRowPanel.MeasureOverride(Size availableSize)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.Border.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.Control.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.VirtualizingStackPanel.MeasureChild(IItemContainerGenerator& generator, IContainItemStorage& itemStorageProvider, IContainItemStorage& parentItemStorageProvider, Object& parentItem, Boolean& hasUniformOrAverageContainerSizeBeenSet, Double& computedUniformOrAverageContainerSize, Double& computedUniformOrAverageContainerPixelSize, Boolean& computedAreContainersUniformlySized, IList& items, Object& item, IList& children, Int32& childIndex, Boolean& visualOrderChanged, Boolean& isHorizontal, Size& childConstraint, Rect& viewport, VirtualizationCacheLength& cacheSize, VirtualizationCacheLengthUnit& cacheUnit, Boolean& foundFirstItemInViewport, Double& firstItemInViewportOffset, Size& stackPixelSize, Size& stackPixelSizeInViewport, Size& stackPixelSizeInCacheBeforeViewport, Size& stackPixelSizeInCacheAfterViewport, Size& stackLogicalSize, Size& stackLogicalSizeInViewport, Size& stackLogicalSizeInCacheBeforeViewport, Size& stackLogicalSizeInCacheAfterViewport, Boolean& mustDisableVirtualization, Boolean isBeforeFirstItem, Boolean isAfterFirstItem, Boolean isAfterLastItem, Boolean skipActualMeasure, Boolean skipGeneration, Boolean& hasBringIntoViewContainerBeenMeasured, Boolean& hasVirtualizingChildren)
at System.Windows.Controls.VirtualizingStackPanel.MeasureOverrideImpl(Size constraint, Nullable'1& lastPageSafeOffset, List'1& previouslyMeasuredOffsets, Nullable'1& lastPagePixelSize, Boolean remeasure)
at System.Windows.Controls.VirtualizingStackPanel.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.ContextLayoutManager.UpdateLayout()
at System.Windows.ContextLayoutManager.UpdateLayoutCallback(Object arg)
at System.Windows.Media.MediaContext.FireInvokeOnRenderCallbacks()
at System.Windows.Media.MediaContext.RenderMessageHandlerCore(Object resizedCompositionTarget)
at System.Windows.Media.MediaContext.RenderMessageHandler(Object resizedCompositionTarget)
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.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 MS.Internal.CulturePreservingExecutionContext.Run(CulturePreservingExecutionContext 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 CS_DriverBaseWPF.Startup._Lambda$__30-0() in C:\dev-vso\Cameleon-Dev\Common\CS_DriverBaseWPF\Startup.vb:line 134
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.Threading.ThreadHelper.ThreadStart()

Posted 6 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hello,

Can you send our support address an updated sample project that shows both these things so we can debug with that and see what's possibly causing it?  Please remember to reference this thread in your email, exclude any bin/obj folders from the ZIP you send, and rename the .zip file extension so it doesn't get spam blocked.  Thanks!


Actipro Software Support

Posted 6 years ago by Darcy Davidson
Avatar

I have sent a sample that reproduces the chart crash.  As for the other crash, it is not immediately reproducible in a sample, so it might take me a few days to whittle it down.

The latest build of this product (v24.1.1) was released 1 month ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.