Read and Write DICOM Private Tags - WinForms C# .NET 6

This tutorial shows how to load a DICOM dataset in a C# WinForms application and write user-defined data into private tags. The tutorial also shows how to read and display the stored data after they have been written.

Overview  
Summary This tutorial covers how to read and write data from DICOM tags in a WinForms C# Application.
Completion Time 30 minutes
Visual Studio Project Download tutorial project (6 KB)
Platform .NET 6 WinForms C# Application
IDE Visual Studio 2022
Development License Download LEADTOOLS

Required Knowledge

Get familiar with the basic steps of creating a project by reviewing the Add References and Set a License tutorial, before working on the Read and Write DICOM Private Tags - WinForms C# tutorial.

Private Data Elements

The specifications for Private Data Elements are listed in Part 5 Section 7.8 of the DICOM standard and are intended to be used to contain information that cannot be contained in Standard DICOM Data Elements.

The tutorial will use tags (0027, 1000-1004) to store user-defined data inputted through the WinForms UI.

For the specific rules on the insertion of Private Data tags, see the link included in the See Also section below.

Create the Project and Add LEADTOOLS References

In Visual Studio, create a new C# Windows WinForms project, and add the below necessary LEADTOOLS references.

The references needed depend upon the purpose of the project. References can be added by one or the other of the following two methods (but not both).

If using NuGet references, this tutorial requires the following NuGet package:

If using local DLL references, the following DLLs are needed.

The DLLs are located at <INSTALL_DIR>\LEADTOOLS23\Bin\net:

For a complete list of which DLL files are required for your application, refer to Files to be Included With Your Application.

Set the License File

The License unlocks the features needed for the project. It must be set before any toolkit function is called. For details, including tutorials for different platforms, refer to Setting a Runtime License.

There are two types of runtime licenses:

Note: Adding LEADTOOLS NuGet and local references and setting a license are covered in more detail in the Add References and Set a License tutorial.

With the project created, the references added, and the license set, coding can begin.

Add the using statements below to the top.

C#
using Leadtools; 
using Leadtools.Codecs; 
using Leadtools.Dicom; 

Add the following global variables to the Form class.

C#
DicomDataSet dicomDS; 
       
DicomElement root = null; 
int elementGroup = 0x27; 
string sUniqueID = "My Private Creator Data Element"; 

In Solution Explorer, double-click Form1.cs to display it in the Designer. Click the Events icon in the Properties Window. Then, double-click the Load event to create an event handler if one does not already exist. This will bring up the code behind the form.

Add the following code inside the Form1_Load event handler to startup the DicomEngine object.

C#
private void Form1_Load(object sender, EventArgs e) 
{ 
   DicomEngine.Startup(); 
} 

Add the Form Controls

In Solution Explorer, double-click Form1.cs to display it in the Designer. Go to the Toolbox and add the following controls:

Add the Load DataSet Code

Add a new function called SetDSLoadPath() and add the below code to it.

C#
private String SetDSLoadPath() 
{ 
   try 
   { 
      OpenFileDialog dlg = new OpenFileDialog(); 
      dlg.InitialDirectory = @"C:\LEADTOOLS23\Resources\Images\DICOM"; 
      dlg.Filter = "DICOM DataSets (*.dcm)|*.dcm"; 
      if (dlg.ShowDialog(this) == DialogResult.OK) 
      { 
         return dlg.FileName; 
      } 
      else 
         return null; 
   } 
   catch (Exception ex) 
   { 
      MessageBox.Show("Error: " + ex.Message); 
      return null; 
   } 
} 

Double-click on the Load DICOM DS button and use the following code to display the dialog used for loading the dataset file.

C#
private void setDicomDSButton_Click(object sender, EventArgs e) 
{ 
   try 
   { 
      string dataSetPath = SetDSLoadPath(); 
      if (dataSetPath != null) 
      { 
         dicomDSPathTextBox.Text = dataSetPath; 
         if(dicomDS == null) 
            dicomDS = new DicomDataSet(); 
         dicomDS.Reset(); 
         dicomDS.Load(dataSetPath, DicomDataSetLoadFlags.LoadAndClose); 
      } 
   } 
   catch (Exception ex) 
   { 
      dicomDS.Dispose(); 
      MessageBox.Show("Error: " + ex.Message); 
   } 
} 

Add the Read Private Tags Code

Double-click on the Read button and use the following code to check the loaded DataSet file for the Private Element stored in Group 27 (0027) and load the values stored in the tags to the respective TextBox control in the form.

