wpf.net-corefixeddocument

FixedPage causes ArgumentNullException when I mouse over too quickly


I am encountering a situation in which WPF successfully creates an Image element on one of my views but appears to take a second or two to properly set up the logical parent of that element. If I mouse over in that time window, my application crashes due to an ArgumentNullException from the LogicalTreeHelper.

If I wait for the second or so, everything works fine and there are no problems. But I can hardly ask my users to do that.

Note that this only happens when my UserControl, is housed in FixedPage in a FixedDocument shown by a DocumentViewer. When I use the same control in other contexts, (away from FixedDocument et al), it works without issue.

Does anyone know anything about this "window" or what might be the cause of it?

This is the code in FixedPage.cs that's trying to get the parent of my item. I've added comments.

    internal int[] _CreateChildIndex(DependencyObject e)
    {
        ArrayList childPath = new ArrayList();
        while (e != this)
        { 
            // *** 'e' is an Image control, created by my view ***
            // *** This value 'parent' is NULL if I mouse over too quickly ***

            DependencyObject parent = LogicalTreeHelper.GetParent(e);
            int childIndex = -1;
            if (parent is FixedPage)
            {
                childIndex = ((FixedPage)parent).Children.IndexOf((UIElement)e);
            }
            else if (parent is Canvas)
            {
                childIndex = ((Canvas)parent).Children.IndexOf((UIElement)e);
            }
            else
            {
                // *** Because 'parent' is null, we end up here.  This call throws ***
                IEnumerable currentChildrens = LogicalTreeHelper.GetChildren(parent);

Here is the code that throws

public static IEnumerable GetChildren(DependencyObject current)
{
    if (current == null)
    {
        throw new ArgumentNullException("current"); 
    }

This is the call stack from the mouseover. None of my code in here except the App.Run method.

System.Windows.LogicalTreeHelper.GetChildren    C#
System.Windows.Documents.FixedPage._CreateChildIndex    C#
System.Windows.Documents.FixedTextView.GetTextPositionFromPoint C#
MS.Internal.Documents.TextViewBase.System.Windows.Documents.ITextView.GetTextPositionFromPoint  C#
MS.Internal.Documents.DocumentPageTextView.GetTextPositionFromPoint C#
MS.Internal.Documents.MultiPageTextView.GetTextPositionFromPoint    C#
MS.Internal.Documents.TextViewBase.System.Windows.Documents.ITextView.GetTextPositionFromPoint  C#
System.Windows.Documents.TextEditorMouse.IsPointWithinInteractiveArea   C#
System.Windows.Documents.TextEditorMouse.OnQueryCursor  C#
System.Windows.RoutedEventArgs.InvokeHandler    C#
System.Windows.EventRoute.InvokeHandlersImpl    C#
System.Windows.UIElement.RaiseEventImpl C#
System.Windows.UIElement.RaiseTrustedEvent  C#
System.Windows.Input.InputManager.ProcessStagingArea    C#
System.Windows.Input.MouseDevice.UpdateCursorPrivate    C#
System.Windows.Input.MouseDevice.PostProcessInput   C#
System.Windows.Input.InputManager.RaiseProcessInputEventHandlers    C#
System.Windows.Input.InputManager.ProcessStagingArea    C#
System.Windows.Input.InputProviderSite.ReportInput  C#
System.Windows.Interop.HwndMouseInputProvider.ReportInput   C#
System.Windows.Interop.HwndMouseInputProvider.FilterMessage C#
System.Windows.Interop.HwndSource.InputFilterMessage    C#
MS.Win32.HwndWrapper.WndProc    C#
MS.Win32.HwndSubclass.DispatcherCallbackOperation   C#
System.Windows.Threading.ExceptionWrapper.InternalRealCall  C#
System.Windows.Threading.ExceptionWrapper.TryCatchWhen  C#
System.Windows.Threading.Dispatcher.LegacyInvokeImpl    C#
MS.Win32.HwndSubclass.SubclassWndProc   C#
[Native to Managed Transition]  
UserCallWinProcCheckWow Unknown
DispatchMessageWorker   Unknown
[Managed to Native Transition]  
System.Windows.Threading.Dispatcher.PushFrameImpl   C#
System.Windows.Threading.Dispatcher.PushFrame   C#
System.Windows.Threading.Dispatcher.Run C#
System.Windows.Application.RunDispatcher    C#
System.Windows.Application.RunInternal  C#
System.Windows.Application.Run  C#
MyCompany.App.Main  Unknown   
[Native to Managed Transition]  
coreclr_t::execute_assembly C++
run_app_for_context C++
run_app C++
corehost_main   C++
execute_app C++
`anonymous namespace'::read_config_and_execute  C++
fx_muxer_t::handle_exec_host_command    C++
fx_muxer_t::execute C++
hostfxr_main_startupinfo    C++
exe_start   C++
wmain   C++
[Inline Frame] invoke_main  C++
__scrt_common_main_seh  C++
BaseThreadInitThunk()  Unknown
RtlUserThreadStart()   Unknown

Below is a very much abbreviated version of my view (a UserControl) with the ItemsControl that creates the Image element

<UserControl
    x:Class="Core.Views.LayerView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:cv="clr-namespace:Core.View"
    >
    <Canvas>
        <ItemsControl ItemsSource="MyItems">
            <ItemsControl.Resources>
                <DataTemplate x:Key="PathOutputTemplate" DataType="{x:Type ShapeVm}">
                    <Path Stroke="Yellow" StrokeThickness="6" Data={Binding Geometry} />
                </DataTemplate>
                <DataTemplate x:Key="ImageOutputTemplate" DataType={x:Type ImageOutputVm}>
                    <Image Source="{Binding ImageSource}"/>
                </DataTemplate>
            </ItemsControl.Resources>
            <ItemsControl.ItemTemplateSelector>
              <cv:OutputTemplateSelector
                PathTemplate="{StaticResource PathOutputTemplate}"
                ImageTemplate="{StaticResource ImageOutputTemplate}"
                />
            </ItemsControl.ItemTemplateSelector>
        </ItemsControl>
    </Canvas>
</UserControl>

Solution

  • I encountered this problem today when creating a new report and wanted to post my workaround for any future developer that hits this issue. This is really a workaround and not a fix for the underlying issue as I didn't have time to dig deeper.

    The workaround consisted of adding a Border control with Transparent background over my image controls, essentially preventing any mouse events from triggering below:

    <Grid>
        <My-content-that-must-not-be-moused-over/>
        <Border Background="Transparent"></Border>
    <Grid>