Hi,
Our customer encountered exception in xamSpreadsheet control. Based on description customer loaded this control view left it opened. After an hour or more he tried to access same application control and got exception with fallowing stack trace:
System.NotSupportedException: Workbooks can not have multiple owners bei Infragistics.Documents.Excel.Workbook.RegisterOwner(IWorkbookOwner owner) bei Infragistics.Controls.Grids.Core.Spreadsheet.OnWorkbookChanged(Workbook oldWorkbook, Workbook newWorkbook) bei Infragistics.Controls.Grids.Core.Spreadsheet.set_Workbook(Workbook value) bei Infragistics.Controls.Grids.XamSpreadsheet.<>c.<.cctor>b__365_42(XamSpreadsheet c, Object v) bei Infragistics.Controls.Grids.XamSpreadsheet.SetInnerProperty[T](T d, Object newValue, Action`2 setter, String propertyName) bei Infragistics.Controls.Grids.XamSpreadsheet.<>c.<.cctor>b__365_41(DependencyObject d, DependencyPropertyChangedEventArgs e) bei System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e) bei System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e) bei System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args) bei System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType) bei System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType, Boolean isInternal) bei System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value) bei Infragistics.Controls.Grids.XamSpreadsheet.set_Workbook(Workbook value) bei EafClient.Editor.Core.Workbooks.SpreadsheetControl.SpreadsheetWorkbook.ApplyTo(XamSpreadsheet spreadsheetControl) in D:\TfsBuildAgent2017\_work\278\s\Source\Implementation\EafClient.Editor.Core\Workbooks\SpreadsheetControl\SpreadsheetWorkbook.cs:Zeile 97. bei EafClient.Editor.CellAutomation.EquipmentDictionary.Views.SpecificBehaviors.EquipmentDictionaryWorkbookBehavior.WorkbookDataChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) in D:\TfsBuildAgent2017\_work\278\s\Source\Implementation\EafClient.Editor.CellAutomation\EquipmentDictionary\Views\SpecificBehaviors\EquipmentDictionaryWorkbookBehavior.cs:Zeile 155. bei System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e) bei System.Windows.Freezable.OnPropertyChanged(DependencyPropertyChangedEventArgs e) bei System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args) bei System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType) bei System.Windows.DependencyObject.InvalidateProperty(DependencyProperty dp, Boolean preserveCurrentValue) bei System.Windows.Data.BindingExpressionBase.Invalidate(Boolean isASubPropertyChange) bei System.Windows.Data.BindingExpression.TransferValue(Object newValue, Boolean isASubPropertyChange) bei System.Windows.Data.BindingExpression.Activate(Object item) bei System.Windows.Data.BindingExpression.AttachToContext(AttachAttempt attempt) bei System.Windows.Data.BindingExpression.MS.Internal.Data.IDataBindEngineClient.AttachToContext(Boolean lastChance) bei MS.Internal.Data.DataBindEngine.Task.Run(Boolean lastChance) bei MS.Internal.Data.DataBindEngine.Run(Object arg) bei MS.Internal.Data.DataBindEngine.OnLayoutUpdated(Object sender, EventArgs e) bei System.Windows.ContextLayoutManager.fireLayoutUpdateEvent() bei System.Windows.ContextLayoutManager.UpdateLayout() bei System.Windows.UIElement.UpdateLayout() bei Infragistics.Windows.DataPresenter.GridUtilities.ProcessAsyncInvalidationsImpl() bei Infragistics.Windows.DataPresenter.GridUtilities.ProcessAsyncInvalidations()
Our code involved in stack trace just monitoring changes and then reapplying back the workbook. Here is line 155 from our code with ApplyTo:
var behaviorInstance = d as EquipmentDictionaryWorkbookBehavior; (e.NewValue as IWorkbook)?.ApplyTo(behaviorInstance?.Spreadsheet);
And then setting back (line 97 in SpreadsheetWorkbook class):
public void ApplyTo(XamSpreadsheet spreadsheetControl) => spreadsheetControl.Workbook = mWorkbook;
The workbook behavior is grabbing active spreadsheet:
private XamSpreadsheet Spreadsheet => AssociatedObject.SpreadSheet;book;
What could cause this error if we use only 1 control in our application? No other user should be able to access this application during away time.
I don't know if it could be related, but this is Virtual PC and during this time auto lock of windows is enabled.
Hello Tomas,
I have been investigating into the behavior you are seeing, and the exception you are seeing is being intentionally thrown from our internal code. This happens if the owner of the Workbook is not null when the RegisterOwner method is hit.
I would like to get a bit more of an idea of how you are reproducing this behavior. You mentioned that you are using Virtual PC and auto-lock of Windows is enabled. I am curious if you run your application, lock your screen, and then unlock it if this behavior happens? I have personally tried this on my end, and it does not happen, but I am also not in a virtual environment, and perhaps that is the missing piece.
Please let me know if you have any other questions or concerns on this matter.
Hi Andrew,
I do have virtual PC and tried same behavior multiple times but never seen this error. I've asked user for more details on steps and memory dump file if possible which might be useful. Since it is vacation time it may take a week to get a reply. I will respond once I get more details.
After getting additional details on this topic I am able to reproduce easy same problem just by using Remote Desktop application. I've tried to create a test sample with single attached behavior but it did not failed so far so something else is involved in this event. From additional logging I was able to figure out that used RegionManager with XamDockManager might be involved in this event chain which is missing in test application.
Additionally, as I observed before it really creates new instance of SpreadSheet control or existing has been reset since worksheets disappearing but active sheet's data content remains shown. This is very unusual behavior and I am not sure how I could track this change so far. The investigation continues and once I will be able to reproduce the problem in test application I will upload test application.
I will post update later.
I have been running a XamSpreadsheet application against our internal source code to see what the process is for the RegisterOwner issue that you are seeing, and it appears that when the XamSpreadsheet’s Workbook property changes, we check for an old workbook, and if one exists, clear its Undo history and unregister its owner. Then, we register an owner for the new one. An exception is thrown if the cached owner for the Workbook already exists, and that is the only way that this exception happens.
The “owner” that is created in this case is an instance of WeakWorkbookOwner, and it is used primarily in transaction histories for undo operations in the Workbook for usage within the XamSpreadsheet.
The XamDockManager part of this made me think of what could potentially cause this, and I tested the scenario in which there are multiple instances of the XamSpreadsheet with the same instance of the Workbook assigned. In doing so, I reproduced the exception you are seeing, which leads me to believe that somewhere in your application, a new instance of XamSpreadsheet is getting created and has the same Workbook assigned to it, which is not a supported action. Perhaps this information will help you to track down the exception in your application?
Can you provide your sample application? I would like to try to adapt to my known scenario with single scenario of this control and check if problem still persist on RDP session.
During analysis I noticed that other views reloaded same way as this one but they don't have such a side effects like spread sheet control. Based on stack trace in my very first called view no other our views are involved, thus still causing problem understanding the problem. The stack trace is quite long and it involves mainly Windows calls however few related to Infragistics:
at EafClient.Editor.CellAutomation.EquipmentDictionary.Views.EquipmentDictionaryEditorView..ctor() in D:\_PROJECTS\EAF_MAINT\EAF Mango\v3.x_Maint\Implementation\EafClient.Editor.CellAutomation\EquipmentDictionary\Views\EquipmentDictionaryEditorView.xaml.cs:line 23 at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) at System.Activator.CreateInstance(Type type, Boolean nonPublic) at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, StackCrawlMark& stackMark) at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes) at System.Activator.CreateInstance(Type type, Object[] args) ... at Infragistics.Windows.DockManager.SplitPane.MeasureOverride(Size availableSize) at System.Windows.FrameworkElement.MeasureCore(Size availableSize) at System.Windows.UIElement.Measure(Size availableSize) at Infragistics.Windows.DockManager.DocumentContentHostPanel.MeasureOverride(Size availableSize) at System.Windows.FrameworkElement.MeasureCore(Size availableSize) ... at System.Windows.UIElement.Measure(Size availableSize) at Infragistics.Windows.DockManager.DockManagerPanel.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.UIElement.UpdateLayout() at Infragistics.Windows.DataPresenter.GridUtilities.ProcessAsyncInvalidationsImpl() at Infragistics.Windows.DataPresenter.GridUtilities.ProcessAsyncInvalidations() at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor) at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments) ....
By the way, have you tried your sample application using fallowing steps:
The sample project I tried did not use a XamDockManager or a remote desktop session, as I was awaiting a more concrete set of reproduction steps from your end or a sample project that reproduces it.
Your mention of the XamDockManager a couple of updates ago only sparked the idea in my mind that you may have multiple instances of the XamSpreadsheet bound to the same instance of the Excel Workbook in this case, and so to test that, I simply put two XamSpreadsheet controls into a WPF Window and assigned a single Workbook to both of them. This reproduced the exception you are seeing, but very likely not in the same route that you are currently doing.
I am curious to know if perhaps something that you could use as a workaround in this case would be to use a flag that determines whether or not a particular Workbook has already been assigned to a XamSpreadsheet or not as this could potentially prevent your code that is assigning the Workbook to a XamSpreadsheet instance from firing again for a different XamSpreadsheet and the same Workbook?
Something that might be worth checking as well is the code-path that is followed when this exception happens. Where in your code are you trying to apply the Workbook to a XamSpreadsheet instance? For example, is it happening in a Loaded event or something along those lines?
I've tried to check the Load event on our side and it is dead end there since like I wrote before it has no more callers from our code. So can't investigate there. However, as a next step I've added logging to the DockPanel control containing the spreadsheet control which is reloaded and observed that two same instances created of same and running together during raised with event LayoutUpdated. So after session reconnect two spreadsheet controls looks like running with different hash codes while before only 1 was running.
I've tried to create sample application based on our control path but I got stuck on view display in tab page (based on this link). I am attaching my almost completed project:
SpreadsheetOwnerErrorSampleV3.zip
Please help to resolve fallowing issue: selecting "Test 1" or "Test 2" should open new tab in main region and all content is created correctly but it is not displayed in the TabGroupPane. Hopefully this simple application will reproduce the original problem on my Remote Desktop PC once this done. At the moment it is still missing one additional spreadsheet behavior which is setting saved workbook and causing original exception so I should be close to completion.
Thank you for your update on this matter. I am glad you were able to find the root cause of the issue you were seeing.
I did found a rootcuase of this weird a problem. It turned out that using UserControl type instead of ContentPresenter causing this reload problem of all child controls during reconnect of RDP session when mapping type used to resolve view based on View Model. This peace was missing in my test samples thus it did not reproduced original problem.
I found answer in this forum: https://stackoverflow.com/questions/39996682/wpf-mvvm-load-a-view-dynamically-at-runtime
We've use this way to display the content of mapped ViewModel:
<igWindows:XamTabControl TabStripPlacement="Bottom"> <igWindows:TabItemEx Header="Editor" IsSelected="{Binding Path=IsCustomEditorSelected}" Visibility="{Binding Path=CanLoadEditor, Converter={StaticResource BooleanToVisibilityConverter}}"> <igWindows:TabItemEx.Content> <UserControl Content="{Binding Path=EditorData}" /> </igWindows:TabItemEx.Content> </igWindows:TabItemEx>
But should be:
<igWindows:TabItemEx.Content> <ContentPresenter Content="{Binding Path=EditorData}" /> </igWindows:TabItemEx.Content>
Thank you very much for support on this topic.
Thank you for your update on this matter.
I am rather curious how the Workbook that is being bound to the Spreadsheets in your actual application is stored, as that could potentially offer a clue to the underlying reason that this issue is happening. As mentioned previously in this forum thread, I was able to reproduce the error you are seeing by trying to bind a single instance of a Workbook to multiple XamSpreadsheet control instances. This is something that is unsupported, and it is expected that an exception is thrown in that circumstance.
This makes me wonder if somewhere in your actual application you may be binding the same instance of a Workbook to multiple XamSpreadsheet instances, perhaps when the application is reloaded. Something you might be able to do to check this in your actual application is to print out the hash code of the Workbook and the hash code of the XamSpreadsheet that it is being assigned to just before assigning it, although this might prove to be a bit more work if you are binding the Workbook. If you find that more than one instance of a hash code shows up for a Workbook assigning to multiple different XamSpreadsheets (you can add the hash code of the spreadsheets to check this too), you can discern that it is being applied to multiple instances of XamSpreadsheets, which is an operation that – as mentioned above - is invalid.
I also have to wonder how much of this error happening and the reloading of views is reliant on the Prism implementation that you have in place. It’s worth noting that Prism is not actually an Infragistics product, and as such is not something that we provide support for.
Thanks for a hint. I found a place preventing to show the selection. For whatever reason I get loaded two main views and I still can't find rootcause of this behavior. Our original application does not behave this way and loads single window as expected. I will have to ask on stackoverflow maybe somebody could help me.
Current version still does not reproduce original problem with spreadsheet. Most likely due incomplete structure (missing 1 behavior and two xam views containing spreadsheet) but I will carry on until problem is reproduced or reason of reload is found. However, I've noticed that my list of selections ("Test 1" and "Test 2") is every time re-added on reconnect on RDP session. Entries added on Load of view so it is unclear why Load event is called on reconnect. The stack trace looks different than on spreadsheet control so not sure about that.
With regards prism we are aware and already created a work item to upgrade outdated prism assemblies. Since our application is very big and we are very busy it will take time. At the end it depends on priorities and it may change once I know which part is causing this strange behavior with reload error.
SpreadsheetOwnerErrorSampleV3_v2.zip
I have been investigating into your sample project, and this sample might explain why you are seeing the behavior you are seeing – although my inexperience with Prism cannot really give you an underlying reason as to why the behavior that is happening is happening.
Put simply, the TabGroupPane that you are adding your views to is not the one that is in your XamDockManager view. To test this, I added a Button to the page that your XamDockManager is on that checks the TabGroupPane’s GUID hash code and printed it out to the console. I did the same in the TabGroupPaneRegionAdapter.OnViewsCollectionChanged for when the views were being added to the TabGroupPane, and these GUIDs were different. This leads me to believe that the TabGroupPane being used in your TabGroupPaneRegionAdapter.OnViewsCollectionChanged is not the one that is in your XamDockManager, but where this one is, I am unsure at the moment.
With that said, I have been in conversation with Brian Lagunas – the creator of the TabGroupPaneRegionAdapter, and it appears that the version of Prism your application is currently targeting is pretty old and currently out of support. He recently updated the XamDockManager Region Adapter on GitHub to use newer versions of Prism, and you can view that here: https://github.com/brianlagunas/xamDockManager-Region-Adapter.