When the user visually changes a property such as the size or location of a TXTextControl.FrameBase object such as images or barcodes, events are fired to help developers detect these changes. When properties are changed in a dialog such as the TXTextControl.BarcodeLayoutDialog, the TX Text Control's Changed event is fired to indicate that changes have been made to the object. However, the exact change is not returned and must be determined by comparing the objects. Serializing Objects By serializing the object before and after the change, we can compare and find the differences in a very efficient way. The JsonSerializerHelper class implements the SerializeObjectToJson public method that uses the .NET Json implementation to serialize the object. public static string SerializeObjectToJson<T>(T obj) { JsonSerializerOptions options = new JsonSerializerOptions { WriteIndented = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault, Converters = { new IgnoreIntPtrConverter() } }; try { string jsonString = JsonSerializer.Serialize(obj, options); return jsonString; } catch (Exception ex) { return string.Empty; } } The other methods compare the serialized objects by comparing the values of all keys at all levels. It is important to check the complete object hierarchy to get access to all properties. For example, the TXTextControl.BarcodeFrame class implements the inherited properties of FrameBase, and the actual properties of the barcode, such as text or color, are stored in the underlying TXTextControl.Barcode.TXBarcodeControl object. Comparing Barcode Objects When a barcode object is changed in the dialog, the Changed event is fired. The following code shows how to compare the barcode objects before and after the change: var curBarcode = textControl1.Barcodes.GetItem(); var curBarcodeJson = JsonSerializerHelper.SerializeObjectToJson(curBarcode); var dialogResult = textControl1.BarcodeLayoutDialog(); if (dialogResult == DialogResult.OK) { var newBarcode = textControl1.Barcodes.GetItem(); var newBarcodeJson = JsonSerializerHelper.SerializeObjectToJson(newBarcode); var differences = JsonSerializerHelper.CompareSerializedObjects(curBarcodeJson, newBarcodeJson); foreach (var difference in differences) { Debug.WriteLine(difference); } } First, we serialize the barcode object before opening the BarcodeLayoutDialog. After the dialog has been successfully closed, we have the same object and serialize it for comparison. For the following example, we will change the text of the QR code from "A" to "ABC": In this sample code, we print the differences, which are returned in a list of strings like this: barcode.text: A != ABC barcode.upperTextLength: 1 != 3 You can see that the property Barcode.Text and Barcode.UpperTextLength has been updated by the dialog. JsonSerializerHelper Implementation Here is the full implementation of the JsonSerializerHelper class: using System.Text.Json; using System.Text.Json.Serialization; public class JsonSerializerHelper { public static string SerializeObjectToJson<T>(T obj) { JsonSerializerOptions options = new JsonSerializerOptions { WriteIndented = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault, Converters = { new IgnoreIntPtrConverter() } }; try { string jsonString = JsonSerializer.Serialize(obj, options); return jsonString; } catch (Exception ex) { return string.Empty; } } private class IgnoreIntPtrConverter : JsonConverter<IntPtr> { public override IntPtr Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { throw new NotImplementedException(); } public override void Write(Utf8JsonWriter writer, IntPtr value, JsonSerializerOptions options) { writer.WriteNullValue(); } } public static List<string> CompareSerializedObjects(string json1, string json2) { var differences = new List<string>(); try { var dictionary1 = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(json1); var dictionary2 = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(json2); foreach (var key in dictionary1.Keys) { if (dictionary2.ContainsKey(key)) { var value1 = dictionary1[key]; var value2 = dictionary2[key]; if (value1.ValueKind == JsonValueKind.Object && value2.ValueKind == JsonValueKind.Object) { var subDict1 = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(value1.GetRawText()); var subDict2 = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(value2.GetRawText()); CompareDictionaries(subDict1, subDict2, differences, key); } } else { differences.Add($"{key}: {dictionary1[key]} != null"); } } foreach (var key in dictionary2.Keys) { if (!dictionary1.ContainsKey(key)) { differences.Add($"{key}: null != {dictionary2[key]}"); } } } catch (Exception ex) { // exception handling } return differences; } private static void CompareDictionaries(Dictionary<string, JsonElement> dict1, Dictionary<string, JsonElement> dict2, List<string> differences, string parentKey) { foreach (var key in dict1.Keys) { var fullKey = $"{parentKey}.{key}"; if (!dict2.ContainsKey(key)) { differences.Add($"{fullKey}: {dict1[key]} != null"); } else if (!JsonElementEquals(dict1[key], dict2[key])) { differences.Add($"{fullKey}: {dict1[key]} != {dict2[key]}"); } } foreach (var key in dict2.Keys) { if (!dict1.ContainsKey(key)) { var fullKey = $"{parentKey}.{key}"; differences.Add($"{fullKey}: null != {dict2[key]}"); } } } private static bool JsonElementEquals(JsonElement element1, JsonElement element2) { if (element1.ValueKind != element2.ValueKind) { return false; } switch (element1.ValueKind) { case JsonValueKind.Object: var dict1 = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(element1.GetRawText()); var dict2 = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(element2.GetRawText()); return DictionariesEqual(dict1, dict2); case JsonValueKind.Array: if (element1.GetArrayLength() != element2.GetArrayLength()) { return false; } var enumerator1 = element1.EnumerateArray(); var enumerator2 = element2.EnumerateArray(); while (enumerator1.MoveNext() && enumerator2.MoveNext()) { if (!JsonElementEquals(enumerator1.Current, enumerator2.Current)) { return false; } } return true; default: return element1.ToString() == element2.ToString(); } } private static bool DictionariesEqual(Dictionary<string, JsonElement> dict1, Dictionary<string, JsonElement> dict2) { if (dict1.Count != dict2.Count) { return false; } foreach (var kvp in dict1) { if (!dict2.ContainsKey(kvp.Key) || !JsonElementEquals(kvp.Value, dict2[kvp.Key])) { return false; } } return true; } } Conclusion By serializing objects before and after a change, you can easily compare the differences. This is a very efficient way to detect changes in complex objects such as barcode objects in TX Text Control.