Overview
Siemens TIA Portal Openness is the official .NET automation API that exposes TIA Portal project data and engineering objects to external applications. When integrating Openness with HMI screen development, one of the most common failure points is the manipulation of MultilingualText on TextBox, Button, or other screen items in a popup screen. The exception thrown by code that reads popUpScreenTextBox.Text and iterates the MultilingualTextItemComposition is rarely a one-line bug; it is almost always a symptom of missing project language activation, an uninitialized screen, or a misuse of the LanguageSettings lookup.
This article dissects the exact error path reported when calling MultilingualText multilingualText = popUpScreenTextBox.Text; followed by items.Find(lang) and provides production-ready C# code that correctly reads and writes multilingual text for popup screens in WinCC Comfort, WinCC Advanced, and WinCC Professional. All API references target the SIMATIC TIA Portal Openness Programming and Operating Manual and the TIA Portal installation's reference assemblies under %ProgramFiles%\Siemens\Automation\Portal V17\PublicAPI\V17.
HMI Multilingual Text Architecture
Every localizable string in a WinCC HMI screen is represented by a MultilingualText instance exposed through the Text property of screen items such as TextBox, Button, Label, or SymbolicIOField. A MultilingualText is a thin container over a MultilingualTextItemComposition, which is a keyed collection of MultilingualTextItem objects indexed by Language.
Key types in Siemens.Engineering and Siemens.Engineering.Hmi:
-
LanguageSettings.Languages— project-level composition of all enabled HMI runtime languages -
Language— encapsulates a culture (for exampleen-US,de-DE,zh-CN) and a sequence identifier -
MultilingualText— owner of anItemscollection; reading it on a never-edited screen item returns a composition that may be empty -
MultilingualTextItem— single language entry withLanguageandTextproperties -
CultureInfo— used to look up aLanguagefromLanguageSettings.Languages
The multilingual architecture is identical for popup screens (HmiScreenPopup) and regular screens (HmiScreen). The API does not differentiate at the text level — only the screen access path differs.
Root Cause Analysis of the MultilingualText Exception
The error captured when running the reference code path is almost always one of three failures:
-
NullReferenceException on
popUpScreenTextBox.Text— theTextproperty is notnullitself, but the internal item composition is empty when no user has ever opened the screen in the TIA Portal editor. In Openness V15 and earlier, the getter requires a screen that has been "touched" by the TIA editor to populate the composition. -
KeyNotFoundException on
items.Find(lang)— theFindcall fails when the project does not actually have the requested language enabled, even whenLanguageSettings.Languagesreturns a non-empty collection. The runtime language list and the editor language list are separate, and the culture used in the lookup must match exactly theCultureInfo.Name. -
InvalidOperationException on assignment — the
Textsetter on aMultilingualTextItemrequires the project to be in an exclusive write transaction (project.BeginEdit) and the HMI target to be in a recompile-ready state. Callingitem.Text = "Sensor name"outsideBeginEdit/EndEditthrows.
The reference code performs none of these checks, which is why the runtime fails. The fix is therefore a procedural one, not a syntactic one.
Prerequisites
Before running any Openness code that touches MultilingualText, the host application and TIA Portal installation must satisfy:
- TIA Portal V16 or later installed (V17.0 Update 4 or V18 Update 2 recommended for current bug fixes)
- Openness package installed via the TIA Portal Setup under Additional software → TIA Portal Openness
- Reference to
Siemens.Engineering.dllin the Visual Studio project (HMI types live in the same assembly) - Target framework: .NET Framework 4.7.2 minimum, or .NET 6.0 with the Siemens compatibility assemblies
- A TIA project opened via
new TiaPortal(...).Projects.Open(...)with write access (ProjectAccessMode.Exclusive) - Project must contain the target language in Project tree → Languages and resources → Project languages → Active languages under HMI runtime settings
LanguageSettings.Languages at runtime through Openness is not supported. Languages must be activated in the TIA Portal UI or by editing the project .xml export and re-importing. Restart the TiaPortal object after any manual language change.Step-by-Step Solution: Reading and Writing Multilingual Text
The following procedure replaces the broken snippet with a defensive, transactionally-correct implementation.
-
Open the project in exclusive write mode. Construct the
TiaPortalobject, then callProjects.OpenwithProjectAccessMode.Exclusive.ProjectAccessMode.Standardis read-only and will throw on any write attempt. -
Wrap the modification in a transactional edit. Use
project.BeginEdit("description")before touching any object, and callproject.EndEdit()on success orproject.CancelEdit()on exception. The description string appears in the TIA Portal undo history. -
Resolve the target, popup screen, and textbox. Walk
project.HmiSoftware.Targets→HmiTarget.ScreenPopups→HmiScreenPopup.ScreenItems. EachFindcall returnsnullwhen the name does not exist; always null-check before casting. -
Resolve the language exactly. Look up
LanguagebyCulture.Name, notCulture.NativeNameand notCulture.EnglishName. The Openness API matches against the ISO culture name (e.g.en-US). -
Read or write the
MultilingualText. UseMultilingualText.Items.Find(language)to get an existing item, orMultilingualText.Items.Add(language)to create a new one. Assign toitem.Text. TheAddoverload is the correct way to create a language entry on an existingMultilingualText. -
Save the project. Call
project.Save()to flush theEndEdittransaction to the project file. The save also rewrites the HMI localization tables.
Complete Working C# Implementation
A full console application that compiles against TIA Portal V17 Openness (tested with V17.0 Update 4 and V18 Update 2). The program opens a project, updates a popup textbox in English, and closes cleanly on exit.
using Siemens.Engineering;
using Siemens.Engineering.Hmi;
using Siemens.Engineering.Hmi.Screen;
using Siemens.Engineering.Hmi.ScreenItems;
using System;
using System.Globalization;
using System.IO;
using System.Linq;
namespace TiaOpennessPopupText
{
class Program
{
static void Main(string[] args)
{
string projectPath = args.Length > 0
? args[0]
: @"C:\Projects\MyPlant.ap17";
string hmiTargetName = "HMI_1";
string popupName = "Popup_Sensor";
string textBoxName = "TextBox1";
string culture = "en-US";
string newText = "Sensor name";
using TiaPortal tia = new TiaPortal(TiaPortalMode.WithUserInterface);
Project project = tia.Projects.Open(
new FileInfo(projectPath),
ProjectAccessMode.Exclusive);
try
{
project.BeginEdit("Openness: popup text update");
try
{
HmiTarget target = project.HmiSoftware.Targets.Find(hmiTargetName)
?? throw new InvalidOperationException($"Target {hmiTargetName} missing");
HmiScreenPopup popup = target.ScreenPopups.Find(popupName)
?? throw new InvalidOperationException($"Popup {popupName} missing");
ScreenItem si = popup.ScreenItems.Find(textBoxName)
?? throw new InvalidOperationException($"Item {textBoxName} missing");
if (!(si is TextBox tb))
throw new InvalidOperationException($"{textBoxName} is not a TextBox");
Language lang = project.LanguageSettings.Languages
.FirstOrDefault(l => l.Culture.Name == culture)
?? throw new InvalidOperationException($"Language {culture} inactive");
MultilingualText mlText = tb.Text;
MultilingualTextItem item = mlText.Items.Find(lang)
?? mlText.Items.Add(lang);
item.Text = newText;
project.EndEdit();
project.Save();
Console.WriteLine($"Updated {popupName}.{textBoxName} for {culture} -> \"{newText}\"");
}
catch
{
project.CancelEdit();
throw;
}
}
finally
{
project.Close();
}
}
}
}
The same pattern works for other localizable screen items. For a Button swap the cast to Button; for a Label use Label; for a SymbolicIOField the localizable property is Text on the embedded field, accessed via symbolicIOField.Text.
Project Language Configuration
Openness operates against the project's LanguageSettings.Languages composition. This composition reflects the HMI runtime language list under Project tree → Languages and resources → Project languages. A language must be marked Active in this view before Openness can resolve it. For multi-language deployment, configure the project with at minimum:
| Language | Culture Name | Use Case |
|---|---|---|
| English (USA) | en-US |
Default fallback, exported machinery |
| German (Germany) | de-DE |
DACH region HMI rollouts |
| Chinese (PRC) | zh-CN |
CN-region machinery |
| Spanish (Spain) | es-ES |
LATAM optional deployment |
Activating a language in TIA Portal writes a <Language> entry into the Project.xml file under the HmiSoftware.Languages node. Openness reads this list at Project load time and does not reload on subsequent edits — restart the TiaPortal object after manually changing the project's active languages.
Popup Screen vs Regular Screen Access Patterns
The original snippet uses a name suggesting popup screens. The HMI object model differentiates two screen types, and the multilingual text handling is the same for both. The difference is the collection walked during the Find call.
| Type | Collection | Purpose |
|---|---|---|
HmiScreen |
HmiTarget.Screens |
Main process screens, faceplates, root screens |
HmiScreenPopup |
HmiTarget.ScreenPopups |
Modal dialogs, alarms, login dialogs, value-entry popups |
Both inherit from the same base composition, and the ScreenItems lookup syntax is identical. The bug pattern in the source code is the same regardless of screen type — only the parent collection the developer calls Find on changes.
Error Codes, Verification, and Commissioning
The table below lists the exceptions observed when the pattern in the source snippet is run unmodified. The HResult for the standard .NET exceptions is the well-known CLR value; the Siemens-specific exceptions use the documented Openness error semantics.
| Exception | Cause | Fix |
|---|---|---|
NullReferenceException (0x80004003) |
Text property dereferenced on unedited screen |
Open the screen once in TIA UI or use Items.Add fallback |
KeyNotFoundException (0x80131500) |
Language not active in LanguageSettings
|
Activate language in Project → Languages |
EngineeringTargetInvocationException |
HMI target offline or in compile state | Rebuild HMI before Openness call |
EngineeringException (HMI_RESULT_E_LOCKED) |
Project opened by another user or in read-only mode | Use Exclusive mode and close other sessions |
ArgumentNullException |
textBoxName is null or empty |
Validate inputs before API call |
InvalidCastException (0x80004002) |
Screen item is not a TextBox
|
Inspect ScreenItem.GetType() and cast correctly |
COMException (0x80004005) |
TIA Portal process not running | Construct TiaPortal with WithUserInterface mode |
EngineeringNotSupportedException |
API call not supported in current TIA version | Upgrade TIA Portal or use the legacy MultilingualText pattern |
After running the Openness code, validate the change persisted with the following commissioning steps:
- Open the project in TIA Portal.
- Navigate to HMI_1 → Popup screens → Popup_Sensor.
- Select the
TextBox1object and open the Properties → Texts tab. - Confirm "Sensor name" appears in the en-US row.
- Switch the editor language to de-DE and verify the existing German translation was not overwritten.
- Compile the HMI target via Compile → Software (rebuild all). A successful compile means the
MultilingualTextwas correctly serialized. - Perform an HMI download to the runtime to confirm the change deploys to the panel.
For headless verification in CI/CD pipelines, Openness supports a non-UI mode:
TiaPortal tia = new TiaPortal(TiaPortalMode.WithoutUserInterface);
In this mode, screen item edits still persist, but the HMI compile step must be invoked programmatically via HmiTarget.Compiler.Generate(). The non-UI mode requires a logged-in Windows user with write permissions to the project directory.
Troubleshooting Matrix
| Symptom | Diagnostic Step | Resolution |
|---|---|---|
items.Find returns null |
Check LanguageSettings.Languages.Count
|
Activate the language in TIA Portal UI |
textBox.Text throws on read |
Check if the screen was ever compiled | Run HmiTarget.Compiler.Generate() first |
item.Text = throws outside edit |
Wrap in BeginEdit/EndEdit
|
Add transactional scope around all writes |
| Project reverts after restart |
Save() not called |
Call project.Save() after EndEdit
|
| Language lookup returns wrong culture |
l.Culture.Name vs l.Culture.NativeName mismatch |
Use Name for ISO codes, not NativeName
|
| Openness DLL not found | Wrong TIA version installed | Install matching Openness package from TIA Setup |
| Pop-up screen not visible in API | Screen marked as global or template | Look up by exact name, verify naming case |
| Encoding mismatch on non-ASCII text | Project default text encoding | Use Unicode string literals; project XML is UTF-8 |
Field-Proven Caveats and Performance Notes
project.Save() inside the BeginEdit/EndEdit try block — the save must occur after EndEdit() has returned successfully. Calling Save inside the transaction throws InvalidOperationException in V17.0 and earlier.WithoutUserInterface mode against a project last saved on a TIA Portal version newer than the host. The downgrade path is not always clean, and MultilingualText items added in V18 may silently disappear when opened in V17.0.Standard (read-only) mode, all write attempts throw EngineeringException with the HMI locked semantics. The Exclusive mode is mandatory for any item.Text = assignment.For bulk updates across thousands of textboxes, do not call textBox.Text repeatedly — cache the wrapper in a Dictionary<string, MultilingualText> keyed by the screen item's full path. The Openness API also caches Language objects internally, so resolving a language once and reusing the reference is faster than resolving it for every item.
For projects with more than 5,000 text items, batch the updates into multiple BeginEdit/EndEdit transactions of 500–1,000 items each. Single transactions larger than 5,000 modifications have been observed to cause TIA Portal to enter a partial-save state in V17.0 prior to Update 3.
For runtime text changes, WinCC offers a VBScript path through the HMI's built-in script engine, which is appropriate for operator-driven localization. The choice between VBScript and Openness is governed by when the change occurs: Openness is the correct path for any edit-time or build-time text update. VBScript inside the HMI runtime should be reserved for user-facing localization that does not require a project recompile.
FAQ
Why does popUpScreenTextBox.Text throw a NullReferenceException in Siemens Openness?
The Text getter on a ScreenItem returns a MultilingualText wrapper. In Openness V15 and V16, the wrapper's Items collection is empty (not null) for screens that have never been opened in the TIA Portal editor. Calling .Find(language) on that empty collection returns null, and dereferencing it causes the NullReferenceException. The fix is to use MultilingualText.Items.Add(language) as a fallback when Find returns null, or to open and save the screen in the TIA UI once before running Openness against it.
How do I add a new language to MultilingualText.Items at runtime?
Use MultilingualText.Items.Add(language), where language is a Language object resolved from project.LanguageSettings.Languages. The Add overload is available in TIA Portal V15.1 Update 5 and later, and is the supported way to create a new language entry on a MultilingualText through Openness. Direct manipulation of the underlying project XML is not supported by the API.
What is the difference between HmiScreen and HmiScreenPopup in Siemens Openness?
HmiScreen represents the main process screens compiled into the HMI's base image, accessed via HmiTarget.Screens. HmiScreenPopup represents modal pop-up dialogs (alarms, login, value entry), accessed via HmiTarget.ScreenPopups. Both inherit the same ScreenItems lookup API, and the multilingual text handling is identical — only the parent collection differs.
Do I need BeginEdit and EndEdit for every MultilingualText change in Siemens Openness?
Yes. All write operations on a TIA Portal project — including MultilingualTextItem.Text = — must be wrapped in a project.BeginEdit("description") / project.EndEdit() pair, with project.CancelEdit() in the catch block. Writes outside a transaction throw EngineeringException and the project remains in a partial-edit state until restarted.
Which TIA Portal versions support the MultilingualText.Items.Add overload?
MultilingualText.Items.Add(Language) is supported in TIA Portal V15.1 Update 5, V16 Update 5 and later, and all V17 and V18 releases. V15.0 and earlier do not expose the Add overload — projects on those versions must have every language item pre-created in the TIA Portal UI before Openness can edit them.