InvalidOperationException when opening ToolWindow while editing DataGrid values

Docking/MDI for WPF Forum

The latest build of this product (v25.1.1) was released 3 months ago, which was before this thread was created.
Posted 7 days ago by DRohr
Version: 24.1.1
Platform: .NET 8
Environment: Windows 11 (64-bit)
Avatar

Dear ActiPro,

We're currently dealing with an issue that causes our application to crash when opening the ToolWindow (Ctrl+Tab) while editing a DataGrid cell. This can be reproduced using the code example below (basic WPF application containing an App and a MainWindow):

<Window x:Class="ActiProDataGridCrash.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:docking="http://schemas.actiprosoftware.com/winfx/xaml/docking"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <DockPanel>
        <docking:DockSite x:Name="DockSite">
            <docking:Workspace>
                <docking:TabbedMdiHost>
                    <docking:TabbedMdiContainer x:Name="MdiContainer" />
                </docking:TabbedMdiHost>
            </docking:Workspace>
        </docking:DockSite>
    </DockPanel>
</Window>
using ActiproSoftware.Windows.Controls.Docking;
using System.Windows;
using System.Windows.Controls;

namespace ActiProDataGridCrash {
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window {
        public MainWindow() {
            InitializeComponent();
            InitializeDataGrid();
        }

        private void InitializeDataGrid() {
            var dataGrid = new DataGrid {
                ItemsSource = new List<DataGridItem> {
                    new("A1", "B1"),
                    new("A2", "B2")
                }
            };

            var document = new DocumentWindow(DockSite) {
                Content = dataGrid,
                IsTabStop = false,
                DataContext = dataGrid,
                Focusable = true,
                Title = "DataGrid"
            };

            document.Attach(MdiContainer);
        }
    }

    public record DataGridItem(string A, string B);
}

We're currently using ActiPro version 24.1.3, but could also reproduce this exception (using the example above) in version 24.1.5.

Thank you very much in advance!

Comments (5)

Posted 7 days ago by DRohr
Avatar

A small but possibly important addendum: This issue does not occur if the tool window has been opened at least once before opening it again while editing the DataGrid cell.

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

Hello,

I'm sorry you're having trouble.  I tried to reproduce this in our latest codebase but was unable to.  I believe the DataGridItem class in your code is a custom class so I replaced it with Tuple<string, string> instead.  When I run the sample, there is no exception and the document opens with the four DataGrid cells visible.

On a side note, you never want to name a docking container like TabbedMdiContainer.  Containers are transient and naming it will pin it in memory.  Instead you can remove that container from your XAML and just do document.IsOpen = true in your code-behind.  That won't affect your original issue, but I wanted to mention it as a best practice.

If you'd like us to look into it any further, please provide some details on the exception you are getting (type, message, stack trace, etc.) and send our support address a new simple sample project showing it happening.  Then we can debug with that.  In your email, mention this thread and be sure to exclude the bin/obj folders from the .zip you send so it doesn't get spam blocked.  Thanks!


Actipro Software Support

Posted 6 days ago by DRohr
Avatar

