Files
Mapo-IOB-WIN/IOB-OPC-UA/Applications/ClientControls.Net4/Common/Client/EditComplexValueCtrl.cs
T
2021-03-25 18:25:25 +01:00

1559 lines
47 KiB
C#

/* ========================================================================
* Copyright (c) 2005-2020 The OPC Foundation, Inc. All rights reserved.
*
* OPC Foundation MIT License 1.00
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* The complete license agreement can be found here:
* http://opcfoundation.org/License/MIT/1.00/
* ======================================================================*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Reflection;
namespace Opc.Ua.Client.Controls.Common
{
/// <summary>
/// Allows the user to edit a complex value.
/// </summary>
public partial class EditComplexValueCtrl : UserControl
{
/// <summary>
/// Constructs the object.
/// </summary>
public EditComplexValueCtrl()
{
InitializeComponent();
MaxDisplayTextLength = 100;
ValuesDV.AutoGenerateColumns = false;
ImageList = new ClientUtils().ImageList;
m_dataset = new DataSet();
m_dataset.Tables.Add("Values");
m_dataset.Tables[0].Columns.Add("AccessInfo", typeof(AccessInfo));
m_dataset.Tables[0].Columns.Add("Name", typeof(string));
m_dataset.Tables[0].Columns.Add("DataType", typeof(string));
m_dataset.Tables[0].Columns.Add("Value", typeof(string));
m_dataset.Tables[0].Columns.Add("Icon", typeof(Image));
ValuesDV.DataSource = m_dataset.Tables[0];
}
#region Private Fields
private DataSet m_dataset;
private Session m_session;
private AccessInfo m_value;
private bool m_readOnly;
private int m_maxDisplayTextLength;
private event EventHandler m_ValueChanged;
#endregion
private class AccessInfo
{
public AccessInfo Parent { get; set; }
public PropertyInfo PropertyInfo { get; set; }
public int[] Indexes;
public TypeInfo TypeInfo;
public object Value;
public string Name;
}
#region Public Members
/// <summary>
/// The maximum length of a value string displayed in a column.
/// </summary>
[DefaultValue(100)]
public int MaxDisplayTextLength
{
get
{
return m_maxDisplayTextLength;
}
set
{
if (value < 20)
{
m_maxDisplayTextLength = 20;
}
m_maxDisplayTextLength = value;
}
}
/// <summary>
/// Returns true if the Back command can be called.
/// </summary>
public bool CanGoBack
{
get
{
return (NavigationMENU.Items.Count > 1);
}
}
/// <summary>
/// Returns true if the ArraySize can be changed.
/// </summary>
public bool CanSetArraySize
{
get
{
if (m_readOnly)
{
return false;
}
AccessInfo info = NavigationMENU.Items[NavigationMENU.Items.Count - 1].Tag as AccessInfo;
if (info != null)
{
return info.TypeInfo.ValueRank >= 0;
}
return false;
}
}
/// <summary>
/// Returns true if the data type can be changed.
/// </summary>
public bool CanChangeType
{
get
{
if (m_readOnly)
{
return false;
}
if (NavigationMENU.Items.Count > 0)
{
AccessInfo info = NavigationMENU.Items[NavigationMENU.Items.Count - 1].Tag as AccessInfo;
if (info != null)
{
return info.Parent != null && info.Parent.TypeInfo != null && info.Parent.TypeInfo.BuiltInType == BuiltInType.Variant;
}
}
return false;
}
}
/// <summary>
/// Returns the current data type.
/// </summary>
public BuiltInType CurrentType
{
get
{
if (NavigationMENU.Items.Count > 0)
{
AccessInfo info = NavigationMENU.Items[NavigationMENU.Items.Count - 1].Tag as AccessInfo;
if (info != null)
{
Variant? value = info.Value as Variant?;
if (value != null && value.Value.TypeInfo != null)
{
return value.Value.TypeInfo.BuiltInType;
}
return info.TypeInfo.BuiltInType;
}
}
return BuiltInType.Variant;
}
}
/// <summary>
/// Raised when the value is changed.
/// </summary>
public event EventHandler ValueChanged
{
add { m_ValueChanged += value; }
remove { m_ValueChanged -= value; }
}
/// <summary>
/// Changes the session used for editing the value.
/// </summary>
public void ChangeSession(Session session)
{
m_session = session;
}
/// <summary>
/// Moves the displayed value back.
/// </summary>
public void Back()
{
if (!CanGoBack)
{
return;
}
NavigationMENU_Click(NavigationMENU.Items[NavigationMENU.Items.Count - 2], null);
}
/// <summary>
/// Changes the array size.
/// </summary>
public void SetArraySize()
{
if (!CanSetArraySize)
{
return;
}
EndEdit();
AccessInfo info = NavigationMENU.Items[NavigationMENU.Items.Count - 1].Tag as AccessInfo;
TypeInfo currentType = info.TypeInfo;
object currentValue = info.Value;
if (info.Value is Variant)
{
Variant variant = (Variant)info.Value;
currentValue = variant.Value;
if (currentValue != null)
{
currentType = variant.TypeInfo;
if (currentType == null)
{
currentType = TypeInfo.Construct(currentValue);
}
}
}
int[] dimensions = null;
Array array = currentValue as Array;
if (array != null)
{
dimensions = new int[array.Rank];
for (int ii = 0; ii < array.Rank; ii++)
{
dimensions[ii] = array.GetLength(ii);
}
}
IList list = currentValue as IList;
if (array == null && list != null)
{
dimensions = new int[1];
dimensions[0] = list.Count;
}
Matrix matrix = currentValue as Matrix;
if (matrix != null)
{
dimensions = matrix.Dimensions;
array = matrix.ToArray();
}
SetTypeDlg.SetTypeResult result = new SetTypeDlg().ShowDialog(currentType, dimensions);
if (result == null)
{
return;
}
// convert to new type.
object newValue = currentValue;
if (result.ArrayDimensions == null || result.ArrayDimensions.Length < 1)
{
newValue = Convert(currentValue, currentType, result.TypeInfo, result.UseDefaultOnError);
}
else
{
if (array == null && list != null)
{
Type elementType = GetListElementType(list);
for (int ii = result.ArrayDimensions[0]; ii < list.Count; ii++)
{
list.RemoveAt(ii);
}
for (int ii = list.Count; ii < result.ArrayDimensions[0]; ii++)
{
list.Add(Activator.CreateInstance(elementType));
}
newValue = list;
}
if (array != null)
{
Array newArray = null;
if (currentValue is Array)
{
newArray = Array.CreateInstance(currentValue.GetType().GetElementType(), result.ArrayDimensions);
}
else
{
newArray = TypeInfo.CreateArray(result.TypeInfo.BuiltInType, result.ArrayDimensions);
}
int maxCount = result.ArrayDimensions[0];
for (int ii = 1; ii < result.ArrayDimensions.Length; ii++)
{
maxCount *= result.ArrayDimensions[ii];
}
int count = 0;
foreach (object element in array)
{
if (maxCount <= count)
{
break;
}
object newElement = Convert(element, currentType, result.TypeInfo, result.UseDefaultOnError);
int[] indexes = GetIndexFromCount(count++, result.ArrayDimensions);
newArray.SetValue(newElement, indexes);
}
newValue = newArray;
}
}
NavigationMENU.Items.RemoveAt(NavigationMENU.Items.Count - 1);
info.TypeInfo = result.TypeInfo;
info.Value = newValue;
ShowValue(info);
}
/// <summary>
/// Changes the data type.
/// </summary>
public void SetType(BuiltInType builtInType)
{
if (!CanChangeType)
{
return;
}
AccessInfo info = NavigationMENU.Items[NavigationMENU.Items.Count - 1].Tag as AccessInfo;
TypeInfo currentType = info.TypeInfo;
object currentValue = info.Value;
try
{
EndEdit();
currentValue = info.Value;
}
catch (Exception)
{
currentValue = TypeInfo.GetDefaultValue(currentType.BuiltInType);
}
if (info.Value is Variant)
{
Variant variant = (Variant)info.Value;
currentValue = variant.Value;
if (currentValue != null)
{
currentType = variant.TypeInfo;
if (currentType == null)
{
currentType = TypeInfo.Construct(currentValue);
}
}
}
TypeInfo targetType = new TypeInfo(builtInType, currentType.ValueRank);
object newValue = Convert(currentValue, currentType, targetType, true);
NavigationMENU.Items.RemoveAt(NavigationMENU.Items.Count - 1);
info.TypeInfo = targetType;
info.Value = newValue;
ShowValueNoNotify(info);
}
/// <summary>
/// Converts the old type to the new type.
/// </summary>
private object Convert(object oldValue, TypeInfo oldType, TypeInfo newType, bool useDefaultOnError)
{
object newValue = oldValue;
if (oldType.BuiltInType != newType.BuiltInType)
{
try
{
newValue = TypeInfo.Cast(oldValue, oldType, newType.BuiltInType);
}
catch (Exception e)
{
if (!useDefaultOnError)
{
throw new FormatException("Could not cast value to requested type.", e);
}
newValue = TypeInfo.GetDefaultValue(newType.BuiltInType);
}
}
return newValue;
}
/// <summary>
/// Displays the value in the control.
/// </summary>
public void ShowValue(
NodeId nodeId,
uint attributeId,
string name,
object value,
bool readOnly)
{
m_readOnly = readOnly;
NavigationMENU.Items.Clear();
if (m_readOnly)
{
ValuesDV.EditMode = DataGridViewEditMode.EditProgrammatically;
TextValueTB.ReadOnly = true;
}
Type type = null;
// determine the expected data type for non-value attributes.
if (attributeId != 0 && attributeId != Attributes.Value)
{
BuiltInType builtInType = TypeInfo.GetBuiltInType(Attributes.GetDataTypeId(attributeId));
int valueRank = Attributes.GetValueRank(attributeId);
type = TypeInfo.GetSystemType(builtInType, valueRank);
}
// determine the expected data type for value attributes.
else if (!NodeId.IsNull(nodeId))
{
IVariableBase variable = m_session.NodeCache.Find(nodeId) as IVariableBase;
if (variable != null)
{
BuiltInType builtInType = TypeInfo.GetBuiltInType(variable.DataType, m_session.TypeTree);
int valueRank = variable.ValueRank;
type = TypeInfo.GetSystemType(builtInType, valueRank);
if (builtInType == BuiltInType.ExtensionObject && valueRank < 0)
{
type = TypeInfo.GetSystemType(variable.DataType, m_session.Factory);
}
}
}
// use the value.
else if (value != null)
{
type = value.GetType();
}
// go with default.
else
{
type = typeof(string);
}
// assign a name.
if (String.IsNullOrEmpty(name))
{
if (attributeId != 0)
{
name = Attributes.GetBrowseName(attributeId);
}
else
{
name = type.Name;
}
}
AccessInfo info = new AccessInfo();
info.Value = Utils.Clone(value);
info.TypeInfo = TypeInfo.Construct(type);
if (value == null && info.TypeInfo.ValueRank < 0)
{
info.Value = TypeInfo.GetDefaultValue(info.TypeInfo.BuiltInType);
}
info.Name = name;
m_value = info;
ShowValue(info);
}
/// <summary>
/// Displays the value in the control.
/// </summary>
public void ShowValue(
string name,
NodeId dataType,
int valueRank,
object value)
{
if (value == null && m_session != null)
{
BuiltInType builtInType = TypeInfo.GetBuiltInType(dataType, m_session.TypeTree);
if (builtInType == BuiltInType.ExtensionObject)
{
Type type = m_session.Factory.GetSystemType(dataType);
if (type != null)
{
if (valueRank < 0)
{
value = Activator.CreateInstance(type);
}
else
{
value = Array.CreateInstance(type, new int[valueRank]);
}
}
}
else
{
value = TypeInfo.GetDefaultValue(dataType, valueRank, m_session.TypeTree);
}
}
ShowValue(null, name, value);
}
/// <summary>
/// Displays the value in the control.
/// </summary>
public void ShowValue(
TypeInfo expectedType,
string name,
object value)
{
m_readOnly = false;
NavigationMENU.Items.Clear();
// assign a type.
if (expectedType == null)
{
if (value == null)
{
expectedType = TypeInfo.Scalars.String;
}
else
{
expectedType = TypeInfo.Construct(value);
}
}
// assign a name.
if (String.IsNullOrEmpty(name))
{
name = expectedType.ToString();
}
AccessInfo info = new AccessInfo();
info.Value = Utils.Clone(value);
info.TypeInfo = expectedType;
if (value == null && info.TypeInfo.ValueRank < 0)
{
info.Value = TypeInfo.GetDefaultValue(info.TypeInfo.BuiltInType);
}
// ensure value is the target type.
info.Value = TypeInfo.Cast(info.Value, expectedType.BuiltInType);
info.Name = name;
m_value = info;
ShowValue(info);
}
/// <summary>
/// Returns the edited value.
/// </summary>
public object GetValue()
{
return m_value.Value;
}
/// <summary>
/// Validates the value currently being edited.
/// </summary>
public void EndEdit()
{
if (NavigationMENU.Items.Count < 1)
{
return;
}
if (!TextValueTB.Visible)
{
ValuesDV.EndEdit();
return;
}
AccessInfo info = NavigationMENU.Items[NavigationMENU.Items.Count - 1].Tag as AccessInfo;
object newValue = TypeInfo.Cast(TextValueTB.Text, info.TypeInfo.BuiltInType);
info.Value = newValue;
UpdateParent(info);
}
/// <summary>
/// Displays the value in the control.
/// </summary>
private void ShowValue(AccessInfo parent)
{
ShowValueNoNotify(parent);
if (m_ValueChanged != null)
{
m_ValueChanged(this, null);
}
}
/// <summary>
/// Displays the value in the control.
/// </summary>
private void ShowValueNoNotify(AccessInfo parent)
{
m_dataset.Tables[0].Clear();
ValuesDV.Visible = true;
TextValueTB.Visible = false;
ToolStripItem item = NavigationMENU.Items.Add(parent.Name);
item.Click += new EventHandler(NavigationMENU_Click);
item.Tag = parent;
TypeInfo typeInfo = parent.TypeInfo;
object value = parent.Value;
if (value is Variant)
{
Variant variant = (Variant)value;
value = variant.Value;
if (value != null)
{
parent.TypeInfo = typeInfo = variant.TypeInfo;
if (typeInfo == null)
{
parent.TypeInfo = typeInfo = TypeInfo.Construct(value);
}
}
}
if (typeInfo.ValueRank >= 0)
{
Matrix matrix = value as Matrix;
if (matrix != null)
{
value = matrix.ToArray();
}
System.Collections.IEnumerable enumerable = value as System.Collections.IEnumerable;
if (enumerable != null)
{
// get the dimensions of any array.
int[] dimensions = null;
// calculate them.
if (matrix == null)
{
Array array = enumerable as Array;
if (array != null)
{
dimensions = new int[array.Rank];
for (int ii = 0; ii < array.Rank; ii++)
{
dimensions[ii] = array.GetLength(ii);
}
}
else
{
dimensions = new int[1];
System.Collections.IList list = enumerable as System.Collections.IList;
if (list != null)
{
dimensions[0] = list.Count;
}
}
}
// get them from the matrix.
else
{
dimensions = matrix.Dimensions;
}
// display the array elements.
int count = 0;
TypeInfo elementType = new TypeInfo(typeInfo.BuiltInType, ValueRanks.Scalar);
ValuesDV.Visible = true;
TextValueTB.Visible = false;
foreach (object element in enumerable)
{
int[] indexes = GetIndexFromCount(count++, dimensions);
AccessInfo info = new AccessInfo();
info.Parent = parent;
info.Indexes = indexes;
info.TypeInfo = elementType;
info.Value = element;
ShowIndexedValue(info);
}
}
return;
}
// check for null.
if (value == null)
{
if (parent.Parent != null && parent.Parent.Value is Array)
{
parent.Value = value = Activator.CreateInstance(parent.Parent.Value.GetType().GetElementType());
}
else if (parent.Parent != null && parent.PropertyInfo != null)
{
parent.Value = value = Activator.CreateInstance(parent.PropertyInfo.PropertyType);
}
else
{
ShowTextValue(value, parent.TypeInfo);
return;
}
}
object structure = value;
// check for extension object.
ExtensionObject extension = structure as ExtensionObject;
if (extension != null)
{
structure = extension.Body;
}
// check for XmlElements.
if (structure is XmlElement)
{
ShowTextValue((XmlElement)structure);
return;
}
// check for ByteString.
if (structure is byte[])
{
ShowTextValue((byte[])structure);
return;
}
// check for NodeId.
if (structure is NodeId)
{
ShowTextValue(((NodeId)structure).ToString());
return;
}
// check for ExpandedNodeId.
if (structure is ExpandedNodeId)
{
ShowTextValue(((ExpandedNodeId)structure).ToString());
return;
}
// check for QualifiedName.
if (structure is QualifiedName)
{
ShowTextValue(((QualifiedName)structure).ToString());
return;
}
// check for Guid.
if (structure is Guid)
{
ShowTextValue(((Guid)structure).ToString());
return;
}
// check for Uuid.
if (structure is Uuid)
{
ShowTextValue(((Uuid)structure).ToString());
return;
}
// check for StatusCode.
if (structure is StatusCode)
{
ShowTextValue(Utils.Format("0x{0:X8}", ((StatusCode)structure).Code));
return;
}
ValuesDV.Visible = true;
TextValueTB.Visible = false;
// use reflection to display the properties of the structure.
bool isStructure = false;
PropertyInfo[] properties = structure.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (PropertyInfo property in properties)
{
if (property.GetIndexParameters().Length > 0)
{
continue;
}
object element = property.GetValue(structure, null);
string name = null;
foreach (object attribute in property.GetCustomAttributes(true))
{
if (typeof(System.Runtime.Serialization.DataMemberAttribute).IsInstanceOfType(attribute))
{
name = ((System.Runtime.Serialization.DataMemberAttribute)attribute).Name;
if (name == null)
{
name = property.Name;
}
break;
}
}
if (name == null)
{
continue;
}
AccessInfo info = new AccessInfo();
info.Parent = parent;
info.PropertyInfo = property;
info.TypeInfo = TypeInfo.Construct(property.PropertyType);
info.Value = element;
info.Name = name;
ShowNamedValue(info);
isStructure = true;
}
if (!isStructure)
{
ShowTextValue(parent.Value, parent.TypeInfo);
}
}
#endregion
#region Private Methods
/// <summary>
/// Returns the index based on the current count.
/// </summary>
private int[] GetIndexFromCount(int count, int[] dimensions)
{
int[] indexes = new int[(dimensions != null) ? dimensions.Length : 1];
for (int ii = indexes.Length - 1; ii >= 0; ii--)
{
indexes[ii] = count % dimensions[ii];
count /= dimensions[ii];
}
return indexes;
}
/// <summary>
/// Adds the value at an array index to the control.
/// </summary>
private void ShowIndexedValue(AccessInfo info)
{
DataRow row = m_dataset.Tables[0].NewRow();
StringBuilder buffer = new StringBuilder();
buffer.Append("[");
if (info.Indexes != null)
{
for (int ii = 0; ii < info.Indexes.Length; ii++)
{
if (ii > 0)
{
buffer.Append(",");
}
buffer.Append(info.Indexes[ii]);
}
}
buffer.Append("]");
info.Name = buffer.ToString();
row[0] = info;
row[1] = info.Name;
row[2] = GetDataTypeString(info);
row[3] = ValueToString(info.Value, info.TypeInfo);
row[4] = ImageList.Images[ClientUtils.GetImageIndex(Attributes.Value, info.Value)];
m_dataset.Tables[0].Rows.Add(row);
}
/// <summary>
/// Returns the element type for a list.
/// </summary>
private Type GetListElementType(IList list)
{
if (list != null)
{
for (Type type = list.GetType(); type != null; type = type.BaseType)
{
if (type.IsGenericType)
{
Type[] argTypes = type.GetGenericArguments();
if (argTypes.Length > 0)
{
return argTypes[0];
}
}
}
}
return typeof(object);
}
/// <summary>
/// Returns the data type of the value.
/// </summary>
private Type GetDataType(AccessInfo accessInfo)
{
if (accessInfo == null || accessInfo.TypeInfo == null)
{
return null;
}
if (accessInfo.TypeInfo.BuiltInType == BuiltInType.ExtensionObject)
{
if (accessInfo.Value != null)
{
return accessInfo.Value.GetType();
}
if (accessInfo.PropertyInfo != null)
{
return accessInfo.PropertyInfo.PropertyType;
}
if (accessInfo.Parent != null)
{
if (accessInfo.Parent.Value is Array)
{
Array array = (Array)accessInfo.Parent.Value;
return array.GetType().GetElementType();
}
if (accessInfo.Parent.Value is IList)
{
IList list = (IList)accessInfo.Parent.Value;
return GetListElementType(list);
}
}
}
return TypeInfo.GetSystemType(accessInfo.TypeInfo.BuiltInType, accessInfo.TypeInfo.ValueRank);
}
/// <summary>
/// Returns the data type of the value.
/// </summary>
private string GetDataTypeString(AccessInfo accessInfo)
{
Type type = GetDataType(accessInfo);
if (type == null)
{
return accessInfo.TypeInfo.ToString();
}
return type.Name;
}
/// <summary>
/// Adds the value with the specified name to the control.
/// </summary>
private void ShowNamedValue(AccessInfo info)
{
DataRow row = m_dataset.Tables[0].NewRow();
row[0] = info;
row[1] = (info.Name != null) ? info.Name : "unknown";
row[2] = GetDataTypeString(info);
row[3] = ValueToString(info.Value, info.TypeInfo);
row[4] = ImageList.Images[ClientUtils.GetImageIndex(Attributes.Value, info.Value)];
m_dataset.Tables[0].Rows.Add(row);
}
/// <summary>
/// Displays a value in the control.
/// </summary>
private void ShowTextValue(object value, TypeInfo typeInfo)
{
switch (typeInfo.BuiltInType)
{
case BuiltInType.ByteString:
{
ShowTextValue((byte[])value);
break;
}
case BuiltInType.XmlElement:
{
ShowTextValue((XmlElement)value);
break;
}
case BuiltInType.String:
{
ShowTextValue((string)value);
break;
}
default:
{
ShowTextValue(ValueToString(value, typeInfo));
break;
}
}
}
/// <summary>
/// Displays a string in the control.
/// </summary>
private void ShowTextValue(string value)
{
ValuesDV.Visible = false;
TextValueTB.Visible = true;
if (value != null && value.Length > MaxDisplayTextLength)
{
TextValueTB.ScrollBars = ScrollBars.Both;
}
else
{
TextValueTB.ScrollBars = ScrollBars.None;
}
TextValueTB.Font = new Font("Segoe UI", TextValueTB.Font.Size);
TextValueTB.Text = value;
}
/// <summary>
/// Displays a complete byte string in the control.
/// </summary>
private void ShowTextValue(byte[] value)
{
ValuesDV.Visible = false;
TextValueTB.Visible = true;
StringBuilder buffer = new StringBuilder();
if (value != null)
{
for (int ii = 0; ii < value.Length; ii++)
{
if (buffer.Length > 0 && (ii % 30) == 0)
{
buffer.Append("\r\n");
}
buffer.AppendFormat("{0:X2} ", value[ii]);
}
}
TextValueTB.Font = new Font("Courier New", TextValueTB.Font.Size);
TextValueTB.Text = buffer.ToString();
}
/// <summary>
/// Displays a complete XML element in the control.
/// </summary>
private void ShowTextValue(XmlElement value)
{
ValuesDV.Visible = false;
TextValueTB.Visible = true;
StringBuilder buffer = new StringBuilder();
if (value != null)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.OmitXmlDeclaration = true;
settings.NewLineHandling = NewLineHandling.Replace;
settings.NewLineChars = "\r\n";
settings.IndentChars = " ";
using (XmlWriter writer = XmlWriter.Create(buffer, settings))
{
using (XmlNodeReader reader = new XmlNodeReader(value))
{
writer.WriteNode(reader, false);
}
}
}
TextValueTB.Font = new Font("Courier New", TextValueTB.Font.Size);
TextValueTB.Text = buffer.ToString();
}
/// <summary>
/// Converts a value to a string for display in the grid.
/// </summary>
private string ValueToString(object value, TypeInfo typeInfo)
{
if (value == null)
{
return String.Empty;
}
if (value is Variant)
{
Variant variant = (Variant)value;
value = variant.Value;
if (value != null)
{
typeInfo = variant.TypeInfo;
if (typeInfo == null)
{
typeInfo = TypeInfo.Construct(value);
}
}
}
if (typeInfo.ValueRank >= 0)
{
StringBuilder buffer = new StringBuilder();
System.Collections.IEnumerable enumerable = value as System.Collections.IEnumerable;
if (enumerable != null)
{
buffer.Append("{ ");
foreach (object element in enumerable)
{
if (buffer.Length > 2)
{
buffer.Append(" | ");
}
if (buffer.Length > MaxDisplayTextLength)
{
buffer.Append("...");
break;
}
buffer.Append(ValueToString(element, new TypeInfo(typeInfo.BuiltInType, ValueRanks.Scalar)));
}
buffer.Append(" }");
}
return buffer.ToString();
}
switch (typeInfo.BuiltInType)
{
case BuiltInType.String:
{
string text = (string)value;
if (text != null && text.Length > MaxDisplayTextLength)
{
return text.Substring(0, MaxDisplayTextLength) + "...";
}
return text;
}
case BuiltInType.ByteString:
{
StringBuilder buffer = new StringBuilder();
byte[] bytes = (byte[])value;
for (int ii = 0; ii < bytes.Length; ii++)
{
if (buffer.Length > MaxDisplayTextLength)
{
buffer.Append("...");
break;
}
buffer.AppendFormat("{0:X2}", bytes[ii]);
}
return buffer.ToString();
}
case BuiltInType.Enumeration:
{
return ((int)value).ToString();
}
case BuiltInType.ExtensionObject:
{
string text = null;
ExtensionObject extension = value as ExtensionObject;
if (extension != null)
{
if (extension.Body is byte[])
{
return ValueToString(extension.Body, new TypeInfo(BuiltInType.ByteString, ValueRanks.Scalar));
}
if (extension.Body is XmlElement)
{
return ValueToString(extension.Body, new TypeInfo(BuiltInType.XmlElement, ValueRanks.Scalar));
}
if (extension.Body is IEncodeable)
{
text = new Variant(extension).ToString();
}
}
if (text == null)
{
IEncodeable encodeable = value as IEncodeable;
if (encodeable != null)
{
text = new Variant(encodeable).ToString();
}
}
if (text != null && text.Length > MaxDisplayTextLength)
{
return text.Substring(0, MaxDisplayTextLength) + "...";
}
return text;
}
}
return (string)TypeInfo.Cast(value, BuiltInType.String);
}
/// <summary>
/// Whether the value can be edited in the grid view.
/// </summary>
private bool IsSimpleValue(AccessInfo info)
{
if (info == null || info.TypeInfo == null)
{
return true;
}
TypeInfo typeInfo = info.TypeInfo;
object value = info.Value;
if (value is Variant)
{
Variant variant = (Variant)info.Value;
typeInfo = variant.TypeInfo;
value = variant.Value;
if (typeInfo == null)
{
typeInfo = TypeInfo.Construct(value);
}
}
if (typeInfo.ValueRank >= 0)
{
return false;
}
switch (typeInfo.BuiltInType)
{
case BuiltInType.String:
{
string text = value as string;
if (text != null && text.Length >= MaxDisplayTextLength)
{
return false;
}
return true;
}
case BuiltInType.ByteString:
case BuiltInType.XmlElement:
case BuiltInType.QualifiedName:
case BuiltInType.LocalizedText:
case BuiltInType.DataValue:
case BuiltInType.ExtensionObject:
{
return false;
}
}
return true;
}
#endregion
private void NavigationMENU_Click(object sender, EventArgs e)
{
try
{
EndEdit();
ToolStripItem item = sender as ToolStripItem;
if (item != null)
{
// remove all menu items appearing after the selected item.
for (int ii = NavigationMENU.Items.Count-1; ii >= 0; ii--)
{
ToolStripItem target = NavigationMENU.Items[ii];
NavigationMENU.Items.Remove(target);
if (Object.ReferenceEquals(target, item))
{
break;
}
}
// show the current value.
AccessInfo info = (AccessInfo)item.Tag;
ShowValue(info);
}
}
catch (Exception exception)
{
ClientUtils.HandleException(this.Text, exception);
}
}
private void ValuesDV_DoubleClick(object sender, EventArgs e)
{
try
{
foreach (DataGridViewCell cell in ValuesDV.SelectedCells)
{
DataRowView source = ValuesDV.Rows[cell.RowIndex].DataBoundItem as DataRowView;
if (cell.ColumnIndex == 3)
{
AccessInfo info = (AccessInfo)source.Row[0];
ShowValue(info);
}
break;
}
}
catch (Exception exception)
{
ClientUtils.HandleException(this.Text, exception);
}
}
private void ValuesDV_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
try
{
if (this.Visible && e.ColumnIndex == 3)
{
DataRowView source = ValuesDV.Rows[e.RowIndex].DataBoundItem as DataRowView;
AccessInfo info = (AccessInfo)source.Row[0];
if (IsSimpleValue(info))
{
TypeInfo.Cast(e.FormattedValue, info.TypeInfo.BuiltInType);
}
}
}
catch (Exception exception)
{
ClientUtils.HandleException(this.Text, exception);
e.Cancel = true;
}
}
private void ValuesDV_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
try
{
if (this.Visible && e.RowIndex >= 0 && e.ColumnIndex == 3)
{
DataRowView source = ValuesDV.Rows[e.RowIndex].DataBoundItem as DataRowView;
AccessInfo info = (AccessInfo)source.Row[0];
if (IsSimpleValue(info))
{
object newValue = TypeInfo.Cast((string)source.Row[3], info.TypeInfo.BuiltInType);
info.Value = newValue;
UpdateParent(info);
}
}
}
catch (Exception exception)
{
ClientUtils.HandleException(this.Text, exception);
}
}
/// <summary>
/// Recusivesly updates the parent values.
/// </summary>
private void UpdateParent(AccessInfo info)
{
if (info.Parent == null)
{
return;
}
object parentValue = info.Parent.Value;
if (info.Parent.TypeInfo.BuiltInType == BuiltInType.Variant && info.Parent.TypeInfo.ValueRank < 0)
{
parentValue = ((Variant)info.Parent.Value).Value;
}
if (info.PropertyInfo != null && info.Parent.TypeInfo.ValueRank < 0)
{
ExtensionObject extension = parentValue as ExtensionObject;
if (extension != null)
{
parentValue = extension.Body;
}
info.PropertyInfo.SetValue(parentValue, info.Value, null);
}
else if (info.Indexes != null)
{
int[] indexes = info.Indexes;
Array array = parentValue as Array;
Matrix matrix = parentValue as Matrix;
if (matrix != null)
{
int count = 0;
int block = 1;
for (int ii = info.Indexes.Length-1; ii >= 0 ; ii--)
{
count += info.Indexes[ii] * block;
block *= matrix.Dimensions[ii];
}
array = matrix.Elements;
indexes = new int[] { count };
}
if (array != null)
{
if (info.Parent.TypeInfo.BuiltInType == BuiltInType.Variant && info.Parent.TypeInfo.ValueRank >= 0)
{
array.SetValue(new Variant(info.Value), indexes);
}
else
{
array.SetValue(info.Value, indexes);
}
}
else
{
IList list = parentValue as IList;
if (info.Parent.TypeInfo.BuiltInType == BuiltInType.Variant && info.Parent.TypeInfo.ValueRank >= 0)
{
list[indexes[0]] = new Variant(info.Value);
}
else
{
list[indexes[0]] = info.Value;
}
}
}
if (info.Parent != null)
{
UpdateParent(info.Parent);
}
}
}
}