C#
private void readButton_Click(object sender, EventArgs e) 
{ 
   try 
   { 
      DicomElement privateCreatorElement = null; 
      DicomElement privateElement = null; 
      TextBox[] privateTagValuesTextBoxes = 
      { 
      tag1000TextBox, 
      tag1001TextBox, 
      tag1002TextBox, 
      tag1003TextBox, 
      tag1004TextBox 
   }; 
 
      // Check if DS is loaded 
      if (dicomDS == null) 
      { 
         MessageBox.Show("Load a DICOM DataSet First"); 
         return; 
      } 
 
      // Check if the Private Creator Data Element for group 0027 already exists 
      privateCreatorElement = dicomDS.FindFirstPrivateCreatorDataElement(root, true, sUniqueID, elementGroup); 
 
      // If the Private Creator Data Element exists, try to read from it  
      if (privateCreatorElement != null) 
      { 
         // Read some private elements                    
         privateElement = dicomDS.FindFirstPrivateElement(privateCreatorElement); 
         for (int i = 0; i < 5; i++) 
         { 
            // Display Tag number (in hex) and value in tag. 
            privateTagValuesTextBoxes[i].Text = dicomDS.GetConvertValue(privateElement); 
            privateElement = dicomDS.FindNextPrivateElement(privateElement, privateCreatorElement); 
         } 
      } 
   } 
   catch (Exception ex) 
   { 
      MessageBox.Show("Error: " + ex.Message); 
   } 
} 

Add the Clear Button Code

Double-click on the Clear button control and add the code below so that the TextBox controls are cleared from any loaded text.

C#
private void clearButton_Click(object sender, EventArgs e) 
{ 
   tag1000TextBox.Clear(); 
   tag1001TextBox.Clear(); 
   tag1002TextBox.Clear(); 
   tag1003TextBox.Clear(); 
   tag1004TextBox.Clear(); 
} 

Add the Write Private Tags Code

Double-click on the Write button and use the following code to take the values entered in the TextBox controls and store them in the respective Private Data tag indicated. Once stored, the code will prompt the user to save the DataSet containing the Private Tags in a new DataSet file.

C#
private void writeButton_Click(object sender, EventArgs e) 
{ 
   try 
   { 
      DicomElement privateCreatorElement = null; 
      DicomElement privateElement = null; 
      int tag = 0; 
      string[] privateTagsValues = 
      { 
         tag1000TextBox.Text, 
         tag1001TextBox.Text, 
         tag1002TextBox.Text, 
         tag1003TextBox.Text, 
         tag1004TextBox.Text 
      }; 
 
      // Check if DS is loaded 
      if (dicomDS == null) 
      { 
         MessageBox.Show("Load a DICOM DataSet First"); 
         return; 
      } 
 
      // Check if the Private Creator Data Element for group 0027 already exists 
      privateCreatorElement = dicomDS.FindFirstPrivateCreatorDataElement(root, true, sUniqueID, elementGroup); 
 
      // If the Private Creator Data Element does not exist, try to create it  
      if (privateCreatorElement == null) 
      { 
         privateCreatorElement = dicomDS.CreatePrivateCreatorDataElement(root, elementGroup, 0x10, sUniqueID); 
         DicomTagTable.Instance.Insert(privateCreatorElement.Tag, 0xFFFFFFFF, sUniqueID, privateCreatorElement.VR, 1, 1, 1); 
 
         for (int i = 0; i < 5; i++) 
         { 
            // Insert private tags 
            tag = dicomDS.GetNextUnusedPrivateTag(privateCreatorElement); 
            dicomDS.InsertElement(root, false, tag, DicomVRType.LO, false, 0); 
         } 
      } 
 
      // Set the values in the private tags 
      privateElement = dicomDS.FindFirstPrivateElement(privateCreatorElement); 
      for (int i = 0; i < 5; i++) 
      { 
         bool result = dicomDS.SetStringValue(privateElement, new string[] { privateTagsValues[i] }); 
         Console.WriteLine(result.ToString()); 
         privateElement = dicomDS.FindNextPrivateElement(privateElement, privateCreatorElement); 
      } 
 
      // Save 
      MessageBox.Show("Private Tag Values written successfully. Select a location to save the DS."); 
 
      SaveFileDialog dlg = new SaveFileDialog(); 
      dlg.InitialDirectory = @"C:\LEADTOOLS23\Resources\Images\DICOM"; 
      dlg.Filter = "DICOM DataSets (*.dcm)|*.dcm"; 
      dlg.FileName = "PrivateTags.dcm"; 
      if (dlg.ShowDialog(this) == DialogResult.OK) 
      { 
         dicomDS.Save(dlg.FileName, DicomDataSetSaveFlags.ExplicitVR); 
      } 
   } 
   catch (Exception ex) 
   { 
      MessageBox.Show("Error: " + ex.Message); 
   } 
} 

Run the Project

Run the project by pressing F5, or by selecting Debug -> Start Debugging.

If the steps were followed correctly, the application runs and allows the user to load a DICOM DataSet, enter any valid data in each of the TextBox controls corresponding to their respective private tag, then store them into the DataSet using the Write button.

The stored Private Data tags can then be read by loading the output DataSet file and clicking the Read button which will load the values in their respective TextBox control.

Wrap-up

This tutorial showed how to use the DicomDataSet, DicomElement, and DicomTagTable classes to read and write Private Data elements in DICOM DataSets.

See Also

Help Version 23.0.2024.5.22
Products | Support | Contact Us | Intellectual Property Notices
© 1991-2024 LEAD Technologies, Inc. All Rights Reserved.

Products | Support | Contact Us | Intellectual Property Notices
© 1991-2023 LEAD Technologies, Inc. All Rights Reserved.