Thank you for looking into it! The DataGridItem (which I included at the end of the C# code sample, but maybe was a bit hard to spot) is a basic record with two editable field values:

public record DataGridItem(string A, string B);

I noticed that sadly, the error cannot reproduced with a Tuple<string, string> because it is read-only. After replacing the Tuple with the DataGridItem record, please use the following steps to reproduce the exception:

  1. Launch the sample application. This will open the window with the 4 editable DataGrid cells as described by you.
  2. Double click on one of the 4 DataGrid cells (e.g., A1) to start edit mode. You can change the value of the DataGrid cell by typing to verify that you're in edit mode. Do not commit your changes (by pressing enter or clicking on a different cell) yet.
  3. While still in edit mode, press Ctrl+Tab to open the tool window. This will crash the application. Please note that the tool window opens as expected if it has already been opened before entering cell edit mode and the exception will not occur.

If this does not work, I'll be happy to create a support case via e-mail as suggested by you.

Posted 5 days ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hello,

Thanks for the steps to recreate it.  I missed the DataGridItem when copying the code snippets out into a sample.  When I follow the steps, I do see this exception occur when attempting to focus an item in the StandardSwitcher that is displayed:

System.InvalidOperationException: 'Cannot perform this operation while dispatcher processing is suspended.'

That is very odd and we haven't seen that before.  It seems to be DataGrid's internal logic not liking that we are focusing another control, which is then triggering a commit of the DataGrid cell's TextBox edit.  Here's the stack trace, with our StandardSwitcherItem.Focus() call at the bottom:

 	WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame frame)	Unknown
 	WindowsBase.dll!System.Windows.Threading.DispatcherOperation.Wait(System.TimeSpan timeout)	Unknown
 	WindowsBase.dll!System.Windows.Threading.Dispatcher.InvokeImpl(System.Windows.Threading.DispatcherOperation operation, System.Threading.CancellationToken cancellationToken, System.TimeSpan timeout)	Unknown
 	WindowsBase.dll!System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority priority, System.TimeSpan timeout, System.Delegate method, object args, int numArgs)	Unknown
 	WindowsBase.dll!System.Windows.Threading.Dispatcher.Invoke(System.Delegate method, System.Windows.Threading.DispatcherPriority priority, object[] args)	Unknown
 	PresentationFramework.dll!System.Windows.Controls.DataGrid.OnExecutedCommitEdit(System.Windows.Input.ExecutedRoutedEventArgs e)	Unknown
 	PresentationCore.dll!System.Windows.Input.CommandBinding.OnExecuted(object sender, System.Windows.Input.ExecutedRoutedEventArgs e)	Unknown
 	PresentationCore.dll!System.Windows.Input.CommandManager.FindCommandBinding(object sender, System.Windows.RoutedEventArgs e, System.Windows.Input.ICommand command, bool execute)	Unknown
 	PresentationCore.dll!System.Windows.Input.CommandManager.OnExecuted(object sender, System.Windows.Input.ExecutedRoutedEventArgs e)	Unknown
 	PresentationCore.dll!System.Windows.RoutedEventArgs.InvokeHandler(System.Delegate handler, object target)	Unknown
 	PresentationCore.dll!System.Windows.EventRoute.InvokeHandlersImpl(object source, System.Windows.RoutedEventArgs args, bool reRaised)	Unknown
 	PresentationCore.dll!System.Windows.UIElement.RaiseEventImpl(System.Windows.DependencyObject sender, System.Windows.RoutedEventArgs args)	Unknown
 	PresentationCore.dll!System.Windows.Input.RoutedCommand.ExecuteImpl(object parameter, System.Windows.IInputElement target, bool userInitiated)	Unknown
 	PresentationCore.dll!System.Windows.Input.RoutedCommand.Execute(object parameter, System.Windows.IInputElement target)	Unknown
 	PresentationFramework.dll!System.Windows.Controls.DataGrid.EndEdit(System.Windows.Input.RoutedCommand command, System.Windows.Controls.DataGridCell cellContainer, System.Windows.Controls.DataGridEditingUnit editingUnit, bool exitEditMode)	Unknown
 	PresentationFramework.dll!System.Windows.Controls.DataGrid.OnCurrentCellChanged(System.Windows.DependencyObject d, System.Windows.DependencyPropertyChangedEventArgs e)	Unknown
 	PresentationFramework.dll!System.Windows.FrameworkElement.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e)	Unknown
 	WindowsBase.dll!System.Windows.DependencyObject.NotifyPropertyChange(System.Windows.DependencyPropertyChangedEventArgs args)	Unknown
 	WindowsBase.dll!System.Windows.DependencyObject.UpdateEffectiveValue(System.Windows.EntryIndex entryIndex, System.Windows.DependencyProperty dp, System.Windows.PropertyMetadata metadata, System.Windows.EffectiveValueEntry oldEntry, ref System.Windows.EffectiveValueEntry newEntry, bool coerceWithDeferredReference, bool coerceWithCurrentValue, System.Windows.OperationType operationType)	Unknown
 	WindowsBase.dll!System.Windows.DependencyObject.SetValueCommon(System.Windows.DependencyProperty dp, object value, System.Windows.PropertyMetadata metadata, bool coerceWithDeferredReference, bool coerceWithCurrentValue, System.Windows.OperationType operationType, bool isInternal)	Unknown
 	WindowsBase.dll!System.Windows.DependencyObject.SetCurrentValueInternal(System.Windows.DependencyProperty dp, object value)	Unknown
 	PresentationFramework.dll!System.Windows.Controls.DataGrid.CurrentCellContainer.set(System.Windows.Controls.DataGridCell value)	Unknown
 	PresentationFramework.dll!System.Windows.Controls.DataGrid.FocusedCell.set(System.Windows.Controls.DataGridCell value)	Unknown
 	PresentationCore.dll!System.Windows.EventRoute.InvokeHandlersImpl(object source, System.Windows.RoutedEventArgs args, bool reRaised)	Unknown
 	PresentationCore.dll!System.Windows.UIElement.RaiseEventImpl(System.Windows.DependencyObject sender, System.Windows.RoutedEventArgs args)	Unknown
 	PresentationFramework.dll!System.Windows.Controls.Primitives.TextBoxBase.OnLostFocus(System.Windows.RoutedEventArgs e)	Unknown
 	PresentationFramework.dll!System.Windows.FrameworkElement.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e)	Unknown
 	PresentationFramework.dll!System.Windows.Controls.TextBox.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e)	Unknown
 	WindowsBase.dll!System.Windows.DependencyObject.NotifyPropertyChange(System.Windows.DependencyPropertyChangedEventArgs args)	Unknown
 	WindowsBase.dll!System.Windows.DependencyObject.UpdateEffectiveValue(System.Windows.EntryIndex entryIndex, System.Windows.DependencyProperty dp, System.Windows.PropertyMetadata metadata, System.Windows.EffectiveValueEntry oldEntry, ref System.Windows.EffectiveValueEntry newEntry, bool coerceWithDeferredReference, bool coerceWithCurrentValue, System.Windows.OperationType operationType)	Unknown
 	WindowsBase.dll!System.Windows.DependencyObject.ClearValueCommon(System.Windows.EntryIndex entryIndex, System.Windows.DependencyProperty dp, System.Windows.PropertyMetadata metadata)	Unknown
 	WindowsBase.dll!System.Windows.DependencyObject.ClearValue(System.Windows.DependencyPropertyKey key)	Unknown
 	PresentationCore.dll!System.Windows.Input.FocusManager.OnFocusedElementChanged(System.Windows.DependencyObject d, System.Windows.DependencyPropertyChangedEventArgs e)	Unknown
 	PresentationFramework.dll!System.Windows.FrameworkElement.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e)	Unknown
 	WindowsBase.dll!System.Windows.DependencyObject.NotifyPropertyChange(System.Windows.DependencyPropertyChangedEventArgs args)	Unknown
 	WindowsBase.dll!System.Windows.DependencyObject.UpdateEffectiveValue(System.Windows.EntryIndex entryIndex, System.Windows.DependencyProperty dp, System.Windows.PropertyMetadata metadata, System.Windows.EffectiveValueEntry oldEntry, ref System.Windows.EffectiveValueEntry newEntry, bool coerceWithDeferredReference, bool coerceWithCurrentValue, System.Windows.OperationType operationType)	Unknown
 	WindowsBase.dll!System.Windows.DependencyObject.SetValueCommon(System.Windows.DependencyProperty dp, object value, System.Windows.PropertyMetadata metadata, bool coerceWithDeferredReference, bool coerceWithCurrentValue, System.Windows.OperationType operationType, bool isInternal)	Unknown
 	WindowsBase.dll!System.Windows.DependencyObject.SetValue(System.Windows.DependencyProperty dp, object value)	Unknown
 	PresentationFramework.dll!System.Windows.Input.KeyboardNavigation.UpdateFocusedElement(System.Windows.DependencyObject focusTarget)	Unknown
 	PresentationFramework.dll!System.Windows.FrameworkElement.OnGotKeyboardFocus(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e)	Unknown
 	PresentationCore.dll!System.Windows.RoutedEventArgs.InvokeHandler(System.Delegate handler, object target)	Unknown
 	PresentationCore.dll!System.Windows.EventRoute.InvokeHandlersImpl(object source, System.Windows.RoutedEventArgs args, bool reRaised)	Unknown
 	PresentationCore.dll!System.Windows.UIElement.RaiseEventImpl(System.Windows.DependencyObject sender, System.Windows.RoutedEventArgs args)	Unknown
 	PresentationCore.dll!System.Windows.UIElement.RaiseTrustedEvent(System.Windows.RoutedEventArgs args)	Unknown
 	PresentationCore.dll!System.Windows.Input.InputManager.ProcessStagingArea()	Unknown
 	PresentationCore.dll!System.Windows.Input.KeyboardDevice.ChangeFocus(System.Windows.DependencyObject focus, int timestamp)	Unknown
 	PresentationCore.dll!System.Windows.Input.KeyboardDevice.Focus(System.Windows.DependencyObject focus, bool askOld, bool askNew, bool forceToNullIfFailed)	Unknown
 	PresentationCore.dll!System.Windows.Input.KeyboardDevice.Focus(System.Windows.IInputElement element)	Unknown
 	PresentationCore.dll!System.Windows.UIElement.Focus()	Unknown

It feels like a possible bug in DataGrid since all we're doing here is focusing another control programmatically.  That being said, we found that if we did a Dispatcher.BeginInvoke on the Focus call, it works around the issue.  We'll implement that for the next release.


Actipro Software Support

Posted 5 days ago by DRohr
Avatar

I'm glad you could reproduce the issue and already work out a possible solution. As you said, it seems like the DataGrid cell commit triggered by the focus call can't handle this kind of situation properly. Using Dispatcher.BeginInvoke sounds like a good and safe workaround to me.

Thank you again for analyzing and resolving this issue so quickly, we're looking forward to your next release!

Add Comment

Please log in to a validated account to post comments.