Map crash while disposing

8 posts, 0 answers
  1. Peter
    Peter avatar
    48 posts
    Member since:
    Oct 2016

    Posted 12 Apr Link to this post

    We've seen a crash in our application when the RadMap control is disposed. We've only seen the crash once but have been unable to reproduce. The stack trace is as follows:

    Telerik.Windows.Controls.DataVisualization : System.NullReferenceException
    Object reference not set to an instance of an object.

    at Telerik.Windows.Controls.Map.Location.PixelToLogical(RadMap mapControl, Point pixel, Boolean useTileLayer)

    at Telerik.Windows.Controls.Map.Location.PixelToLogical(RadMap mapControl, Point pixel, Boolean useTileLayer)
    at Telerik.Windows.Controls.Map.MapMouseLocationIndicator.MapControl_MouseMove(Object sender, MouseEventArgs e)
    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.RaiseTrustedEvent(RoutedEventArgs args)
    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, WindowMessage 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, 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 System.Windows.Application.RunDispatcher(Object ignore)
    at System.Windows.Application.RunInternal(Window window)
    at CNL.IPSecurityCenter.WindowsClient.App.Main()

    We're currently using version 2017.2.614.45. Looking at the Telerik code it seems like the mouse event handler for MapMouseLocationIndicator doesn't get detached when RadMap is disposed. Is it possible there's some race condition that allows a mouse event to be processed in MapMouseLocationIndicator after its RadMap property has been set to null (which does happen when RadMap is disposed)?

    Thanks
    Pete

  2. Peter
    Peter avatar
    48 posts
    Member since:
    Oct 2016

    Posted 10 May in reply to Peter Link to this post

    No update on this post since I raised it on 12th April. Would I be better raising a support ticket?

    Pete

  3. Vladimir Stoyanov
    Admin
    Vladimir Stoyanov avatar
    444 posts

    Posted 15 May Link to this post

    Hello Pete,

    Thank you for the provided stacktrace. 

    I went through our backlog, however I am afraid that we have not received reports of such an exception. With this in mind and without being able to reproduce it, it is difficult to pinpoint what could be the reason for the exception based on the stacktrace only.

    May I ask you to elaborate on the following questions? Can you share some sample xaml/code of the application's structure and mainly how the RadMap is defined? May I also ask you to elaborate on when and how is the RadMap disposed? This way I will hopefully be able to reproduce the observed behavior on my end and investigate it.

    Thank you in advance for any help you can provide.

    Regards,
    Vladimir Stoyanov
    Progress Telerik
    Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
  4. Peter
    Peter avatar
    48 posts
    Member since:
    Oct 2016

    Posted 24 Jun in reply to Vladimir Stoyanov Link to this post

    Hi Vladimir,

    It's a little difficult to explain. The user can select different maps by clicking on another control in the application. Each map they view is configured with one or more background layers (providers) that they can select from. In addition the map has several "entity" layers allowing us to configure various objects on the map (visibility for each layer can configured by the user). Some of these entity layers have dynamically changing data being updated on a dispatcher timer (see our support ticket: ID:1411532) Because the layers we need for different map providers can differ greatly, when they switch between maps we tear-down the previous map (i.e. disposing the map) and configure a new map view from scratch.

    The xaml for the map control contains the following:

    <telerik:RadMap x:Name="RadMap" IsEnabled="False"
            MiniMapExpanderVisibility="Collapsed"
            Background="{Binding MainGridBackgroundColor, Converter={StaticResource ColorToBrushConverter}}"
            MouseDragMode="Drag"
            MouseSelectionMode="RaiseEvent"
            MouseDoubleClickMode="None"
            MouseClickMode="None"
            ZoomLevel="{Binding MapZoomLevel}"
            MinZoomLevel="{Binding MinZoomLevel}"
            MaxZoomLevel="{Binding MaxZoomLevel}">
        <telerik:RadContextMenu.ContextMenu>
            <telerik:RadContextMenu x:Name="MapRadContextMenu" ItemsSource="{Binding ContextMenuViewModel.Items, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                    PlacementTarget="{Binding ElementName=RadMap}"
                                    ItemContainerStyle="{StaticResource MenuItemContainer}"/>
        </telerik:RadContextMenu.ContextMenu>
    </telerik:RadMap>
     
    <telerik:RadExpander x:Name="RadExpander" Margin="0" Padding="0"
                         HorizontalAlignment="Right"
                         VerticalAlignment="Top"
                         Style="{DynamicResource RadExpanderStyle2}" >
        <telerik:RadExpander.Header>
            <StackPanel Width="224">
                <TextBlock Height="5"/>
            </StackPanel>
        </telerik:RadExpander.Header>
        <Border BorderThickness="2" BorderBrush="#CCAAAAAA">
            <telerik:MiniMap x:Name="MiniMap" MapControl="{Binding ElementName=RadMap}" Width="256" Height="200"
                             Background="{Binding MainGridBackgroundColor, Converter={StaticResource ColorToBrushConverter}}"  Padding="0" Margin="0"/>
        </Border>
    </telerik:RadExpander>

    The providers and layers for the map are all configured in code after the map control has loaded.

    When we switch between maps the map is disposed something like this:

    public void Dispose(bool disposing)
    {
        if (disposing)
        {
            _disposed = true;
            _logger.Debug("TelerikMap: (RadMap) disposing");
            Enable(false);
            Loaded -= OnLoaded;
            Drop -= OnDrop;
            DragOver -= OnDragOver;
            DataContext = null;
            // dispose reactive extensions subscription
            _mouseMoveSubscription?.Dispose();
            _mouseMoveSubscription = null;
     
            //Workaround for modern client crash when disposing telerik control (switching between locations)
            if (RadMap?.Items?.Count > 0)
            {
                foreach (var radMapItem in RadMap.Items)
                {
                    var visualizationLayer = radMapItem as VisualizationLayer;
                    visualizationLayer?.Items?.Clear();
                }
            }
     
            DetachRadMapHandlers();
            DetachViewModelHandlers(_viewModel);
            DisposeMapLayers();
            RadMap.ItemsSource = null;
            RadMap.Dispose();
            RadMap.Provider = null;
            _viewModel = null;
            MapRadContextMenu.DataContext = null;
            _logger.Debug("TelerikMap: (RadMap) disposed");
            _alreadyLoadedViewModelScene = false;
        }
    }

     

    Our application is fairly complex and it's difficult for me to generate a simpler sample app showing the problem. Given the stack trace it does seem like the problem could be fixed if the code in MapMouseLocationIndicator.MapControl_MouseMove had some null check for the RadMap control. 

    Alternatively can you suggest a different sequence for our disposal code that might allow us to workaround this issue?

    Thanks

    Pete

  5. Vladimir Stoyanov
    Admin
    Vladimir Stoyanov avatar
    444 posts

    Posted 26 Jun Link to this post

    Hello Pete,

    Thank you for the additional information and the sample code.

    I went over it, however I am uncertain whether there is actually a need to use the Dispose method the RadMap. My current understanding is that you are giving the user an option to choose from different "views", which requires changing the providers and/or layers, but you are using the same RadMap instance. If that is indeed the case, I believe that it is not necessary to call the Dispose method of the RadMap. Note, that its idea is to be called when the RadMap is unloaded in order to dispose the resources used by the map. 

    That said, in your scenario you can simply clear and repopulate the provider, layers and anything else that you want to change dynamically. Can you give this approach a try and let me know how it goes?

    Regards,
    Vladimir Stoyanov
    Progress Telerik
    Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
  6. Peter
    Peter avatar
    48 posts
    Member since:
    Oct 2016

    Posted 26 Jun in reply to Vladimir Stoyanov Link to this post

    Hi Vladimir,

    Thanks for the update. The structure of our application is such that users can launch new windows containing a map so we will still need to dispose the control at some times. However when we are not launching a new window I will try changing the code to fully reconfigure the RadMap instead of disposing it. Unfortunately this might not be a straightforward change given the current application structure but I will investigate if this can be done.

    Thanks

    Pete

  7. Peter
    Peter avatar
    48 posts
    Member since:
    Oct 2016

    Posted 08 Jul Link to this post

    I tried that and it works in the scenario I described. 

    Thanks for your help

    Pete

  8. Vladimir Stoyanov
    Admin
    Vladimir Stoyanov avatar
    444 posts

    Posted 09 Jul Link to this post

    Hello Pete,

    It is good to know that the suggestion was helpful for your scenario.

    Don't hesitate to reach out to us again, if you have any other questions or concerns.

    Regards,
    Vladimir Stoyanov
    Progress Telerik
    Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
Back to Top