Null Reference Exception in plugin when accessing ActiveFileProperties and ActiveFile in Trados Studio 2024

Context
First of all, I should note that I have previously worked on our plugin Trados Studio 2024 compatibility and everything was working fine. While I was creating a new version for Trados 2024 with our latest changes, the plugin started failing with NullReferenceException when opening a new file. The plugin is working fine in Studio 2021-2022 versions, but failing in Studio 2024.


Issue Description
In Studio 2024, when the plugin initializes and tries to access _activeDocument.ActiveFileProperties and _activeDocument.ActiveFile, both properties return null, causing NullReferenceExceptions. These properties were previously accessible in Studio 2021-2022, suggesting an API change in the newer version.

Error Points
The error starts from EditorController_ActiveDocumentChanged method where the the Document has null ActiveFile and ActiveFileProperties:

private void EditorController_ActiveDocumentChanged(object sender, DocumentEventArgs e)
{
    SetActiveDocument(e.Document);
}

What I've Tried
1. Added null checks for _activeDocument.ActiveFile before attempting to access it
2. Attempted to access file properties through other paths (ActiveDocument.Files collection)
3. Checked the Studio 2024 documentation for API changes (limited information available)


Expected Behavior
The plugin should be able to access file metadata in Trados Studio 2024 to determine if the current document was processed by ESTeam Language Factory and display the appropriate tabs and information based on the document type.


Actual Behavior
The plugin fails with NullReferenceException when trying to access ActiveFileProperties or ActiveFile.

Parents Reply
  • Hi  , I've reviewed yr plugin and identified where the problems are + how you can workaround them. Let me know if you need the full example.

    Delete yr current UserControl implementation here: SampleTradosPluginControl.cs.

    Delete SampleTradosPluginInitializer.cs; you don't need it with this sample project impelmentation.

    I'd recommend to move the logic that accesses the editor controller to yr controller that manages the view/viewModel, as it should initalize when the editor context is avaialble.

    using SampleTradosPlugin.View;
    using SampleTradosPlugin.ViewModel;
    using Sdl.Desktop.IntegrationApi;
    using Sdl.Desktop.IntegrationApi.Extensions;
    using Sdl.Desktop.IntegrationApi.Interfaces;
    using Sdl.TranslationStudioAutomation.IntegrationApi;
    
    namespace SampleTradosPlugin
    {
        [ViewPart(
            Id = "Information Box",
            Name = "Information Box",
            Description = "Information Box",
            Icon = "favicon"
        )]
        [ViewPartLayout(typeof(EditorController), Dock = DockType.Top)]
        public class SampleTradosPluginController : AbstractViewPartController
        {
            private SampleTradosPluginView _view;
            private SampleTradosPluginViewModel _viewModel;
            private EditorController _editorController;
    
            protected override IUIControl GetContentControl()
            {
                return _view;
            }
            protected override void Initialize()
            {
                _editorController = SdlTradosStudio.Application.GetController<EditorController>();
                
                _view = new SampleTradosPluginView();
                _viewModel = new SampleTradosPluginViewModel(_view, _editorController);
    
                _view.DataContext = _viewModel;
            }
        }
    }

    The ActiveFile on the IStudioDocument is null when loading the document for the first time as it's simply not active when you attempting to access it.  Simply get the first file.

            private ProjectFile GetActiveFile(IStudioDocument document)
            {
                try
                {
                    if (document?.ActiveFile != null)
                    {
                        return document.ActiveFile;
                    }
    
                    var file = document?.Files?.FirstOrDefault();
                    if (file != null)
                    {
                        return file;
                    }
                }
                catch
                {
                    throw new Exception("Document files object is null");
                }
    
                return null;
            }

Children
  • Hey  ,

    Thank you for the time allocated for this, I really appreciate it!

    First of all, I have updated your role to have write and push rights to the repo. Secondly, after the suggested changes, I suppose I have to refactor the whole code to use the file returned from GetActiveFile instead of _activeDocument.ActiveFile.

    This approach creates some issues in my main repo, since I am using _activeDocument.ActiveFileProperties.FileConversionProperties.MetaDataContainsKey a few times. I don't see any similar methods in the file returned from GetActiveFile method.

    Another issue is that I am using 
    private Document activeDocument = (Document)InformationBoxInitializer.EditorController.ActiveDocument;
    in my custom verifier class (and a few other classes), which will create errors by deleting InformationBoxInitializer class. Any workarounds on that?

  • Hi  , I'm not finding 'InformationBoxInitializer' in the sample project.  If this is the same as 'SampleTradosPluginInitializer' from the sample project you provided, then it's still ok to initialize the editor controller there and access it everywhere.  You just need to make sure it's initialize after the context is ready.

    Example:

    using System;
    using Sdl.Desktop.IntegrationApi;
    using Sdl.Desktop.IntegrationApi.Extensions;
    using Sdl.Desktop.IntegrationApi.Interfaces;
    using Sdl.TranslationStudioAutomation.IntegrationApi;
    using Sdl.Desktop.IntegrationApi.Notifications.Events;
    
    namespace SampleTradosPlugin
    {
        [ApplicationInitializer]
        public class SampleTradosPluginInitializer : IApplicationInitializer
        {
            public void Execute()  
            {  
                SdlTradosStudio.Application.GetService<IStudioEventAggregator>()  
                    .GetEvent<StudioWindowCreatedNotificationEvent>().Subscribe(OnStudioWindowCreated);  
            }  
    
            private void OnStudioWindowCreated(StudioWindowCreatedNotificationEvent obj)  
            {  
                EditorController = SdlTradosStudio.Application.GetController<EditorController>();  
            }  
    
            public static EditorController EditorController { get; private set; }
        }
    }

    Note: I'd recommend that you reference System.Reactive.dll from the studio installation directory to ensure you have right version for subscibing to the notification events.

    <Project Sdk="Microsoft.NET.Sdk">
        <PropertyGroup>
            <TradosFolder>$(MSBuildProgramFiles32)\Trados\Trados Studio\Studio18</TradosFolder>
            <PluginDeploymentPath>$(AppData)\Trados\Trados Studio\18\Plugins</PluginDeploymentPath>
        </PropertyGroup>
        <ItemGroup>
            <Reference Include="System.Reactive">
              <HintPath>$(TradosFolder)\System.Reactive.dll</HintPath>
            </Reference>
            // Other Trados References...
        </ItemGroup>
    </Project>