PromptOnLongList(int length)
+ {
+ if (length < 256)
+ {
+ return true;
+ }
+ MessageDlg dialog = new MessageDlg("It may take a long time to display the list are you sure you want to continue?", MessageDlgButton.Yes, MessageDlgButton.No);
+ MessageDlgButton result = await dialog.ShowAsync();
+ if (result != MessageDlgButton.Yes)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Shows the element of a list in the control.
+ ///
+ private void ShowValue(ref int index, ref bool overwrite, IList value, int element)
+ {
+ // get the name of the element.
+ string name = Utils.Format("[{0}]", element);
+
+ // get the element value.
+ object elementValue = value[element];
+
+ // get the type name.
+ string type = null;
+
+ if (elementValue != null)
+ {
+ type = elementValue.GetType().Name;
+ }
+
+ // update the list view.
+ UpdateList(
+ ref index,
+ ref overwrite,
+ value,
+ elementValue,
+ element,
+ name,
+ type);
+ }
+
+ ///
+ /// Shows an XML element in the control.
+ ///
+ private void ShowValue(ref int index, ref bool overwrite, XmlElement value, int childIndex)
+ {
+ // ignore children that are not elements.
+ XmlElement child = value.ChildNodes[childIndex] as XmlElement;
+
+ if (child == null)
+ {
+ return;
+ }
+
+ // get the name of the element.
+ string name = Utils.Format("{0}", child.Name);
+
+ // get the type name.
+ string type = value.GetType().Name;
+
+ // update the list view.
+ UpdateList(
+ ref index,
+ ref overwrite,
+ value,
+ child,
+ childIndex,
+ name,
+ type);
+ }
+
+ ///
+ /// Shows an event in the control.
+ ///
+ private void ShowValue(ref int index, ref bool overwrite, EventFieldList value, int fieldIndex)
+ {
+ // ignore children that are not elements.
+ object field = value.EventFields[fieldIndex].Value;
+
+ if (field == null)
+ {
+ return;
+ }
+
+ // get the name of the element.
+ string name = null;
+
+ if (m_monitoredItem != null)
+ {
+ name = m_monitoredItem.GetFieldName(fieldIndex);
+ }
+
+ // get the type name.
+ string type = value.GetType().Name;
+
+ // update the list view.
+ UpdateList(
+ ref index,
+ ref overwrite,
+ value,
+ field,
+ fieldIndex,
+ name,
+ type);
+ }
+
+ ///
+ /// Shows a byte array in the control.
+ ///
+ private void ShowValue(ref int index, ref bool overwrite, byte[] value, int blockStart)
+ {
+ // get the name of the element.
+ string name = Utils.Format("[{0:X4}]", blockStart);
+
+ int bytesLeft = value.Length - blockStart;
+
+ if (bytesLeft > 16)
+ {
+ bytesLeft = 16;
+ }
+
+ // get the element value.
+ byte[] blockValue = new byte[bytesLeft];
+ Array.Copy(value, blockStart, blockValue, 0, bytesLeft);
+
+ // get the type name.
+ string type = value.GetType().Name;
+
+ // update the list view.
+ UpdateList(
+ ref index,
+ ref overwrite,
+ value,
+ blockValue,
+ blockStart,
+ name,
+ type);
+ }
+
+ ///
+ /// Shows a data value in the control.
+ ///
+ private void ShowValue(ref int index, ref bool overwrite, DataValue value, int component)
+ {
+ string name = null;
+ object componentValue = null;
+
+ switch (component)
+ {
+ case 0:
+ {
+ name = "Value";
+ componentValue = value.Value;
+
+ ExtensionObject extension = componentValue as ExtensionObject;
+
+ if (extension != null)
+ {
+ componentValue = extension.Body;
+ }
+
+ break;
+ }
+
+ case 1:
+ {
+ name = "StatusCode";
+ componentValue = value.StatusCode;
+ break;
+ }
+
+ case 2:
+ {
+ if (value.SourceTimestamp != DateTime.MinValue)
+ {
+ name = "SourceTimestamp";
+ componentValue = value.SourceTimestamp;
+ }
+
+ break;
+ }
+
+ case 3:
+ {
+ if (value.ServerTimestamp != DateTime.MinValue)
+ {
+ name = "ServerTimestamp";
+ componentValue = value.ServerTimestamp;
+ }
+
+ break;
+ }
+ }
+
+ // don't display empty components.
+ if (name == null)
+ {
+ return;
+ }
+
+ // get the type name.
+ string type = "(unknown)";
+
+ if (componentValue != null)
+ {
+ type = componentValue.GetType().Name;
+ }
+
+ // update the list view.
+ UpdateList(
+ ref index,
+ ref overwrite,
+ value,
+ componentValue,
+ component,
+ name,
+ type);
+ }
+
+ ///
+ /// Shows a node id in the control.
+ ///
+ private void ShowValue(ref int index, ref bool overwrite, NodeId value, int component)
+ {
+ string name = null;
+ object componentValue = null;
+
+ switch (component)
+ {
+ case 0:
+ {
+ name = "IdType";
+ componentValue = value.IdType;
+ break;
+ }
+
+ case 1:
+ {
+ name = "Identifier";
+ componentValue = value.Identifier;
+ break;
+ }
+
+ case 2:
+ {
+ name = "NamespaceIndex";
+ componentValue = value.NamespaceIndex;
+ break;
+ }
+ }
+
+ // don't display empty components.
+ if (name == null)
+ {
+ return;
+ }
+
+ // get the type name.
+ string type = "(unknown)";
+
+ if (componentValue != null)
+ {
+ type = componentValue.GetType().Name;
+ }
+
+ // update the list view.
+ UpdateList(
+ ref index,
+ ref overwrite,
+ value,
+ componentValue,
+ component,
+ name,
+ type);
+ }
+
+ ///
+ /// Shows am expanded node id in the control.
+ ///
+ private void ShowValue(ref int index, ref bool overwrite, ExpandedNodeId value, int component)
+ {
+ string name = null;
+ object componentValue = null;
+
+ switch (component)
+ {
+ case 0:
+ {
+ name = "IdType";
+ componentValue = value.IdType;
+ break;
+ }
+
+ case 1:
+ {
+ name = "Identifier";
+ componentValue = value.Identifier;
+ break;
+ }
+
+ case 2:
+ {
+ name = "NamespaceIndex";
+ componentValue = value.NamespaceIndex;
+ break;
+ }
+
+ case 3:
+ {
+ name = "NamespaceUri";
+ componentValue = value.NamespaceUri;
+ break;
+ }
+ }
+
+ // don't display empty components.
+ if (name == null)
+ {
+ return;
+ }
+
+ // get the type name.
+ string type = "(unknown)";
+
+ if (componentValue != null)
+ {
+ type = componentValue.GetType().Name;
+ }
+
+ // update the list view.
+ UpdateList(
+ ref index,
+ ref overwrite,
+ value,
+ componentValue,
+ component,
+ name,
+ type);
+ }
+
+ ///
+ /// Shows qualified name in the control.
+ ///
+ private void ShowValue(ref int index, ref bool overwrite, QualifiedName value, int component)
+ {
+ string name = null;
+ object componentValue = null;
+
+ switch (component)
+ {
+ case 0:
+ {
+ name = "Name";
+ componentValue = value.Name;
+ break;
+ }
+
+ case 1:
+ {
+ name = "NamespaceIndex";
+ componentValue = value.NamespaceIndex;
+ break;
+ }
+ }
+
+ // don't display empty components.
+ if (name == null)
+ {
+ return;
+ }
+
+ // get the type name.
+ string type = "(unknown)";
+
+ if (componentValue != null)
+ {
+ type = componentValue.GetType().Name;
+ }
+
+ // update the list view.
+ UpdateList(
+ ref index,
+ ref overwrite,
+ value,
+ componentValue,
+ component,
+ name,
+ type);
+ }
+
+ ///
+ /// Shows localized text in the control.
+ ///
+ private void ShowValue(ref int index, ref bool overwrite, LocalizedText value, int component)
+ {
+ string name = null;
+ object componentValue = null;
+
+ switch (component)
+ {
+ case 0:
+ {
+ name = "Text";
+ componentValue = value.Text;
+ break;
+ }
+
+ case 1:
+ {
+ name = "Locale";
+ componentValue = value.Locale;
+ break;
+ }
+ }
+
+ // don't display empty components.
+ if (name == null)
+ {
+ return;
+ }
+
+ // get the type name.
+ string type = "(unknown)";
+
+ if (componentValue != null)
+ {
+ type = componentValue.GetType().Name;
+ }
+
+ // update the list view.
+ UpdateList(
+ ref index,
+ ref overwrite,
+ value,
+ componentValue,
+ component,
+ name,
+ type);
+ }
+
+ ///
+ /// Shows a string in the control.
+ ///
+ private void ShowValue(ref int index, ref bool overwrite, string value)
+ {
+ string name = "Value";
+ object componentValue = value;
+
+ // don't display empty components.
+ if (name == null)
+ {
+ return;
+ }
+
+ // get the type name.
+ string type = "(unknown)";
+
+ if (componentValue != null)
+ {
+ type = componentValue.GetType().Name;
+ }
+
+ // update the list view.
+ UpdateList(
+ ref index,
+ ref overwrite,
+ value,
+ componentValue,
+ 0,
+ name,
+ type);
+ }
+
+ ///
+ /// Shows a value in control.
+ ///
+ private async Task ShowValue(int index, bool overwrite, object value)
+ {
+ if (value == null)
+ {
+ return;
+ }
+
+ // show monitored items.
+ MonitoredItem monitoredItem = value as MonitoredItem;
+
+ if (monitoredItem != null)
+ {
+ m_monitoredItem = monitoredItem;
+ ShowValue(ref index, ref overwrite, monitoredItem.LastValue.ToString());
+ return;
+ }
+
+ // show data changes
+ MonitoredItemNotification datachange = value as MonitoredItemNotification;
+
+ if (datachange != null)
+ {
+ ShowValue(ref index, ref overwrite, datachange.Value.ToString());
+ return;
+ }
+
+ // show events
+ EventFieldList eventFields = value as EventFieldList;
+
+ if (eventFields != null)
+ {
+ for (int ii = 0; ii < eventFields.EventFields.Count; ii++)
+ {
+ ShowValue(ref index, ref overwrite, eventFields, ii);
+ }
+
+ return;
+ }
+
+ // show extension bodies.
+ ExtensionObject extension = value as ExtensionObject;
+
+ if (extension != null)
+ {
+ ShowValue(ref index, ref overwrite, extension.Body.ToString());
+ return;
+ }
+
+ // show encodeables.
+ IEncodeable encodeable = value as IEncodeable;
+
+ if (encodeable != null)
+ {
+ PropertyInfo[] properties = encodeable.GetType().GetProperties();
+
+ foreach (PropertyInfo property in properties)
+ {
+ ShowValue(ref index, ref overwrite, encodeable, property);
+ }
+
+ return;
+ }
+
+ // show bytes.
+ byte[] bytes = value as byte[];
+
+ if (bytes != null)
+ {
+ bool result = await PromptOnLongList(bytes.Length / 16);
+ if (!result)
+ {
+ return;
+ }
+
+ for (int ii = 0; ii < bytes.Length; ii += 16)
+ {
+ ShowValue(ref index, ref overwrite, bytes, ii);
+ }
+
+ return;
+ }
+
+ // show arrays
+ Array array = value as Array;
+
+ if (array != null)
+ {
+ bool result = await PromptOnLongList(array.Length);
+ if (!result)
+ {
+ return;
+ }
+
+ for (int ii = 0; ii < array.Length; ii++)
+ {
+ ShowValue(ref index, ref overwrite, array, ii);
+ }
+
+ return;
+ }
+
+ // show lists
+ IList list = value as IList;
+
+ if (list != null)
+ {
+ bool result = await PromptOnLongList(list.Count);
+ if (!result)
+ {
+ return;
+ }
+
+ for (int ii = 0; ii < list.Count; ii++)
+ {
+ ShowValue(ref index, ref overwrite, list, ii);
+ }
+
+ return;
+ }
+
+ // show xml elements
+ XmlElement xml = value as XmlElement;
+
+ if (xml != null)
+ {
+ bool result = await PromptOnLongList(xml.ChildNodes.Count);
+ if (!result)
+ {
+ return;
+ }
+
+ for (int ii = 0; ii < xml.ChildNodes.Count; ii++)
+ {
+ ShowValue(ref index, ref overwrite, xml, ii);
+ }
+
+ return;
+ }
+
+ // show data value.
+ DataValue datavalue = value as DataValue;
+
+ if (datavalue != null)
+ {
+ ShowValue(ref index, ref overwrite, datavalue, 0);
+ ShowValue(ref index, ref overwrite, datavalue, 1);
+ ShowValue(ref index, ref overwrite, datavalue, 2);
+ ShowValue(ref index, ref overwrite, datavalue, 3);
+ return;
+ }
+
+ // show node id value.
+ NodeId nodeId = value as NodeId;
+
+ if (nodeId != null)
+ {
+ ShowValue(ref index, ref overwrite, nodeId, 0);
+ ShowValue(ref index, ref overwrite, nodeId, 1);
+ ShowValue(ref index, ref overwrite, nodeId, 2);
+ return;
+ }
+
+ // show expanded node id value.
+ ExpandedNodeId expandedNodeId = value as ExpandedNodeId;
+
+ if (expandedNodeId != null)
+ {
+ ShowValue(ref index, ref overwrite, expandedNodeId, 0);
+ ShowValue(ref index, ref overwrite, expandedNodeId, 1);
+ ShowValue(ref index, ref overwrite, expandedNodeId, 2);
+ ShowValue(ref index, ref overwrite, expandedNodeId, 3);
+ return;
+ }
+
+ // show qualified name value.
+ QualifiedName qualifiedName = value as QualifiedName;
+
+ if (qualifiedName != null)
+ {
+ ShowValue(ref index, ref overwrite, qualifiedName, 0);
+ ShowValue(ref index, ref overwrite, qualifiedName, 1);
+ return;
+ }
+
+ // show qualified name value.
+ LocalizedText localizedText = value as LocalizedText;
+
+ if (localizedText != null)
+ {
+ ShowValue(ref index, ref overwrite, localizedText, 0);
+ ShowValue(ref index, ref overwrite, localizedText, 1);
+ return;
+ }
+
+ // show variant.
+ Variant? variant = value as Variant?;
+
+ if (variant != null)
+ {
+ ShowValue(ref index, ref overwrite, variant.Value.Value.ToString());
+ return;
+ }
+
+ // show unknown types as strings.
+ ShowValue(ref index, ref overwrite, String.Format("{0}", value));
+ }
+ #endregion
+ }
+}
diff --git a/SampleApplications/SDK/Controls/Common (OLD)/DateTimeValueEditCtrl.xaml b/SampleApplications/SDK/Controls/Common (OLD)/DateTimeValueEditCtrl.xaml
new file mode 100644
index 0000000000..577744e447
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Common (OLD)/DateTimeValueEditCtrl.xaml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
diff --git a/SampleApplications/SDK/Controls/Common (OLD)/DateTimeValueEditCtrl.xaml.cs b/SampleApplications/SDK/Controls/Common (OLD)/DateTimeValueEditCtrl.xaml.cs
new file mode 100644
index 0000000000..5661863118
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Common (OLD)/DateTimeValueEditCtrl.xaml.cs
@@ -0,0 +1,27 @@
+using System;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Controls.Primitives;
+
+// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236
+
+namespace Opc.Ua.Client.Controls
+{
+ public sealed partial class DateTimeValueEditCtrl : UserControl
+ {
+ public DateTime localValue;
+
+ public DateTimeValueEditCtrl(DateTime value)
+ {
+ this.InitializeComponent();
+ this.Date.Date = value.Date;
+ this.Time.Time = value.TimeOfDay;
+ }
+
+ private void button_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
+ {
+ Popup p = this.Parent as Popup;
+ p.IsOpen = false;
+ localValue = new DateTime(Date.Date.Year, Date.Date.Month, Date.Date.Day, Time.Time.Hours, Time.Time.Minutes, Time.Time.Seconds);
+ }
+ }
+}
diff --git a/SampleApplications/SDK/Controls/Common (OLD)/ExceptionDlg.xaml b/SampleApplications/SDK/Controls/Common (OLD)/ExceptionDlg.xaml
new file mode 100644
index 0000000000..6d0cb11be7
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Common (OLD)/ExceptionDlg.xaml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
diff --git a/SampleApplications/SDK/Controls/Common (OLD)/ExceptionDlg.xaml.cs b/SampleApplications/SDK/Controls/Common (OLD)/ExceptionDlg.xaml.cs
new file mode 100644
index 0000000000..647bec858e
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Common (OLD)/ExceptionDlg.xaml.cs
@@ -0,0 +1,130 @@
+/* ========================================================================
+ * Copyright (c) 2005-2013 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 Opc.Ua;
+using System;
+using System.Text;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Controls.Primitives;
+
+namespace Opc.Ua.Client.Controls
+{
+ ///
+ /// A dialog that displays an exception trace in an HTML page.
+ ///
+ public sealed partial class ExceptionDlg : Page
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ExceptionDlg()
+ {
+ InitializeComponent();
+ }
+
+ ///
+ /// Replaces all special characters in the message.
+ ///
+ private string ReplaceSpecialCharacters(string message)
+ {
+ message = message.Replace("&", "&");
+ message = message.Replace("<", "<");
+ message = message.Replace(">", ">");
+ message = message.Replace("\"", """);
+ message = message.Replace("'", "'");
+ message = message.Replace("\r\n", "
");
+
+ return message;
+ }
+
+ ///
+ /// Display the exception in the dialog.
+ ///
+ public void ShowDialog(string caption, Exception e)
+ {
+ Text.Text = caption;
+
+ StringBuilder buffer = new StringBuilder();
+
+ buffer.Append("");
+
+ while (e != null)
+ {
+ string message = e.Message;
+
+ ServiceResultException exception = e as ServiceResultException;
+
+ if (exception != null)
+ {
+ message = exception.ToLongString();
+ }
+
+ message = ReplaceSpecialCharacters(message);
+
+ if (exception != null)
+ {
+ buffer.Append("");
+ buffer.Append("");
+ buffer.Append(message);
+ buffer.Append("");
+ buffer.Append("
");
+ }
+ else
+ {
+ buffer.Append("");
+ buffer.Append(message);
+ buffer.Append("
");
+ }
+
+ message = e.StackTrace;
+
+ if (!String.IsNullOrEmpty(message))
+ {
+ message = ReplaceSpecialCharacters(message);
+
+ buffer.Append("");
+ buffer.Append("");
+ buffer.Append(message);
+ buffer.Append("");
+ buffer.Append("
");
+ }
+
+ e = e.InnerException;
+ }
+
+ buffer.Append("");
+
+ ExceptionBrowser.NavigateToString(buffer.ToString());
+
+ Popup myPopup = new Popup();
+ myPopup.Child = this;
+ myPopup.IsOpen = true;
+ }
+ }
+}
diff --git a/SampleApplications/SDK/Controls/Common (OLD)/GuiUtils.cs b/SampleApplications/SDK/Controls/Common (OLD)/GuiUtils.cs
new file mode 100644
index 0000000000..25c2b897e7
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Common (OLD)/GuiUtils.cs
@@ -0,0 +1,892 @@
+/* ========================================================================
+ * Copyright (c) 2005-2013 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.Generic;
+using System.Text;
+using System.Security.Cryptography.X509Certificates;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Popups;
+using Windows.UI.Xaml.Controls.Primitives;
+using System.Runtime.CompilerServices;
+using Windows.Storage;
+using System.Threading.Tasks;
+using Windows.UI.Xaml;
+
+namespace Opc.Ua.Client.Controls
+{
+ ///
+ /// A class that provide various common utility functions and shared resources.
+ ///
+ public partial class GuiUtils
+ {
+ public static string CallerName([CallerMemberName]string caller = "")
+ {
+ return caller;
+ }
+
+ ///
+ /// The list of icon images.
+ ///
+ public List ImageList;
+
+ ///
+ /// Displays the details of an exception.
+ ///
+ public delegate void ExceptionMessageDlgEventHandler(string message);
+ public static event ExceptionMessageDlgEventHandler ExceptionMessageDlg;
+ public static void HandleException(string caption, string callerName, Exception e)
+ {
+ if (String.IsNullOrEmpty(caption))
+ {
+ caption = callerName;
+ }
+ Utils.Trace("HandleException:{0}:{1}:{2}", caption, callerName, e.Message);
+ if (ExceptionMessageDlg != null)
+ {
+ StringBuilder buffer = new StringBuilder();
+ buffer.AppendFormat("HandleException: {0}\r\n\r\n", caption);
+ buffer.AppendFormat("Caller: {0}\r\n", callerName);
+ buffer.AppendFormat("Exception: {0}\r\n", e.Message);
+ ExceptionMessageDlg(buffer.ToString());
+ }
+ }
+
+ ///
+ /// Defines names for the available 16x16 icons.
+ ///
+ public static class Icons
+ {
+ ///
+ /// An attribute
+ ///
+ public const string Attribute = "SimpleItem";
+
+ ///
+ /// A property
+ ///
+ public const string Property = "Property";
+
+ ///
+ /// A variable
+ ///
+ public const string Variable = "Variable";
+
+ ///
+ /// An object
+ ///
+ public const string Object = "Object";
+
+ ///
+ /// A method
+ ///
+ public const string Method = "Method";
+
+ ///
+ /// A single computer.
+ ///
+ public const string Computer = "Computer";
+
+ ///
+ /// A computer network.
+ ///
+ public const string Network = "Network";
+
+ ///
+ /// A folder.
+ ///
+ public const string Folder = "Folder";
+
+ ///
+ /// A selected folder.
+ ///
+ public const string SelectedFolder = "SelectedFolder";
+
+ ///
+ /// A process or application.
+ ///
+ public const string Process = "Process";
+
+ ///
+ /// A certificate
+ ///
+ public const string Certificate = "Certificate";
+
+ ///
+ /// An invalid certificate
+ ///
+ public const string InvalidCertificate = "InvalidCertificate";
+
+ ///
+ /// A certificate store
+ ///
+ public const string CertificateStore = "CertificateStore";
+
+ ///
+ /// A group of users.
+ ///
+ public const string Users = "Users";
+
+ ///
+ /// A service.
+ ///
+ public const string Service = "Service";
+
+ ///
+ /// A logical drive.
+ ///
+ public const string Drive = "Drive";
+
+ ///
+ /// The computer desktop.
+ ///
+ public const string Desktop = "Desktop";
+
+ ///
+ /// A single user.
+ ///
+ public const string SingleUser = "SingleUser";
+
+ ///
+ /// A group of services.
+ ///
+ public const string ServiceGroup = "ServiceGroup";
+
+ ///
+ /// A group of users.
+ ///
+ public const string UserGroup = "UserGroup";
+
+ ///
+ /// A green check
+ ///
+ public const string GreenCheck = "GreenCheck";
+
+ ///
+ /// A red cross
+ ///
+ public const string RedCross = "RedCross";
+
+ ///
+ /// A users icon with a red cross through it.
+ ///
+ public const string UsersRedCross = "UsersRedCross";
+ }
+
+ ///
+ /// Uses the command line to override the UA TCP implementation specified in the configuration.
+ ///
+ /// The configuration instance that stores the configurable information for a UA application.
+ ///
+ public static void OverrideUaTcpImplementation(ApplicationConfiguration configuration)
+ {
+ // check if UA TCP configuration included.
+ TransportConfiguration transport = null;
+
+ for (int ii = 0; ii < configuration.TransportConfigurations.Count; ii++)
+ {
+ if (configuration.TransportConfigurations[ii].UriScheme == Utils.UriSchemeOpcTcp)
+ {
+ transport = configuration.TransportConfigurations[ii];
+ break;
+ }
+ }
+ }
+
+ ///
+ /// Displays the UA-TCP configuration in the form.
+ ///
+ /// The form to display the UA-TCP configuration.
+ /// The configuration instance that stores the configurable information for a UA application.
+ public static void DisplayUaTcpImplementation(Page form, ApplicationConfiguration configuration)
+ {
+ // check if UA TCP configuration included.
+ TransportConfiguration transport = null;
+
+ for (int ii = 0; ii < configuration.TransportConfigurations.Count; ii++)
+ {
+ if (configuration.TransportConfigurations[ii].UriScheme == Utils.UriSchemeOpcTcp)
+ {
+ transport = configuration.TransportConfigurations[ii];
+ break;
+ }
+ }
+ }
+
+ ///
+ /// Handles a certificate validation error.
+ ///
+ /// The caller's text is used as the caption of the shown to provide details about the error.
+ /// The validator (not used).
+ /// The instance event arguments provided when a certificate validation error occurs.
+ public static async Task HandleCertificateValidationError(Page caller, CertificateValidator validator, CertificateValidationEventArgs e)
+ {
+ StringBuilder buffer = new StringBuilder();
+
+ buffer.AppendFormat("Certificate could not validated: {0}\r\n\r\n", e.Error.StatusCode);
+ buffer.AppendFormat("Subject: {0}\r\n", e.Certificate.Subject);
+ buffer.AppendFormat("Issuer: {0}\r\n", (e.Certificate.Subject == e.Certificate.Issuer) ? "Self-signed" : e.Certificate.Issuer);
+ buffer.AppendFormat("Thumbprint: {0}\r\n\r\n", e.Certificate.Thumbprint);
+
+ buffer.AppendFormat("Accept anyways?");
+ MessageDlg dialog = new MessageDlg(buffer.ToString(), MessageDlgButton.Yes, MessageDlgButton.No);
+ MessageDlgButton result = await dialog.ShowAsync();
+ if (result == MessageDlgButton.Yes)
+ {
+ e.Accept = true;
+ }
+ }
+
+ ///
+ /// Does any configuration checks before starting up.
+ ///
+ public static async Task LoadConfiguration(
+ string configSectionName,
+ ApplicationType applicationType,
+ string defaultConfigFile,
+ bool interactive)
+ {
+ // get the location of the config file.
+ string filePath = ApplicationConfiguration.GetFilePathFromAppConfig(configSectionName);
+
+ if (filePath == null || !System.IO.File.Exists(filePath))
+ {
+ filePath = Utils.GetAbsoluteFilePath(defaultConfigFile, false, false, false);
+ }
+
+ try
+ {
+ // load the configuration file.
+ ApplicationConfiguration configuration = await ApplicationConfiguration.Load(new System.IO.FileInfo(filePath), applicationType, null);
+
+ if (configuration == null)
+ {
+ return null;
+ }
+
+ return configuration;
+ }
+ catch (Exception e)
+ {
+ // warn user.
+ if (interactive)
+ {
+ StringBuilder message = new StringBuilder();
+
+ message.Append("Could not load configuration file.\r\n");
+ message.Append(filePath);
+ message.Append("\r\n");
+ message.Append("\r\n");
+ message.Append(e.Message);
+ MessageDlg dialog = new MessageDlg(message.ToString());
+ await dialog.ShowAsync();
+ Utils.Trace(e, "Could not load configuration file. {0}", filePath);
+ }
+
+ return null;
+ }
+ }
+
+ ///
+ /// Does any configuration checks before starting up.
+ ///
+ public static async Task DoStartupChecks(
+ string configSectionName,
+ ApplicationType applicationType,
+ string defaultConfigFile,
+ bool interactive)
+ {
+ // load the configuration file.
+ ApplicationConfiguration configuration = await LoadConfiguration(configSectionName, applicationType, defaultConfigFile, interactive);
+
+ if (configuration == null)
+ {
+ return null;
+ }
+
+ // check the certificate.
+ X509Certificate2 certificate = await CheckApplicationInstanceCertificate(configuration, 1024, interactive, true);
+
+ if (certificate == null)
+ {
+ return null;
+ }
+
+ // ensure the application uri matches the certificate.
+ string applicationUri = Utils.GetApplicationUriFromCertficate(certificate);
+
+ if (applicationUri != null)
+ {
+ configuration.ApplicationUri = applicationUri;
+ }
+
+ return configuration;
+ }
+
+ ///
+ /// Configures the firewall.
+ ///
+ /// The configuration.
+ /// if set to true if the user should be prompted.
+ public static void ConfigureFirewall(ApplicationConfiguration configuration, bool interactive)
+ {
+ // check if application configuration requires it.
+ if (!configuration.SecurityConfiguration.ConfigureFirewall)
+ {
+ return;
+ }
+
+ // ensure the firewall is configured.
+ if (configuration.ServerConfiguration == null && configuration.DiscoveryServerConfiguration == null)
+ {
+ return;
+ }
+
+ // check if there are any ports to open.
+ StringCollection baseAddresses = null;
+
+ if (configuration.ServerConfiguration != null)
+ {
+ baseAddresses = configuration.ServerConfiguration.BaseAddresses;
+ }
+
+ if (configuration.DiscoveryServerConfiguration != null)
+ {
+ baseAddresses = configuration.DiscoveryServerConfiguration.BaseAddresses;
+ }
+
+ if (baseAddresses == null || baseAddresses.Count == 0)
+ {
+ return;
+ }
+ }
+
+ ///
+ /// Deletes an existing application instance certificate.
+ ///
+ /// The configuration instance that stores the configurable information for a UA application.
+ public static async Task DeleteApplicationInstanceCertificate(ApplicationConfiguration configuration)
+ {
+ // create a default certificate id none specified.
+ CertificateIdentifier id = configuration.SecurityConfiguration.ApplicationCertificate;
+
+ if (id == null)
+ {
+ return;
+ }
+
+ // delete private key.
+ X509Certificate2 certificate = await id.Find();
+
+ // delete trusted peer certificate.
+ if (configuration.SecurityConfiguration != null && configuration.SecurityConfiguration.TrustedPeerCertificates != null)
+ {
+ string thumbprint = id.Thumbprint;
+
+ if (certificate != null)
+ {
+ thumbprint = certificate.Thumbprint;
+ }
+
+ if (!String.IsNullOrEmpty(thumbprint))
+ {
+ using (ICertificateStore store = configuration.SecurityConfiguration.TrustedPeerCertificates.OpenStore())
+ {
+ await store.Delete(thumbprint);
+ }
+ }
+ }
+
+ // delete private key.
+ if (certificate != null)
+ {
+ using (ICertificateStore store = id.OpenStore())
+ {
+ await store.Delete(certificate.Thumbprint);
+ }
+ }
+ }
+
+ ///
+ /// Creates an application instance certificate if one does not already exist.
+ ///
+ public static async Task CheckApplicationInstanceCertificate(ApplicationConfiguration configuration)
+ {
+ return await CheckApplicationInstanceCertificate(configuration, 1024, true, true);
+ }
+
+ ///
+ /// Creates an application instance certificate if one does not already exist.
+ ///
+ public static async Task CheckApplicationInstanceCertificate(
+ ApplicationConfiguration configuration,
+ ushort keySize,
+ bool interactive,
+ bool updateFile)
+ {
+ // create a default certificate if none is specified.
+ CertificateIdentifier id = configuration.SecurityConfiguration.ApplicationCertificate;
+
+ if (id == null)
+ {
+ id = new CertificateIdentifier();
+ id.StoreType = Utils.DefaultStoreType;
+ id.StorePath = ApplicationData.Current.LocalFolder.Path + "\\OPC Foundation\\CertificateStores\\MachineDefault";
+ id.SubjectName = configuration.ApplicationName;
+ }
+
+ bool createNewCertificate = false;
+ IList serverDomainNames = configuration.GetServerDomainNames();
+
+ // check for private key.
+ X509Certificate2 certificate = await id.Find(true);
+
+ if (certificate == null)
+ {
+ // check if config file has wrong thumprint.
+ if (!String.IsNullOrEmpty(id.SubjectName) && !String.IsNullOrEmpty(id.Thumbprint))
+ {
+ CertificateIdentifier id2 = new CertificateIdentifier();
+ id2.StoreType = id.StoreType;
+ id2.StorePath = id.StorePath;
+ id2.SubjectName = id.SubjectName;
+ id = id2;
+
+ certificate = await id2.Find(true);
+
+ if (certificate != null)
+ {
+ string message = Utils.Format(
+ "Matching certificate with SubjectName={0} found but with a different thumbprint. Use certificate?",
+ id.SubjectName);
+
+ if (interactive)
+ {
+ MessageDlg dialog = new MessageDlg(message, MessageDlgButton.Yes, MessageDlgButton.No);
+ MessageDlgButton result = await dialog.ShowAsync();
+ if (result != MessageDlgButton.Yes)
+ {
+ certificate = null;
+ }
+ }
+ }
+ }
+
+ // check if private key is missing.
+ if (certificate == null)
+ {
+ certificate = await id.Find(false);
+
+ if (certificate != null)
+ {
+ string message = Utils.Format(
+ "Matching certificate with SubjectName={0} found but without a private key. Create a new certificate?",
+ id.SubjectName);
+
+ if (interactive)
+ {
+ MessageDlg dialog = new MessageDlg(message, MessageDlgButton.Yes, MessageDlgButton.No);
+ MessageDlgButton result = await dialog.ShowAsync();
+ if (result != MessageDlgButton.Yes)
+ {
+ certificate = null;
+ }
+ }
+ }
+ }
+
+ // check domains.
+ if (certificate != null)
+ {
+ IList certificateDomainNames = Utils.GetDomainsFromCertficate(certificate);
+
+ for (int ii = 0; ii < serverDomainNames.Count; ii++)
+ {
+ if (Utils.FindStringIgnoreCase(certificateDomainNames, serverDomainNames[ii]))
+ {
+ continue;
+ }
+
+ if (String.Compare(serverDomainNames[ii], "localhost", StringComparison.OrdinalIgnoreCase) == 0)
+ {
+ // check computer name.
+ string computerName = Utils.GetHostName();
+
+ if (Utils.FindStringIgnoreCase(certificateDomainNames, computerName))
+ {
+ continue;
+ }
+ }
+
+ string message = Utils.Format(
+ "The server is configured to use domain '{0}' which does not appear in the certificate. Create new certificate?",
+ serverDomainNames[ii]);
+
+ createNewCertificate = true;
+
+ if (interactive)
+ {
+ MessageDlg dialog = new MessageDlg(message, MessageDlgButton.Yes, MessageDlgButton.No);
+ MessageDlgButton result = await dialog.ShowAsync();
+ if (result != MessageDlgButton.Yes)
+ {
+ createNewCertificate = false;
+ continue;
+ }
+ }
+
+ Utils.Trace(message);
+ break;
+ }
+
+ if (!createNewCertificate)
+ {
+ // check if key size matches.
+ if (keySize == certificate.GetRSAPublicKey().KeySize)
+ {
+ await AddToTrustedStore(configuration, certificate);
+ return certificate;
+ }
+ }
+ }
+
+ // prompt user.
+ if (interactive)
+ {
+ if (!createNewCertificate)
+ {
+ MessageDlg dialog = new MessageDlg("Application does not have an instance certificate.\n Create one automatically?", MessageDlgButton.Yes, MessageDlgButton.No);
+ MessageDlgButton result = await dialog.ShowAsync();
+ if (result != MessageDlgButton.Yes)
+ {
+ return null;
+ }
+ }
+ }
+
+ // delete existing certificate.
+ if (certificate != null)
+ {
+ await DeleteApplicationInstanceCertificate(configuration);
+ }
+
+ // add the localhost.
+ if (serverDomainNames.Count == 0)
+ {
+ serverDomainNames.Add(Utils.GetHostName());
+ }
+
+ certificate = await Opc.Ua.CertificateFactory.CreateCertificate(
+ id.StoreType,
+ id.StorePath,
+ configuration.ApplicationUri,
+ configuration.ApplicationName,
+ null,
+ serverDomainNames,
+ keySize,
+ 300);
+
+ id.Certificate = certificate;
+ await AddToTrustedStore(configuration, certificate);
+
+ if (updateFile && !String.IsNullOrEmpty(configuration.SourceFilePath))
+ {
+ configuration.SaveToFile(configuration.SourceFilePath);
+ }
+
+ await configuration.CertificateValidator.Update(configuration.SecurityConfiguration);
+
+ return await configuration.SecurityConfiguration.ApplicationCertificate.LoadPrivateKey(null);
+ }
+
+ return certificate;
+ }
+
+ ///
+ /// Adds the certificate to the Trusted Certificate Store
+ ///
+ /// The application's configuration which specifies the location of the TrustedStore.
+ /// The certificate to register.
+ public static async Task AddToTrustedStore(ApplicationConfiguration configuration, X509Certificate2 certificate)
+ {
+ ICertificateStore store = configuration.SecurityConfiguration.TrustedPeerCertificates.OpenStore();
+
+ try
+ {
+ // check if it already exists.
+ X509Certificate2Collection existingCertificates = await store.FindByThumbprint(certificate.Thumbprint);
+
+ if (existingCertificates.Count > 0)
+ {
+ return;
+ }
+
+ List subjectName = Utils.ParseDistinguishedName(certificate.Subject);
+
+ // check for old certificate.
+ X509Certificate2Collection certificates = await store.Enumerate();
+
+ for (int ii = 0; ii < certificates.Count; ii++)
+ {
+ if (Utils.CompareDistinguishedName(certificates[ii], subjectName))
+ {
+ if (certificates[ii].Thumbprint == certificate.Thumbprint)
+ {
+ return;
+ }
+
+ await store.Delete(certificates[ii].Thumbprint);
+ break;
+ }
+ }
+
+ // add new certificate.
+ X509Certificate2 publicKey = new X509Certificate2(certificate.RawData);
+ await store.Add(publicKey);
+ }
+ finally
+ {
+ store.Close();
+ }
+ }
+
+ ///
+ /// Returns a default value for the data type.
+ ///
+ public static object GetDefaultValue(NodeId datatypeId, int valueRank)
+ {
+ Type type = TypeInfo.GetSystemType(datatypeId, EncodeableFactory.GlobalFactory);
+
+ if (type == null)
+ {
+ return null;
+ }
+
+ if (valueRank < 0)
+ {
+ if (type == typeof(String))
+ {
+ return System.String.Empty;
+ }
+
+ if (type == typeof(byte[]))
+ {
+ return new byte[0];
+ }
+
+ if (type == typeof(NodeId))
+ {
+ return Opc.Ua.NodeId.Null;
+ }
+
+ if (type == typeof(ExpandedNodeId))
+ {
+ return Opc.Ua.ExpandedNodeId.Null;
+ }
+
+ if (type == typeof(QualifiedName))
+ {
+ return Opc.Ua.QualifiedName.Null;
+ }
+
+ if (type == typeof(LocalizedText))
+ {
+ return Opc.Ua.LocalizedText.Null;
+ }
+
+ if (type == typeof(Guid))
+ {
+ return System.Guid.Empty;
+ }
+
+ if (type == typeof(System.Xml.XmlElement))
+ {
+ System.Xml.XmlDocument document = new System.Xml.XmlDocument();
+ document.InnerXml = "";
+ return document.DocumentElement;
+ }
+
+ return Activator.CreateInstance(type);
+ }
+
+ return Array.CreateInstance(type, new int[valueRank]);
+ }
+
+ ///
+ /// Displays a dialog that allows a use to edit a value.
+ ///
+ public static object EditValue(Session session, object value)
+ {
+ TypeInfo typeInfo = TypeInfo.Construct(value);
+
+ if (typeInfo != null)
+ {
+ return EditValue(session, value, (uint)typeInfo.BuiltInType, typeInfo.ValueRank);
+ }
+
+ return null;
+ }
+
+ ///
+ /// Displays a dialog that allows a use to edit a value.
+ ///
+ public static object EditValue(Session session, object value, NodeId datatypeId, int valueRank)
+ {
+ if (value == null)
+ {
+ value = GetDefaultValue(datatypeId, valueRank);
+ }
+
+ Popup myPopup = new Popup();
+
+ BuiltInType builtinType = TypeInfo.GetBuiltInType(datatypeId, session.TypeTree);
+
+ switch (builtinType)
+ {
+ case BuiltInType.Boolean:
+ case BuiltInType.Byte:
+ case BuiltInType.SByte:
+ case BuiltInType.Int16:
+ case BuiltInType.UInt16:
+ case BuiltInType.Int32:
+ case BuiltInType.UInt32:
+ case BuiltInType.Int64:
+ case BuiltInType.UInt64:
+ case BuiltInType.Float:
+ case BuiltInType.Double:
+ case BuiltInType.Enumeration:
+ case BuiltInType.String:
+ {
+
+ myPopup.Child = new SimpleValueEditCtrl(value);
+ myPopup.IsOpen = true;
+ value = ((SimpleValueEditCtrl)myPopup.Child).localValue;
+ break;
+ }
+
+ case BuiltInType.NodeId:
+ {
+ return new NodeIdValueEditDlg().ShowDialog(session, (NodeId)value);
+ }
+
+ case BuiltInType.ExpandedNodeId:
+ {
+ return new NodeIdValueEditDlg().ShowDialog(session, (ExpandedNodeId)value);
+ }
+
+ case BuiltInType.DateTime:
+ {
+ DateTime datetime = (DateTime)value;
+
+ myPopup.Child = new DateTimeValueEditCtrl(datetime);
+ myPopup.IsOpen = true;
+ value = ((DateTimeValueEditCtrl)myPopup.Child).localValue;
+ break;
+ }
+
+ case BuiltInType.QualifiedName:
+ {
+ QualifiedName qname = (QualifiedName)value;
+
+ myPopup.Child = new SimpleValueEditCtrl(qname.Name);
+ myPopup.IsOpen = true;
+ string name = ((SimpleValueEditCtrl)myPopup.Child).localValue.ToString();
+ if (name != null)
+ {
+ return new QualifiedName(name, qname.NamespaceIndex);
+ }
+
+ return null;
+ }
+
+ case BuiltInType.LocalizedText:
+ {
+ LocalizedText ltext = (LocalizedText)value;
+
+ myPopup.Child = new SimpleValueEditCtrl(ltext.Text);
+ myPopup.IsOpen = true;
+ string text = ((SimpleValueEditCtrl)myPopup.Child).localValue.ToString();
+ if (text != null)
+ {
+ return new LocalizedText(text, ltext.Locale);
+ }
+
+ return null;
+ }
+ }
+
+ return value;
+ }
+
+ ///
+ /// Returns to display icon for the target of a reference.
+ ///
+ public static string GetTargetIcon(Session session, ReferenceDescription reference)
+ {
+ return GetTargetIcon(session, reference.NodeClass, reference.TypeDefinition);
+ }
+
+ ///
+ /// Returns to display icon for the target of a reference.
+ ///
+ public static string GetTargetIcon(Session session, NodeClass nodeClass, ExpandedNodeId typeDefinitionId)
+ {
+ // make sure the type definition is in the cache.
+ INode typeDefinition = session.NodeCache.Find(typeDefinitionId);
+
+ switch (nodeClass)
+ {
+ case NodeClass.Object:
+ {
+ if (session.TypeTree.IsTypeOf(typeDefinitionId, ObjectTypes.FolderType))
+ {
+ return "Folder";
+ }
+
+ return "Object";
+ }
+
+ case NodeClass.Variable:
+ {
+ if (session.TypeTree.IsTypeOf(typeDefinitionId, VariableTypes.PropertyType))
+ {
+ return "Property";
+ }
+
+ return "Variable";
+ }
+ }
+
+ return nodeClass.ToString();
+ }
+
+#region Private Methods
+#endregion
+ }
+}
diff --git a/SampleApplications/SDK/Controls/Common (OLD)/MessageDlg.xaml b/SampleApplications/SDK/Controls/Common (OLD)/MessageDlg.xaml
new file mode 100644
index 0000000000..9c32debd8f
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Common (OLD)/MessageDlg.xaml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SampleApplications/SDK/Controls/Common (OLD)/MessageDlg.xaml.cs b/SampleApplications/SDK/Controls/Common (OLD)/MessageDlg.xaml.cs
new file mode 100644
index 0000000000..6dfa1d151a
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Common (OLD)/MessageDlg.xaml.cs
@@ -0,0 +1,143 @@
+/* ========================================================================
+ * Copyright (c) 2005-2013 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 Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml;
+using System.Threading.Tasks;
+using Windows.UI.Xaml.Controls.Primitives;
+using Opc.Ua.Configuration;
+using System;
+
+namespace Opc.Ua.Client.Controls
+{
+ public class ApplicationMessageDlg:IApplicationMessageDlg
+ {
+ private MessageDlg dialog = new MessageDlg("");
+ public override void Message(string text, bool ask)
+ {
+ if (ask)
+ {
+ dialog.MessageText(text, MessageDlgButton.Yes, MessageDlgButton.No);
+ }
+ else
+ {
+ dialog.MessageText(text);
+ }
+ }
+ public override async Task ShowAsync()
+ {
+ return await dialog.ShowAsync() == MessageDlgButton.Yes;
+ }
+ }
+
+ public enum MessageDlgButton
+ {
+ None,
+ Ok,
+ Cancel,
+ Yes,
+ No
+ }
+
+ public partial class MessageDlg : Page
+ {
+ private string Text;
+ private Popup dialogPopup = new Popup();
+ TaskCompletionSource tcs;
+ MessageDlgButton Result = MessageDlgButton.None;
+ MessageDlgButton Left = MessageDlgButton.None;
+ MessageDlgButton Right = MessageDlgButton.None;
+
+ #region Constructors
+ public MessageDlg(
+ string text,
+ MessageDlgButton left = MessageDlgButton.Ok,
+ MessageDlgButton right = MessageDlgButton.None)
+ {
+ InitializeComponent();
+ Text = text;
+ Left = left;
+ Right = right;
+ dialogPopup.Child = this;
+ dialogPopup.Closed += ClosedEvent;
+ }
+ #endregion
+
+ public void MessageText(
+ string text,
+ MessageDlgButton left = MessageDlgButton.Ok,
+ MessageDlgButton right = MessageDlgButton.None)
+ {
+ Text = text;
+ Left = left;
+ Right = right;
+ }
+
+
+ public async Task ShowAsync()
+ {
+ // configure dialog
+ SetButtonText(LeftButton, Left);
+ SetButtonText(RightButton, Right);
+ Message.Text = Text;
+
+ tcs = new TaskCompletionSource();
+
+ // display dialog and wait for close event
+ dialogPopup.IsOpen = true;
+ return await tcs.Task;
+ }
+
+ private void ClosedEvent( object o, object e)
+ {
+ tcs.SetResult(Result);
+ }
+
+ private void SetButtonText(Button button, MessageDlgButton item)
+ {
+ button.Content = item.ToString();
+ button.Visibility = (item == MessageDlgButton.None) ? Visibility.Collapsed : Visibility.Visible;
+ }
+
+ private void LeftButton_Click(object sender, RoutedEventArgs e)
+ {
+ Result = Left;
+ dialogPopup.IsOpen = false;
+ }
+
+ private void RightButton_Click(object sender, RoutedEventArgs e)
+ {
+ Result = Right;
+ dialogPopup.IsOpen = false;
+ }
+ }
+
+}
+
diff --git a/SampleApplications/SDK/Controls/Common (OLD)/NodeIdCtrl.xaml b/SampleApplications/SDK/Controls/Common (OLD)/NodeIdCtrl.xaml
new file mode 100644
index 0000000000..25613c3dba
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Common (OLD)/NodeIdCtrl.xaml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
diff --git a/SampleApplications/SDK/Controls/Common (OLD)/NodeIdCtrl.xaml.cs b/SampleApplications/SDK/Controls/Common (OLD)/NodeIdCtrl.xaml.cs
new file mode 100644
index 0000000000..ee590c0257
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Common (OLD)/NodeIdCtrl.xaml.cs
@@ -0,0 +1,210 @@
+/* ========================================================================
+ * Copyright (c) 2005-2013 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 Opc.Ua;
+using Opc.Ua.Client;
+using System;
+using System.ComponentModel;
+using System.Reflection;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Controls.Primitives;
+
+namespace Opc.Ua.Client.Controls
+{
+ ///
+ /// A list of node ids.
+ ///
+ public sealed partial class NodeIdCtrl : UserControl
+ {
+ #region Constructors
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public NodeIdCtrl()
+ {
+ InitializeComponent();
+
+ m_rootId = Objects.RootFolder;
+ BrowseBTN.IsEnabled = false;
+ }
+ #endregion
+
+ public NodeId ShowDialog(Session session, NodeId value)
+ {
+ if (session == null) throw new ArgumentNullException("session");
+
+ m_browser = new Browser(session);
+ m_rootId = Objects.RootFolder;
+ this.Identifier = value;
+
+ Popup myPopup = new Popup();
+ myPopup.Child = this;
+ myPopup.IsOpen = true;
+
+ return this.Identifier;
+ }
+
+ ///
+ /// Displays the dialog.
+ ///
+ public ExpandedNodeId ShowDialog(Session session, ExpandedNodeId value)
+ {
+ if (session == null) throw new ArgumentNullException("session");
+
+ m_browser = new Browser(session);
+ m_rootId = Objects.RootFolder;
+ Identifier = ExpandedNodeId.ToNodeId(value, session.NamespaceUris);
+
+ Popup myPopup = new Popup();
+ myPopup.Child = this;
+ myPopup.IsOpen = true;
+
+ return this.Identifier;
+ }
+
+ #region Event Handlers
+ private Browser m_browser;
+ private NodeId m_rootId;
+ private ReferenceDescription m_reference;
+ private event EventHandler m_IdentifierChanged;
+ #endregion
+
+ #region Public Interface
+ ///
+ /// Raised if the node id is changed.
+ ///
+ public event EventHandler IdentifierChanged
+ {
+ add { m_IdentifierChanged += value; }
+ remove { m_IdentifierChanged -= value; }
+ }
+
+ ///
+ /// The browser to used browse for a node id.
+ ///
+ [DefaultValue(null)]
+ public Browser Browser
+ {
+ get
+ {
+ return m_browser;
+ }
+
+ set
+ {
+ m_browser = value;
+ BrowseBTN.IsEnabled = m_browser != null;
+ }
+ }
+
+ ///
+ /// The root node id to display when browsing.
+ ///
+ [DefaultValue(null)]
+ public NodeId RootId
+ {
+ get
+ {
+ return m_rootId;
+ }
+
+ set
+ {
+ m_rootId = value;
+
+ if (NodeId.IsNull(m_rootId))
+ {
+ m_rootId = Objects.RootFolder;
+ }
+ }
+ }
+
+ ///
+ /// Returns true if the control is empty.
+ ///
+ [DefaultValue(false)]
+ public bool IsEmpty
+ {
+ get
+ {
+ return String.IsNullOrEmpty(NodeIdTB.Text);
+ }
+ }
+
+ ///
+ /// The node identifier specified in the control.
+ ///
+ [DefaultValue(null)]
+ public NodeId Identifier
+ {
+ get
+ {
+ return NodeId.Parse(NodeIdTB.Text);
+ }
+
+ set
+ {
+ NodeIdTB.Text = Utils.Format("{0}", value);
+ }
+ }
+
+ ///
+ /// The reference seleected if the browse feature was used.
+ ///
+ [DefaultValue(null)]
+ public ReferenceDescription Reference
+ {
+ get
+ {
+ return m_reference;
+ }
+
+ set
+ {
+ m_reference = value;
+
+ if (m_reference != null)
+ {
+ NodeIdTB.Text = Utils.Format("{0}", m_reference.NodeId);
+ }
+ }
+ }
+ #endregion
+
+ #region Event Handlers
+ private void NodeIdTB_TextChanged(object sender, EventArgs e)
+ {
+ if (m_IdentifierChanged != null)
+ {
+ m_IdentifierChanged(this, null);
+ }
+ }
+ #endregion
+ }
+}
diff --git a/SampleApplications/SDK/Controls/Common (OLD)/NodeIdValueEditDlg.xaml b/SampleApplications/SDK/Controls/Common (OLD)/NodeIdValueEditDlg.xaml
new file mode 100644
index 0000000000..04240f62bf
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Common (OLD)/NodeIdValueEditDlg.xaml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
diff --git a/SampleApplications/SDK/Controls/Common (OLD)/NodeIdValueEditDlg.xaml.cs b/SampleApplications/SDK/Controls/Common (OLD)/NodeIdValueEditDlg.xaml.cs
new file mode 100644
index 0000000000..1ec5a2e8fe
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Common (OLD)/NodeIdValueEditDlg.xaml.cs
@@ -0,0 +1,53 @@
+using Opc.Ua;
+using Opc.Ua.Client;
+using System;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Controls.Primitives;
+
+// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
+
+namespace Opc.Ua.Client.Controls
+{
+ ///
+ /// An empty page that can be used on its own or navigated to within a Frame.
+ ///
+ public sealed partial class NodeIdValueEditDlg : Page
+ {
+ public NodeIdValueEditDlg()
+ {
+ this.InitializeComponent();
+ }
+ public NodeId ShowDialog(Session session, NodeId value)
+ {
+ if (session == null) throw new ArgumentNullException("session");
+
+ ValueCTRL.Browser = new Browser(session);
+ ValueCTRL.RootId = Objects.RootFolder;
+ ValueCTRL.Identifier = value;
+
+ Popup myPopup = new Popup();
+ myPopup.Child = this;
+ myPopup.IsOpen = true;
+
+ return ValueCTRL.Identifier;
+ }
+
+ ///
+ /// Displays the dialog.
+ ///
+ public ExpandedNodeId ShowDialog(Session session, ExpandedNodeId value)
+ {
+ if (session == null) throw new ArgumentNullException("session");
+
+ ValueCTRL.Browser = new Browser(session);
+ ValueCTRL.RootId = Objects.RootFolder;
+ ValueCTRL.Identifier = ExpandedNodeId.ToNodeId(value, session.NamespaceUris);
+
+ Popup myPopup = new Popup();
+ myPopup.Child = this;
+ myPopup.IsOpen = true;
+
+ return ValueCTRL.Identifier;
+ }
+ }
+}
diff --git a/SampleApplications/SDK/Controls/Common (OLD)/ReferenceTypeCtrl.xaml b/SampleApplications/SDK/Controls/Common (OLD)/ReferenceTypeCtrl.xaml
new file mode 100644
index 0000000000..b0e9d13276
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Common (OLD)/ReferenceTypeCtrl.xaml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
diff --git a/SampleApplications/SDK/Controls/Common (OLD)/ReferenceTypeCtrl.xaml.cs b/SampleApplications/SDK/Controls/Common (OLD)/ReferenceTypeCtrl.xaml.cs
new file mode 100644
index 0000000000..26ca763743
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Common (OLD)/ReferenceTypeCtrl.xaml.cs
@@ -0,0 +1,275 @@
+/* ========================================================================
+ * Copyright (c) 2005-2013 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.Generic;
+using System.Text;
+using System.Reflection;
+using Windows.UI.Xaml.Controls;
+using Opc.Ua;
+using Opc.Ua.Client;
+using Opc.Ua.Client.Controls;
+
+namespace Opc.Ua.Client.Controls
+{
+ ///
+ /// Displays a drop down list of reference types.
+ ///
+ public sealed partial class ReferenceTypeCtrl : UserControl
+ {
+ private ComboBox ReferenceTypesCB = new ComboBox();
+
+ #region Constructors
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ReferenceTypeCtrl()
+ {
+ InitializeComponent();
+ m_baseTypeId = ReferenceTypes.References;
+ }
+ #endregion
+
+ #region Private Fields
+ private Session m_session;
+ private NodeId m_baseTypeId;
+ private event EventHandler m_referenceSelectionChanged;
+ #endregion
+
+ #region Public Interface
+ ///
+ /// Initializes the control with references starting with the specified based type.
+ ///
+ public void Initialize(Session session, NodeId baseTypeId)
+ {
+ m_session = session;
+ m_baseTypeId = baseTypeId;
+
+ if (NodeId.IsNull(m_baseTypeId))
+ {
+ m_baseTypeId = ReferenceTypes.References;
+ }
+
+ ReferenceTypesCB.Items.Clear();
+
+ // recurcively fetch the reference types from the server.
+ if (m_session != null)
+ {
+ AddReferenceTypes(m_baseTypeId, null);
+ }
+ }
+
+ ///
+ /// The currently seleected reference type id.
+ ///
+ public NodeId SelectedTypeId
+ {
+ get
+ {
+ ReferenceTypeChoice choice = ReferenceTypesCB.SelectedItem as ReferenceTypeChoice;
+
+ if (choice == null)
+ {
+ return null;
+ }
+
+ return choice.ReferenceType.NodeId;
+ }
+
+ set
+ {
+ for (int ii = 0; ii < ReferenceTypesCB.Items.Count; ii++)
+ {
+ ReferenceTypeChoice choice = ReferenceTypesCB.Items[ii] as ReferenceTypeChoice;
+
+ if (choice != null && choice.ReferenceType.NodeId == value)
+ {
+ ReferenceTypesCB.SelectedIndex = ii;
+ return;
+ }
+ }
+
+ if (ReferenceTypesCB.Items.Count > 0)
+ {
+ ReferenceTypesCB.SelectedIndex = 0;
+ }
+ }
+ }
+
+ ///
+ /// Raised when the selected reference is changed.
+ ///
+ public event EventHandler ReferenceSelectionChanged
+ {
+ add { m_referenceSelectionChanged += value; }
+ remove { m_referenceSelectionChanged -= value; }
+ }
+
+ #region ReferenceSelectedEventArgs Class
+ ///
+ /// Specifies the nodes that where selected in the control.
+ ///
+ public class ReferenceSelectedEventArgs : EventArgs
+ {
+ ///
+ /// Constructs a new object.
+ ///
+ public ReferenceSelectedEventArgs(NodeId selectedTypeId)
+ {
+ m_referenceTypeId = selectedTypeId;
+ }
+
+ ///
+ /// The reference type that was selected.
+ ///
+ public NodeId ReferenceTypeId
+ {
+ get { return m_referenceTypeId; }
+ }
+
+ private NodeId m_referenceTypeId;
+ }
+ #endregion
+ #endregion
+
+ #region ReferenceTypeChoice Class
+ ///
+ /// A reference type that may be used as a browse filter.
+ ///
+ private class ReferenceTypeChoice
+ {
+ ///
+ /// The text to display in the control.
+ ///
+ public override string ToString()
+ {
+ if (ReferenceType == null)
+ {
+ return "";
+ }
+
+ StringBuilder text = new StringBuilder();
+
+ GetPrefix(text);
+
+ if (text.Length > 0)
+ {
+ text.Append("> ");
+ }
+
+ if (ReferenceType != null)
+ {
+ text.Append(ReferenceType.ToString());
+ }
+
+ return text.ToString();
+ }
+
+ ///
+ /// Adds a prefix for subtypes.
+ ///
+ private void GetPrefix(StringBuilder prefix)
+ {
+ if (SuperType != null)
+ {
+ SuperType.GetPrefix(prefix);
+ prefix.Append("--");
+ }
+ }
+
+ public ReferenceTypeNode ReferenceType;
+ public ReferenceTypeChoice SuperType;
+ }
+ #endregion
+
+ #region Private Methods
+ ///
+ /// Adds the reference types to drop down box.
+ ///
+ private void AddReferenceTypes(ExpandedNodeId referenceTypeId, ReferenceTypeChoice supertype)
+ {
+ if (referenceTypeId == null) throw new Exception("referenceTypeId");
+
+ try
+ {
+ // find reference.
+ ReferenceTypeNode node = m_session.NodeCache.Find(referenceTypeId) as ReferenceTypeNode;
+
+ if (node == null)
+ {
+ return;
+ }
+
+ // add reference to combobox.
+ ReferenceTypeChoice choice = new ReferenceTypeChoice();
+
+ choice.ReferenceType = node;
+ choice.SuperType = supertype;
+
+ ReferenceTypesCB.Items.Add(choice);
+
+ // recursively add subtypes.
+ IList subtypes = m_session.NodeCache.FindReferences(node.NodeId, ReferenceTypeIds.HasSubtype, false, true);
+
+ foreach (INode subtype in subtypes)
+ {
+ AddReferenceTypes(subtype.NodeId, choice);
+ }
+ }
+ catch (Exception e)
+ {
+ Utils.Trace(e, "Ignoring unknown reference type.");
+ return;
+ }
+ }
+ #endregion
+
+ #region Event Handlers
+ private void ReferenceTypesCB_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ try
+ {
+ if (m_referenceSelectionChanged != null)
+ {
+ NodeId referenceTypeId = SelectedTypeId;
+
+ if (referenceTypeId != null)
+ {
+ m_referenceSelectionChanged(this, new ReferenceSelectedEventArgs(referenceTypeId));
+ }
+ }
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
+ }
+ }
+ #endregion
+ }
+}
diff --git a/SampleApplications/SDK/Controls/Common (OLD)/SimpleValueEditCtrl.xaml b/SampleApplications/SDK/Controls/Common (OLD)/SimpleValueEditCtrl.xaml
new file mode 100644
index 0000000000..6ee65cd696
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Common (OLD)/SimpleValueEditCtrl.xaml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
diff --git a/SampleApplications/SDK/Controls/Common (OLD)/SimpleValueEditCtrl.xaml.cs b/SampleApplications/SDK/Controls/Common (OLD)/SimpleValueEditCtrl.xaml.cs
new file mode 100644
index 0000000000..e6962f60f1
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Common (OLD)/SimpleValueEditCtrl.xaml.cs
@@ -0,0 +1,79 @@
+using Opc.Ua;
+using Opc.Ua.Client.Controls;
+using System;
+using System.Reflection;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Controls.Primitives;
+
+// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236
+
+namespace Opc.Ua.Client.Controls
+{
+ public sealed partial class SimpleValueEditCtrl : UserControl
+ {
+ public object localValue;
+
+ public SimpleValueEditCtrl(object value)
+ {
+ this.InitializeComponent();
+ this.textBox.Text = value.ToString();
+ }
+
+ public static bool IsSimpleType(Type type)
+ {
+ if (type == typeof(bool)) return true;
+ if (type == typeof(sbyte)) return true;
+ if (type == typeof(byte)) return true;
+ if (type == typeof(short)) return true;
+ if (type == typeof(ushort)) return true;
+ if (type == typeof(int)) return true;
+ if (type == typeof(uint)) return true;
+ if (type == typeof(long)) return true;
+ if (type == typeof(ulong)) return true;
+ if (type == typeof(float)) return true;
+ if (type == typeof(double)) return true;
+ if (type == typeof(string)) return true;
+ if (type == typeof(DateTime)) return true;
+ if (type == typeof(Guid)) return true;
+
+ return false;
+ }
+
+ private object Parse(string text)
+ {
+ if (localValue == typeof(bool)) return Convert.ToBoolean(text);
+ if (localValue == typeof(sbyte)) return Convert.ToSByte(text);
+ if (localValue == typeof(byte)) return Convert.ToByte(text);
+ if (localValue == typeof(short)) return Convert.ToInt16(text);
+ if (localValue == typeof(ushort)) return Convert.ToUInt16(text);
+ if (localValue == typeof(int)) return Convert.ToInt32(text);
+ if (localValue == typeof(uint)) return Convert.ToUInt32(text);
+ if (localValue == typeof(long)) return Convert.ToInt64(text);
+ if (localValue == typeof(ulong)) return Convert.ToUInt64(text);
+ if (localValue == typeof(float)) return Convert.ToSingle(text);
+ if (localValue == typeof(double)) return Convert.ToDouble(text);
+ if (localValue == typeof(string)) return text;
+ if (localValue == typeof(DateTime)) return DateTime.ParseExact(text, "yyyy-MM-dd HH:mm:ss.fff", null);
+ if (localValue == typeof(Guid)) return new Guid(text);
+ if (localValue == typeof(QualifiedName)) return new QualifiedName(text);
+ if (localValue == typeof(LocalizedText)) return new LocalizedText(text);
+
+ throw new ServiceResultException(StatusCodes.BadUnexpectedError, "Cannot convert type.");
+ }
+
+ private void button_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
+ {
+ Popup p = this.Parent as Popup;
+ p.IsOpen = false;
+
+ try
+ {
+ localValue = Parse(this.textBox.Text);
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(this.textBox.Text, GuiUtils.CallerName(), exception);
+ }
+ }
+ }
+}
diff --git a/SampleApplications/SDK/Controls/Endpoints/ConfiguredServerDlg.xaml b/SampleApplications/SDK/Controls/Endpoints/ConfiguredServerDlg.xaml
new file mode 100644
index 0000000000..a988e359f2
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Endpoints/ConfiguredServerDlg.xaml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SampleApplications/SDK/Controls/Endpoints/ConfiguredServerDlg.xaml.cs b/SampleApplications/SDK/Controls/Endpoints/ConfiguredServerDlg.xaml.cs
new file mode 100644
index 0000000000..4faa0c4a3a
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Endpoints/ConfiguredServerDlg.xaml.cs
@@ -0,0 +1,1588 @@
+/* ========================================================================
+ * Copyright (c) 2005-2013 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.Generic;
+using System.Text;
+using System.Reflection;
+using System.Threading;
+using Windows.UI.Xaml.Controls;
+using Opc.Ua;
+using System.Threading.Tasks;
+using Windows.UI.Xaml.Controls.Primitives;
+using Windows.UI.Popups;
+using Windows.UI.Core;
+using Windows.UI.Xaml;
+
+namespace Opc.Ua.Client.Controls
+{
+ ///
+ /// Prompts the user to edit a ComPseudoServerDlg.
+ ///
+ public partial class ConfiguredServerDlg : Page
+ {
+
+ #region Constructors
+ ///
+ /// Initializes the dialog.
+ ///
+ public ConfiguredServerDlg()
+ {
+ InitializeComponent();
+
+ // options for override limits are fixed.
+ foreach (UseDefaultLimits value in Enum.GetValues(typeof(UseDefaultLimits)))
+ {
+ UseDefaultLimitsCB.Items.Add(value);
+ }
+
+ m_userIdentities = new Dictionary();
+ }
+ #endregion
+
+ #region Private Fields
+ ///
+ /// The possible encodings.
+ ///
+ private enum Encoding
+ {
+ Default,
+ Xml,
+ Binary
+ }
+
+ ///
+ /// The possible COM identities.
+ ///
+ private enum ComIdentityType
+ {
+ None = -1,
+ DA = (int)ComSpecification.DA,
+ AE = (int)ComSpecification.AE,
+ HDA = (int)ComSpecification.HDA,
+ }
+
+ ///
+ /// Whether to override limits
+ ///
+ private enum UseDefaultLimits
+ {
+ Yes,
+ No
+ }
+
+ private Popup dialogPopup = new Popup();
+ private ConfiguredEndpoint m_endpoint;
+ private EndpointDescription m_currentDescription;
+ private EndpointDescriptionCollection m_availableEndpoints;
+ private int m_discoveryTimeout;
+ private int m_discoverCount;
+ private ApplicationConfiguration m_configuration;
+ private bool m_updating;
+ private Dictionary m_userIdentities;
+ private EndpointComIdentity m_comIdentity;
+ private EndpointConfiguration m_endpointConfiguration;
+ private bool m_discoverySucceeded;
+ private Uri m_discoveryUrl;
+ private bool m_showAllOptions;
+ #endregion
+
+ #region Public Interface
+ public delegate void ConfiguredServer(ConfiguredEndpoint endpoint);
+
+ ///
+ /// The timeout in milliseconds to use when discovering servers.
+ ///
+ [System.ComponentModel.DefaultValue(20000)]
+ public int DiscoveryTimeout
+ {
+ get { return m_discoveryTimeout; }
+ set { Interlocked.Exchange(ref m_discoveryTimeout, value); }
+ }
+ ///
+ /// Displays the dialog.
+ ///
+ public async Task ShowDialog(ApplicationDescription server, ApplicationConfiguration configuration)
+ {
+ if (server == null) throw new ArgumentNullException("server");
+
+ m_configuration = configuration;
+
+ // construct a list of available endpoint descriptions for the application.
+ m_availableEndpoints = new EndpointDescriptionCollection();
+ m_endpointConfiguration = EndpointConfiguration.Create(configuration);
+
+ // create a default endpoint description.
+ m_endpoint = null;
+ m_currentDescription = null;
+
+ // initializing the protocol will trigger an update to all other controls.
+ InitializeProtocols(m_availableEndpoints);
+
+ UseDefaultLimitsCB.SelectedIndex = (int)UseDefaultLimits.Yes;
+
+ // discover endpoints in the background.
+ m_discoverySucceeded = false;
+ Interlocked.Increment(ref m_discoverCount);
+ OnDiscoverEndpoints(server);
+
+ TaskCompletionSource tcs = new TaskCompletionSource();
+ // display dialog
+ dialogPopup.Child = this;
+ dialogPopup.IsOpen = true;
+ dialogPopup.Closed += (o, e) =>
+ {
+ tcs.SetResult(m_endpoint);
+ };
+ return await tcs.Task;
+
+ }
+
+ ///
+ /// Displays the dialog.
+ ///
+ public async Task ShowDialog(ConfiguredEndpoint endpoint, ApplicationConfiguration configuration)
+ {
+ if (endpoint == null) throw new ArgumentNullException("endpoint");
+
+ m_endpoint = endpoint;
+ m_configuration = configuration;
+
+ // construct a list of available endpoint descriptions for the application.
+ m_availableEndpoints = new EndpointDescriptionCollection();
+
+ m_availableEndpoints.Add(endpoint.Description);
+ m_currentDescription = endpoint.Description;
+ m_endpointConfiguration = endpoint.Configuration;
+
+ if (m_endpointConfiguration == null)
+ {
+ m_endpointConfiguration = EndpointConfiguration.Create(configuration);
+ }
+
+ if (endpoint.Collection != null)
+ {
+ foreach (ConfiguredEndpoint existingEndpoint in endpoint.Collection.Endpoints)
+ {
+ if (existingEndpoint.Description.Server.ApplicationUri == endpoint.Description.Server.ApplicationUri)
+ {
+ m_availableEndpoints.Add(existingEndpoint.Description);
+ }
+ }
+ }
+
+ UserTokenPolicy policy = m_endpoint.SelectedUserTokenPolicy;
+
+ if (policy == null)
+ {
+ if (m_endpoint.Description.UserIdentityTokens.Count > 0)
+ {
+ policy = m_endpoint.Description.UserIdentityTokens[0];
+ }
+ }
+
+ if (policy != null)
+ {
+ UserTokenItem userTokenItem = new UserTokenItem(policy);
+
+ if (policy.TokenType == UserTokenType.UserName && m_endpoint.UserIdentity is UserNameIdentityToken)
+ {
+ m_userIdentities[userTokenItem.ToString()] = m_endpoint.UserIdentity;
+ }
+
+ if (policy.TokenType == UserTokenType.Certificate && m_endpoint.UserIdentity is X509IdentityToken)
+ {
+ m_userIdentities[userTokenItem.ToString()] = m_endpoint.UserIdentity;
+ }
+
+ if (policy.TokenType == UserTokenType.IssuedToken && m_endpoint.UserIdentity is IssuedIdentityToken)
+ {
+ m_userIdentities[userTokenItem.ToString()] = m_endpoint.UserIdentity;
+ }
+
+ UserTokenTypeCB.Items.Add(userTokenItem);
+ UserTokenTypeCB.SelectedIndex = UserTokenTypeCB.Items.IndexOf(userTokenItem);
+ }
+
+ // copy com identity.
+ m_comIdentity = endpoint.ComIdentity;
+
+ // initializing the protocol will trigger an update to all other controls.
+ InitializeProtocols(m_availableEndpoints);
+
+ // check if the current settings match the defaults.
+ EndpointConfiguration defaultConfiguration = EndpointConfiguration.Create(configuration);
+
+ if (SameAsDefaults(defaultConfiguration, m_endpoint.Configuration))
+ {
+ UseDefaultLimitsCB.SelectedIndex = (int)UseDefaultLimits.Yes;
+ }
+ else
+ {
+ UseDefaultLimitsCB.SelectedIndex = (int)UseDefaultLimits.No;
+ }
+
+ // discover endpoints in the background.
+ Interlocked.Increment(ref m_discoverCount);
+ OnDiscoverEndpoints(m_endpoint.Description.Server);
+
+ TaskCompletionSource tcs = new TaskCompletionSource();
+ // display dialog
+ dialogPopup.Child = this;
+ dialogPopup.IsOpen = true;
+ dialogPopup.Closed += (o, e) =>
+ {
+ tcs.SetResult(m_endpoint);
+ };
+ return await tcs.Task;
+ }
+ #endregion
+
+ #region Private Methods
+ ///
+ /// Returns true if the configuration is the same as the default.
+ ///
+ private bool SameAsDefaults(EndpointConfiguration defaultConfiguration, EndpointConfiguration currentConfiguration)
+ {
+ if (defaultConfiguration.ChannelLifetime != currentConfiguration.ChannelLifetime)
+ {
+ return false;
+ }
+
+ if (defaultConfiguration.MaxArrayLength != currentConfiguration.MaxArrayLength)
+ {
+ return false;
+ }
+
+ if (defaultConfiguration.MaxBufferSize != currentConfiguration.MaxBufferSize)
+ {
+ return false;
+ }
+
+ if (defaultConfiguration.MaxByteStringLength != currentConfiguration.MaxByteStringLength)
+ {
+ return false;
+ }
+
+ if (defaultConfiguration.MaxMessageSize != currentConfiguration.MaxMessageSize)
+ {
+ return false;
+ }
+
+ if (defaultConfiguration.MaxStringLength != currentConfiguration.MaxStringLength)
+ {
+ return false;
+ }
+
+ if (defaultConfiguration.OperationTimeout != currentConfiguration.OperationTimeout)
+ {
+ return false;
+ }
+
+ if (defaultConfiguration.SecurityTokenLifetime != currentConfiguration.SecurityTokenLifetime)
+ {
+ return false;
+ }
+
+ if (defaultConfiguration.UseBinaryEncoding != currentConfiguration.UseBinaryEncoding)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Finds the best match for the current protocol and security selections.
+ ///
+ private EndpointDescription FindBestEndpointDescription(EndpointDescriptionCollection endpoints)
+ {
+ // filter by the current protocol.
+ Protocol currentProtocol = (Protocol)ProtocolCB.SelectedItem;
+
+ // filter by the current security mode.
+ MessageSecurityMode currentMode = MessageSecurityMode.None;
+
+ if (SecurityModeCB.SelectedIndex != -1)
+ {
+ currentMode = (MessageSecurityMode)SecurityModeCB.SelectedItem;
+ }
+
+ // filter by the current security policy.
+ string currentPolicy = (string)SecurityPolicyCB.SelectedItem;
+
+ // find all matching descriptions.
+ EndpointDescriptionCollection matches = new EndpointDescriptionCollection();
+
+ if (endpoints != null)
+ {
+ foreach (EndpointDescription endpoint in endpoints)
+ {
+ Uri url = Utils.ParseUri(endpoint.EndpointUrl);
+
+ if (url == null)
+ {
+ continue;
+ }
+
+ if (currentProtocol == null ||
+ !currentProtocol.Matches(url))
+ {
+ continue;
+ }
+
+ if (currentMode != endpoint.SecurityMode)
+ {
+ continue;
+ }
+
+ if (currentPolicy != SecurityPolicies.GetDisplayName(endpoint.SecurityPolicyUri))
+ {
+ continue;
+ }
+
+ matches.Add(endpoint);
+ }
+ }
+
+ // check for no matches.
+ if (matches.Count == 0)
+ {
+ return null;
+ }
+
+ // check for single match.
+ if (matches.Count == 1)
+ {
+ return matches[0];
+ }
+
+ // choose highest priority.
+ EndpointDescription bestMatch = matches[0];
+
+ for (int ii = 1; ii < matches.Count; ii++)
+ {
+ if (bestMatch.SecurityLevel < matches[ii].SecurityLevel)
+ {
+ bestMatch = matches[ii];
+ }
+ }
+
+ return bestMatch;
+ }
+
+ ///
+ /// Finds the best match for the current protocol and security selections.
+ ///
+ private int FindBestUserTokenPolicy(EndpointDescription endpoint)
+ {
+ // filter by the current token type.
+ UserTokenItem currentTokenType = new UserTokenItem(UserTokenType.Anonymous);
+
+ if (UserTokenTypeCB.SelectedIndex != -1)
+ {
+ currentTokenType = (UserTokenItem)UserTokenTypeCB.SelectedItem;
+ }
+
+ // filter by issued token type.
+ string currentIssuedTokenType = (string)IssuedTokenTypeCB.SelectedItem;
+
+ // find all matching descriptions.
+ UserTokenPolicyCollection matches = new UserTokenPolicyCollection();
+
+ if (endpoint != null)
+ {
+ for (int ii = 0; ii < endpoint.UserIdentityTokens.Count; ii++)
+ {
+ UserTokenPolicy policy = endpoint.UserIdentityTokens[ii];
+
+ if (currentTokenType.Policy.PolicyId == policy.PolicyId)
+ {
+ return ii;
+ }
+ }
+
+ for (int ii = 0; ii < endpoint.UserIdentityTokens.Count; ii++)
+ {
+ UserTokenPolicy policy = endpoint.UserIdentityTokens[ii];
+
+ if (currentTokenType.Policy.TokenType != policy.TokenType)
+ {
+ continue;
+ }
+
+ if (policy.TokenType == UserTokenType.IssuedToken)
+ {
+ if (currentIssuedTokenType != policy.IssuedTokenType)
+ {
+ continue;
+ }
+ }
+
+ return ii;
+ }
+ }
+
+ return -1;
+ }
+
+ private class Protocol
+ {
+ public Uri Url;
+ public string Profile;
+
+ public Protocol(string url)
+ {
+ Url = Utils.ParseUri(url);
+ }
+
+ public Protocol(EndpointDescription url)
+ {
+ Url = Utils.ParseUri(url.EndpointUrl);
+
+ if (Url.Scheme == Utils.UriSchemeHttp)
+ {
+ switch (url.TransportProfileUri)
+ {
+ case Profiles.HttpsXmlTransport:
+ case Profiles.HttpsBinaryTransport:
+ case Profiles.HttpsXmlOrBinaryTransport:
+ {
+ Profile = "REST";
+ break;
+ }
+
+ case Profiles.WsHttpXmlTransport:
+ case Profiles.WsHttpXmlOrBinaryTransport:
+ {
+ Profile = "WS-*";
+ break;
+ }
+ }
+ }
+ }
+
+ public bool Matches(Uri url)
+ {
+ if (url == null || Url == null)
+ {
+ return false;
+ }
+
+ if (url.Scheme != Url.Scheme)
+ {
+ return false;
+ }
+
+ if (url.DnsSafeHost != Url.DnsSafeHost)
+ {
+ return false;
+ }
+
+ if (url.Port != Url.Port)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ public override string ToString()
+ {
+ if (Url == null)
+ {
+ return String.Empty;
+ }
+
+ StringBuilder builder = new StringBuilder();
+ builder.Append(Url.Scheme);
+
+ if (!String.IsNullOrEmpty(Profile))
+ {
+ builder.Append(" ");
+ builder.Append(Profile);
+ }
+
+ builder.Append(" [");
+ builder.Append(Url.DnsSafeHost);
+
+ if (Url.Port != -1)
+ {
+ builder.Append(":");
+ builder.Append(Url.Port);
+ }
+
+ builder.Append("]");
+
+ return builder.ToString();
+ }
+ }
+
+ ///
+ /// Initializes the protocol dropdown.
+ ///
+ private void InitializeProtocols(EndpointDescriptionCollection endpoints)
+ {
+ // preserve the existing value.
+ Protocol currentProtocol = (Protocol)ProtocolCB.SelectedItem;
+
+ ProtocolCB.Items.Clear();
+
+ // set all available protocols.
+ if (m_showAllOptions)
+ {
+ ProtocolCB.Items.Add(new Protocol("http://localhost"));
+ ProtocolCB.Items.Add(new Protocol("https://localhost"));
+ ProtocolCB.Items.Add(new Protocol("opc.tcp://localhost"));
+ }
+
+ // find all unique protocols.
+ else
+ {
+ if (endpoints != null)
+ {
+ foreach (EndpointDescription endpoint in endpoints)
+ {
+ Uri url = Utils.ParseUri(endpoint.EndpointUrl);
+
+ if (url != null)
+ {
+ bool found = false;
+
+ for (int ii = 0; ii < ProtocolCB.Items.Count; ii++)
+ {
+ if (((Protocol)ProtocolCB.Items[ii]).Matches(url))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ ProtocolCB.Items.Add(new Protocol(endpoint));
+ }
+ }
+ }
+ }
+
+ // add at least one protocol.
+ if (ProtocolCB.Items.Count == 0)
+ {
+ ProtocolCB.Items.Add(new Protocol("opc.tcp://localhost"));
+ }
+ }
+
+ // set the current value.
+ int index = 0;
+
+ if (currentProtocol != null)
+ {
+ index = 0;
+
+ for (int ii = 0; ii < ProtocolCB.Items.Count; ii++)
+ {
+ if (((Protocol)ProtocolCB.Items[ii]).Matches(currentProtocol.Url))
+ {
+ index = ii;
+ break;
+ }
+ }
+ }
+
+ ProtocolCB.SelectedIndex = index;
+ }
+
+ ///
+ /// Initializes the security modes dropdown.
+ ///
+ private void InitializeSecurityModes(EndpointDescriptionCollection endpoints)
+ {
+ // filter by the current protocol.
+ Protocol currentProtocol = (Protocol)ProtocolCB.SelectedItem;
+
+ // preserve the existing value.
+ MessageSecurityMode currentMode = MessageSecurityMode.None;
+
+ if (SecurityModeCB.SelectedIndex != -1)
+ {
+ currentMode = (MessageSecurityMode)SecurityModeCB.SelectedItem;
+ }
+
+ SecurityModeCB.Items.Clear();
+
+ // set all available security modes.
+ if (m_showAllOptions)
+ {
+ SecurityModeCB.Items.Add(MessageSecurityMode.None);
+ SecurityModeCB.Items.Add(MessageSecurityMode.Sign);
+ SecurityModeCB.Items.Add(MessageSecurityMode.SignAndEncrypt);
+ }
+
+ // find all unique security modes.
+ else
+ {
+ if (endpoints != null)
+ {
+ foreach (EndpointDescription endpoint in endpoints)
+ {
+ Uri url = Utils.ParseUri(endpoint.EndpointUrl);
+
+ if (url != null)
+ {
+ if (currentProtocol == null ||
+ !currentProtocol.Matches(url))
+ {
+ continue;
+ }
+
+ if (!SecurityModeCB.Items.Contains(endpoint.SecurityMode))
+ {
+ SecurityModeCB.Items.Add(endpoint.SecurityMode);
+ }
+ }
+ }
+ }
+
+ // add at least one policy.
+ if (SecurityModeCB.Items.Count == 0)
+ {
+ SecurityModeCB.Items.Add(MessageSecurityMode.None);
+ }
+ }
+
+ // set the current value.
+ int index = SecurityModeCB.Items.IndexOf(currentMode);
+
+ if (index == -1)
+ {
+ index = 0;
+ }
+
+ SecurityModeCB.SelectedIndex = index;
+ }
+
+ ///
+ /// Initializes the security policies dropdown.
+ ///
+ private void InitializeSecurityPolicies(EndpointDescriptionCollection endpoints)
+ {
+ // filter by the current protocol.
+ Protocol currentProtocol = (Protocol)ProtocolCB.SelectedItem;
+
+ // filter by the current security mode.
+ MessageSecurityMode currentMode = MessageSecurityMode.None;
+
+ if (SecurityModeCB.SelectedIndex != -1)
+ {
+ currentMode = (MessageSecurityMode)SecurityModeCB.SelectedItem;
+ }
+
+ // preserve the existing value.
+ string currentPolicy = (string)SecurityPolicyCB.SelectedItem;
+
+ SecurityPolicyCB.Items.Clear();
+
+ // set all available security policies.
+ if (m_showAllOptions)
+ {
+ SecurityPolicyCB.Items.Add(SecurityPolicies.GetDisplayName(SecurityPolicies.None));
+ SecurityPolicyCB.Items.Add(SecurityPolicies.GetDisplayName(SecurityPolicies.Basic128Rsa15));
+ SecurityPolicyCB.Items.Add(SecurityPolicies.GetDisplayName(SecurityPolicies.Basic256));
+ }
+
+ // find all unique security policies.
+ else
+ {
+ if (endpoints != null)
+ {
+ foreach (EndpointDescription endpoint in endpoints)
+ {
+ Uri url = Utils.ParseUri(endpoint.EndpointUrl);
+
+ if (url != null)
+ {
+ if (currentProtocol == null ||
+ !currentProtocol.Matches(url))
+ {
+ continue;
+ }
+
+ if (currentMode != endpoint.SecurityMode)
+ {
+ continue;
+ }
+
+ string policyName = SecurityPolicies.GetDisplayName(endpoint.SecurityPolicyUri);
+
+ if (policyName != null)
+ {
+ int existingIndex = SecurityPolicyCB.Items.IndexOf(SecurityPolicyCB.FindName(policyName));
+
+ if (existingIndex == -1)
+ {
+ SecurityPolicyCB.Items.Add(policyName);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // add at least one policy.
+ if (SecurityPolicyCB.Items.Count == 0)
+ {
+ SecurityPolicyCB.Items.Add(SecurityPolicies.GetDisplayName(SecurityPolicies.None));
+ }
+
+ // set the current value.
+ int index = 0;
+
+ if (!String.IsNullOrEmpty(currentPolicy))
+ {
+ index = SecurityPolicyCB.Items.IndexOf(SecurityPolicyCB.FindName(currentPolicy));
+
+ if (index == -1)
+ {
+ index = 0;
+ }
+ }
+
+ SecurityPolicyCB.SelectedIndex = index;
+ }
+
+ ///
+ /// Initializes the message encodings dropdown.
+ ///
+ private void InitializeEncodings(EndpointDescription endpoint)
+ {
+ // preserve the existing value.
+ Encoding currentEncoding = Encoding.Default;
+
+ if (EncodingCB.SelectedIndex != -1)
+ {
+ currentEncoding = (Encoding)EncodingCB.SelectedItem;
+ }
+
+ EncodingCB.Items.Clear();
+
+ if (endpoint != null)
+ {
+ switch (endpoint.EncodingSupport)
+ {
+ case BinaryEncodingSupport.None:
+ {
+ EncodingCB.Items.Add(Encoding.Xml);
+ break;
+ }
+
+ case BinaryEncodingSupport.Required:
+ {
+ EncodingCB.Items.Add(Encoding.Binary);
+ break;
+ }
+
+ case BinaryEncodingSupport.Optional:
+ {
+ EncodingCB.Items.Add(Encoding.Binary);
+ EncodingCB.Items.Add(Encoding.Xml);
+ break;
+ }
+ }
+ }
+
+ // add at least one encoding.
+ if (EncodingCB.Items.Count == 0)
+ {
+ EncodingCB.Items.Add(Encoding.Default);
+ }
+
+ // set the current value.
+ int index = EncodingCB.Items.IndexOf(currentEncoding);
+
+ if (index == -1)
+ {
+ index = 0;
+ }
+
+ EncodingCB.SelectedIndex = index;
+ }
+
+ ///
+ /// Initializes the user token types dropdown.
+ ///
+ private void InitializeUserTokenTypes(EndpointDescription endpoint)
+ {
+ // preserve the existing value.
+ UserTokenItem currentTokenType = new UserTokenItem(UserTokenType.Anonymous);
+
+ if (UserTokenTypeCB.SelectedIndex != -1)
+ {
+ currentTokenType = (UserTokenItem)UserTokenTypeCB.SelectedItem;
+ }
+
+ UserTokenTypeCB.Items.Clear();
+
+ // show all options.
+ if (m_showAllOptions)
+ {
+ UserTokenTypeCB.Items.Add(new UserTokenItem(UserTokenType.Anonymous));
+ UserTokenTypeCB.Items.Add(new UserTokenItem(UserTokenType.UserName));
+ UserTokenTypeCB.Items.Add(new UserTokenItem(UserTokenType.Certificate));
+ UserTokenTypeCB.Items.Add(new UserTokenItem(UserTokenType.IssuedToken));
+ }
+
+ // find all unique token types.
+ else
+ {
+ if (endpoint != null)
+ {
+ foreach (UserTokenPolicy policy in endpoint.UserIdentityTokens)
+ {
+ UserTokenTypeCB.Items.Add(new UserTokenItem(policy));
+ }
+ }
+
+ // add at least one policy.
+ if (UserTokenTypeCB.Items.Count == 0)
+ {
+ UserTokenTypeCB.Items.Add(new UserTokenItem(UserTokenType.Anonymous));
+ }
+ }
+
+ int index = -1;
+
+ // try to match policy id.
+ for (int ii = 0; ii < UserTokenTypeCB.Items.Count; ii++)
+ {
+ UserTokenItem item = (UserTokenItem)UserTokenTypeCB.Items[ii];
+
+ if (item.Policy.PolicyId == currentTokenType.Policy.PolicyId)
+ {
+ index = ii;
+ break;
+ }
+ }
+
+ // match user token type.
+ if (index == -1)
+ {
+ index = 0;
+
+ for (int ii = 0; ii < UserTokenTypeCB.Items.Count; ii++)
+ {
+ UserTokenItem item = (UserTokenItem)UserTokenTypeCB.Items[ii];
+
+ if (item.Policy.TokenType == currentTokenType.Policy.TokenType)
+ {
+ index = ii;
+ break;
+ }
+ }
+ }
+
+ UserTokenTypeCB.SelectedIndex = index;
+ }
+
+ private class UserTokenItem
+ {
+ public UserTokenPolicy Policy;
+
+ public UserTokenItem(UserTokenPolicy policy)
+ {
+ Policy = policy;
+ }
+
+ public UserTokenItem(UserTokenType tokenType)
+ {
+ Policy = new UserTokenPolicy(tokenType);
+ }
+
+ public override string ToString()
+ {
+ if (Policy != null)
+ {
+ if (String.IsNullOrEmpty(Policy.PolicyId))
+ {
+ return Policy.TokenType.ToString();
+ }
+
+ return Utils.Format("{0} [{1}]", Policy.TokenType, Policy.PolicyId);
+ }
+
+ return UserTokenType.Anonymous.ToString();
+ }
+ }
+
+ ///
+ /// Initializes the user identity control.
+ ///
+ private void InitializeIssuedTokenType(EndpointDescription endpoint)
+ {
+ // get the current user token type.
+ UserTokenItem currentTokenType = new UserTokenItem(UserTokenType.Anonymous);
+
+ if (UserTokenTypeCB.SelectedIndex != -1)
+ {
+ currentTokenType = (UserTokenItem)UserTokenTypeCB.SelectedItem;
+ }
+
+ // preserve the existing value.
+ string currentIssuedTokenType = (string)IssuedTokenTypeCB.SelectedItem;
+
+ IssuedTokenTypeCB.Items.Clear();
+ IssuedTokenTypeCB.IsEnabled = false;
+
+ // only applies to issued tokens.
+ if (currentTokenType.Policy.TokenType != UserTokenType.IssuedToken)
+ {
+ return;
+ }
+
+ // only one item to select.
+ if (currentTokenType.Policy.IssuedTokenType != null)
+ {
+ IssuedTokenTypeCB.Items.Add(currentTokenType.Policy.IssuedTokenType);
+ IssuedTokenTypeCB.SelectedIndex = 0;
+ IssuedTokenTypeCB.IsEnabled = true;
+ }
+ }
+
+ ///
+ /// Initializes the user identity control.
+ ///
+ private void InitializeUserIdentity(ConfiguredEndpoint endpoint)
+ {
+ // get the current user token type.
+ UserTokenItem currentItem = new UserTokenItem(UserTokenType.Anonymous);
+
+ if (UserTokenTypeCB.SelectedIndex != -1)
+ {
+ currentItem = (UserTokenItem)UserTokenTypeCB.SelectedItem;
+ }
+
+ // get the identity.
+ UserIdentityToken identity = null;
+ m_userIdentities.TryGetValue(currentItem.ToString(), out identity);
+
+ // set the default values.
+ UserIdentityTB.Text = "";
+ UserIdentityTB.IsEnabled = currentItem.Policy.TokenType != UserTokenType.Anonymous;
+ UserIdentityBTN.IsEnabled = currentItem.Policy.TokenType != UserTokenType.Anonymous;
+
+ // update from endpoint.
+ if (identity != null)
+ {
+ UserNameIdentityToken userNameToken = identity as UserNameIdentityToken;
+
+ if (userNameToken != null)
+ {
+ UserIdentityTB.Text = userNameToken.UserName;
+ }
+ }
+ }
+
+ ///
+ /// Attempts fetch the list of servers from the discovery server.
+ ///
+ private void OnDiscoverEndpoints(object state)
+ {
+ // do nothing if a valid list is not provided.
+ ApplicationDescription server = state as ApplicationDescription;
+
+ if (server == null)
+ {
+ return;
+ }
+
+ Task.Run(() =>
+ {
+ int discoverCount = m_discoverCount;
+
+ OnUpdateStatus("Attempting to read latest configuration options from server.");
+
+ // process each url.
+ foreach (string discoveryUrl in server.DiscoveryUrls)
+ {
+ Uri url = Utils.ParseUri(discoveryUrl);
+
+ if (url != null)
+ {
+ try {
+ if (DiscoverEndpoints(url))
+ {
+ m_discoverySucceeded = true;
+ m_discoveryUrl = url;
+ OnUpdateStatus("Configuration options are up to date.");
+ return;
+ }
+
+ // check if another discover operation has started.
+ if (discoverCount != m_discoverCount)
+ {
+ return;
+ }
+ }
+ catch
+ {
+ // protocol may not be supported, continue
+ }
+ }
+ }
+
+ OnUpdateEndpoints(m_availableEndpoints);
+ OnUpdateStatus("Configuration options may not be correct because the server is not available.");
+ });
+ }
+
+ ///
+ /// Replace localhost in returned discovery url with remote host name.
+ ///
+ private void ReplaceLocalHostWithRemoteHost(EndpointDescriptionCollection endpoints, Uri discoveryUrl)
+ {
+ foreach (EndpointDescription endpoint in endpoints)
+ {
+ endpoint.EndpointUrl = Utils.ReplaceLocalhost(endpoint.EndpointUrl, discoveryUrl.DnsSafeHost);
+ StringCollection updatedDiscoveryUrls = new StringCollection();
+ foreach (string url in endpoint.Server.DiscoveryUrls)
+ {
+ updatedDiscoveryUrls.Add(Utils.ReplaceLocalhost(url, discoveryUrl.DnsSafeHost));
+ }
+ endpoint.Server.DiscoveryUrls = updatedDiscoveryUrls;
+ }
+ }
+
+
+ ///
+ /// Fetches the servers from the discovery server.
+ ///
+ private bool DiscoverEndpoints(Uri discoveryUrl)
+ {
+ // use a short timeout.
+ EndpointConfiguration configuration = EndpointConfiguration.Create(m_configuration);
+ configuration.OperationTimeout = m_discoveryTimeout;
+
+ DiscoveryClient client = DiscoveryClient.Create(
+ discoveryUrl,
+ EndpointConfiguration.Create(m_configuration));
+
+ try
+ {
+ EndpointDescriptionCollection endpoints = client.GetEndpoints(null);
+ ReplaceLocalHostWithRemoteHost(endpoints, discoveryUrl);
+ OnUpdateEndpoints(endpoints);
+ return true;
+ }
+ catch (Exception e)
+ {
+ Utils.Trace("Could not fetch endpoints from url: {0}. Reason={1}", discoveryUrl, e.Message);
+ return false;
+ }
+ finally
+ {
+ client.Dispose();
+ }
+ }
+
+ ///
+ /// Updates the status displayed in the dialog.
+ ///
+ private async void OnUpdateStatus(object status)
+ {
+ if (!Dispatcher.HasThreadAccess)
+ {
+ await Dispatcher.RunAsync(
+ CoreDispatcherPriority.Normal,
+ () =>
+ {
+ OnUpdateStatus(status);
+ });
+ return;
+ }
+ StatusTB.Text = status as string;
+ }
+
+ ///
+ /// Updates the list of servers displayed in the control.
+ ///
+ private async void OnUpdateEndpoints(object state)
+ {
+ if (!Dispatcher.HasThreadAccess)
+ {
+ await Dispatcher.RunAsync(
+ CoreDispatcherPriority.Normal,
+ () =>
+ {
+ OnUpdateEndpoints(state);
+ });
+ return;
+ }
+ try
+ {
+ // get the updated descriptions.
+ EndpointDescriptionCollection endpoints = state as EndpointDescriptionCollection;
+
+ if (endpoints == null)
+ {
+ m_showAllOptions = true;
+ InitializeProtocols(m_availableEndpoints);
+ }
+
+ else
+ {
+ m_showAllOptions = false;
+ m_availableEndpoints = endpoints;
+
+ if (endpoints.Count > 0)
+ {
+ m_currentDescription = endpoints[0];
+ }
+
+ // initializing the protocol will trigger an update to all other controls.
+ InitializeProtocols(m_availableEndpoints);
+
+ // select the best security mode.
+ MessageSecurityMode bestMode = MessageSecurityMode.Invalid;
+
+ foreach (MessageSecurityMode securityMode in SecurityModeCB.Items)
+ {
+ if (securityMode > bestMode)
+ {
+ bestMode = securityMode;
+ }
+ }
+
+ SecurityModeCB.SelectedItem = bestMode;
+
+ // select the best encoding.
+ Encoding bestEncoding = Encoding.Default;
+
+ foreach (Encoding encoding in EncodingCB.Items)
+ {
+ if (encoding > bestEncoding)
+ {
+ bestEncoding = encoding;
+ }
+ }
+
+ EncodingCB.SelectedItem = bestEncoding;
+ }
+
+ if (m_endpoint != null)
+ {
+ Uri url = m_endpoint.EndpointUrl;
+
+ foreach (Protocol protocol in ProtocolCB.Items)
+ {
+ if (protocol.Matches(url))
+ {
+ ProtocolCB.SelectedItem = protocol;
+ break;
+ }
+ }
+
+ foreach (MessageSecurityMode securityMode in SecurityModeCB.Items)
+ {
+ if (securityMode == m_endpoint.Description.SecurityMode)
+ {
+ SecurityModeCB.SelectedItem = securityMode;
+ break;
+ }
+ }
+
+ foreach (string securityPolicy in SecurityPolicyCB.Items)
+ {
+ if (securityPolicy == m_endpoint.Description.SecurityPolicyUri)
+ {
+ SecurityPolicyCB.SelectedItem = securityPolicy;
+ break;
+ }
+ }
+
+ foreach (Encoding encoding in EncodingCB.Items)
+ {
+ if (encoding == Encoding.Binary && m_endpoint.Configuration.UseBinaryEncoding)
+ {
+ EncodingCB.SelectedItem = encoding;
+ break;
+ }
+
+ if (encoding == Encoding.Xml && !m_endpoint.Configuration.UseBinaryEncoding)
+ {
+ EncodingCB.SelectedItem = encoding;
+ break;
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Utils.Trace(e, "Unexpected error updating endpoints.");
+ }
+ }
+
+ ///
+ /// Creates the endpoint description from current selections.
+ ///
+ private EndpointDescription CreateDescriptionFromSelections()
+ {
+ Protocol currentProtocol = (Protocol)ProtocolCB.SelectedItem;
+
+ EndpointDescription endpoint = null;
+
+ for (int ii = 0; ii < m_availableEndpoints.Count; ii++)
+ {
+ Uri url = Utils.ParseUri(m_availableEndpoints[ii].EndpointUrl);
+
+ if (url == null)
+ {
+ continue;
+ }
+
+ if (endpoint == null)
+ {
+ endpoint = m_availableEndpoints[ii];
+ }
+
+ if (currentProtocol.Matches(url))
+ {
+ endpoint = m_availableEndpoints[ii];
+ break;
+ }
+ }
+
+ UriBuilder builder = null;
+ string scheme = Utils.UriSchemeOpcTcp;
+
+ if (currentProtocol != null && currentProtocol.Url != null)
+ {
+ scheme = currentProtocol.Url.Scheme;
+ }
+
+ if (endpoint == null)
+ {
+ builder = new UriBuilder();
+ builder.Host = "localhost";
+
+ if (scheme == Utils.UriSchemeOpcTcp)
+ {
+ builder.Port = Utils.UaTcpDefaultPort;
+ }
+ }
+ else
+ {
+ builder = new UriBuilder(endpoint.EndpointUrl);
+ }
+
+ builder.Scheme = scheme;
+
+ endpoint = new EndpointDescription();
+ endpoint.EndpointUrl = builder.ToString();
+ endpoint.SecurityMode = (MessageSecurityMode)SecurityModeCB.SelectedItem;
+ endpoint.SecurityPolicyUri = SecurityPolicies.GetUri((string)SecurityPolicyCB.SelectedItem);
+ endpoint.Server.ApplicationName = endpoint.EndpointUrl;
+ endpoint.Server.ApplicationType = ApplicationType.Server;
+ endpoint.Server.ApplicationUri = endpoint.EndpointUrl;
+
+ UserTokenItem userTokenType = (UserTokenItem)UserTokenTypeCB.SelectedItem;
+
+ if (userTokenType != null && userTokenType.Policy != null)
+ {
+ endpoint.UserIdentityTokens.Add(userTokenType.Policy);
+ }
+
+ return endpoint;
+ }
+ #endregion
+
+ #region Event Handlers
+ private async void OkBTN_Click(object sender, RoutedEventArgs e)
+ {
+ try
+ {
+ // check that discover has completed.
+ if (!m_discoverySucceeded)
+ {
+ MessageDlg dialog = new MessageDlg("Endpoint information may be out of date because the discovery process has not completed. Continue anyway?", MessageDlgButton.Yes, MessageDlgButton.No);
+ MessageDlgButton result = await dialog.ShowAsync();
+ if (result != MessageDlgButton.Yes)
+ {
+ return;
+ }
+ }
+
+ EndpointConfiguration configuration = m_endpointConfiguration;
+
+ if (configuration == null)
+ {
+ configuration = EndpointConfiguration.Create(m_configuration);
+ }
+
+ if (m_currentDescription == null)
+ {
+ m_currentDescription = CreateDescriptionFromSelections();
+ }
+
+ // the discovery endpoint should always be on the same machine as the server.
+ // if there is a mismatch it is likely because the server has multiple addresses
+ // and was not configured to return the current address to the client.
+ // The code automatically updates the domain in the url.
+ Uri endpointUrl = Utils.ParseUri(m_currentDescription.EndpointUrl);
+
+ if (m_discoverySucceeded)
+ {
+ if (!Utils.AreDomainsEqual(endpointUrl, m_discoveryUrl))
+ {
+ UriBuilder url = new UriBuilder(endpointUrl);
+
+ url.Host = m_discoveryUrl.DnsSafeHost;
+
+ if (url.Scheme == m_discoveryUrl.Scheme)
+ {
+ url.Port = m_discoveryUrl.Port;
+ }
+
+ endpointUrl = url.Uri;
+
+ m_currentDescription.EndpointUrl = endpointUrl.ToString();
+ }
+ }
+
+ // set the encoding.
+ Encoding encoding = (Encoding)EncodingCB.SelectedItem;
+ configuration.UseBinaryEncoding = encoding != Encoding.Xml;
+
+ if (m_endpoint == null)
+ {
+ m_endpoint = new ConfiguredEndpoint(null, m_currentDescription, configuration);
+ }
+ else
+ {
+ m_endpoint.Update(m_currentDescription);
+ m_endpoint.Update(configuration);
+ }
+
+ // set the user token policy.
+ m_endpoint.SelectedUserTokenPolicyIndex = FindBestUserTokenPolicy(m_currentDescription);
+
+ // update the user identity.
+ UserTokenItem userTokenItem = (UserTokenItem)UserTokenTypeCB.SelectedItem;
+
+ UserIdentityToken userIdentity = null;
+
+ if (!m_userIdentities.TryGetValue(userTokenItem.ToString(), out userIdentity))
+ {
+ userIdentity = null;
+ }
+
+ m_endpoint.UserIdentity = userIdentity;
+
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
+ }
+
+ dialogPopup.IsOpen = false;
+ }
+
+ private void ProtocolCB_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ try
+ {
+ m_updating = true;
+ InitializeSecurityModes(m_availableEndpoints);
+
+ // update current description.
+ m_currentDescription = FindBestEndpointDescription(m_availableEndpoints);
+
+ InitializeEncodings(m_currentDescription);
+ InitializeUserTokenTypes(m_currentDescription);
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
+ }
+ finally
+ {
+ m_updating = false;
+ }
+ }
+
+ private void SecurityModeCB_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ try
+ {
+ InitializeSecurityPolicies(m_availableEndpoints);
+
+ if (!m_updating)
+ {
+ try
+ {
+ m_updating = true;
+
+ // update current description.
+ m_currentDescription = FindBestEndpointDescription(m_availableEndpoints);
+
+ InitializeEncodings(m_currentDescription);
+ InitializeUserTokenTypes(m_currentDescription);
+ }
+ finally
+ {
+ m_updating = false;
+ }
+ }
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
+ }
+ }
+
+ private void SecurityPolicyCB_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ try
+ {
+ if (!m_updating)
+ {
+ try
+ {
+ m_updating = true;
+
+ // update current description.
+ m_currentDescription = FindBestEndpointDescription(m_availableEndpoints);
+
+ InitializeEncodings(m_currentDescription);
+ InitializeUserTokenTypes(m_currentDescription);
+ }
+ finally
+ {
+ m_updating = false;
+ }
+ }
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
+ }
+ }
+
+ private void UserTokenTypeCB_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ try
+ {
+ InitializeIssuedTokenType(m_currentDescription);
+ InitializeUserIdentity(m_endpoint);
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
+ }
+ }
+
+ private void UseDefaultLimitsCB_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ try
+ {
+ int index = UseDefaultLimitsCB.SelectedIndex;
+
+ if (index != -1)
+ {
+ UseDefaultLimitsBTN.IsEnabled = (UseDefaultLimits)UseDefaultLimitsCB.SelectedItem == UseDefaultLimits.No;
+ }
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
+ }
+ }
+
+ private async void UserIdentityBTN_Click(object sender, RoutedEventArgs e)
+ {
+ try
+ {
+ UserTokenItem currentItem = new UserTokenItem(UserTokenType.Anonymous);
+
+ if (UserTokenTypeCB.SelectedIndex != -1)
+ {
+ currentItem = (UserTokenItem)UserTokenTypeCB.SelectedItem;
+ }
+
+ UserIdentityToken identity = null;
+ m_userIdentities.TryGetValue(currentItem.ToString(), out identity);
+
+ switch (currentItem.Policy.TokenType)
+ {
+ case UserTokenType.UserName:
+ {
+ UserNameIdentityToken userNameToken = identity as UserNameIdentityToken;
+
+ if (userNameToken == null)
+ {
+ userNameToken = new UserNameIdentityToken();
+ }
+
+ if (new UsernameTokenDlg().ShowDialog(userNameToken))
+ {
+ userNameToken.PolicyId = currentItem.Policy.PolicyId;
+ m_userIdentities[currentItem.ToString()] = userNameToken;
+ UserIdentityTB.Text = userNameToken.UserName;
+ }
+
+ break;
+ }
+
+ default:
+ {
+ MessageDlg dialog = new MessageDlg("User token type not supported at this time.");
+ await dialog.ShowAsync();
+ break;
+ }
+ }
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
+ }
+ }
+
+ private void CancelBTN_Click(object sender, RoutedEventArgs e)
+ {
+ m_endpoint = null;
+ dialogPopup.IsOpen = false;
+ }
+
+ private void RefreshBTN_Click(object sender, RoutedEventArgs e)
+ {
+ OnDiscoverEndpoints(m_endpoint.Description.Server);
+ }
+ #endregion
+
+ }
+}
diff --git a/SampleApplications/SDK/Controls/Endpoints/ConfiguredServerListCtrl.xaml b/SampleApplications/SDK/Controls/Endpoints/ConfiguredServerListCtrl.xaml
new file mode 100644
index 0000000000..dcfca829cd
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Endpoints/ConfiguredServerListCtrl.xaml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
diff --git a/SampleApplications/SDK/Controls/Endpoints/ConfiguredServerListCtrl.xaml.cs b/SampleApplications/SDK/Controls/Endpoints/ConfiguredServerListCtrl.xaml.cs
new file mode 100644
index 0000000000..56441279db
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Endpoints/ConfiguredServerListCtrl.xaml.cs
@@ -0,0 +1,260 @@
+/* ========================================================================
+ * Copyright (c) 2005-2013 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.Text;
+using System.Threading;
+using System.Reflection;
+using Windows.UI.Xaml.Controls;
+
+
+namespace Opc.Ua.Client.Controls
+{
+ ///
+ /// A list of servers.
+ ///
+ public partial class ConfiguredServerListCtrl : UserControl
+ {
+ #region Constructors
+ ///
+ /// Initalize the control.
+ ///
+ public ConfiguredServerListCtrl()
+ {
+ InitializeComponent();
+ }
+ #endregion
+
+ #region Private Fields
+ private ApplicationConfiguration m_configuration;
+ private ConfiguredEndpointCollection m_endpoints;
+ private bool m_updating = false;
+ private int m_updateCount = 0;
+
+ public object SelectedTag
+ {
+ get
+ {
+ if (ItemsLV.SelectedItems.Count != 1)
+ {
+ return null;
+ }
+
+ return ((ListViewItem)ItemsLV.SelectedItems[0]).Tag;
+ }
+ }
+ #endregion
+
+ #region Public Interface
+ ///
+ /// Displays a list of servers in the control.
+ ///
+ public void Initialize(ConfiguredEndpointCollection endpoints, ApplicationConfiguration configuration)
+ {
+ Interlocked.Exchange(ref m_configuration, configuration);
+
+ ItemsLV.Items.Clear();
+
+ m_endpoints = endpoints;
+
+ if (endpoints != null)
+ {
+ foreach (ConfiguredEndpoint endpoint in endpoints.Endpoints)
+ {
+ AddItem(endpoint);
+ }
+ }
+ }
+ #endregion
+
+ #region Overridden Methods
+ public ListViewItem AddItem(object item, int index = -1)
+ {
+ ListViewItem listItem = null;
+
+ if (m_updating)
+ {
+ if (m_updateCount < ItemsLV.Items.Count)
+ {
+ listItem = (ListViewItem)ItemsLV.Items[m_updateCount];
+ }
+
+ m_updateCount++;
+ }
+
+ if (listItem == null)
+ {
+ listItem = new ListViewItem();
+ }
+
+ listItem.Name = String.Format("{0}", item);
+ listItem.Tag = item;
+
+ // update columns.
+ UpdateItem(listItem, item);
+
+ if (listItem.Parent == null)
+ {
+ // add to control.
+ if (index >= 0 && index <= ItemsLV.Items.Count)
+ {
+ ItemsLV.Items.Insert(index, listItem);
+ }
+ else
+ {
+ ItemsLV.Items.Add(listItem);
+ }
+ }
+
+ // return new item.
+ return listItem;
+ }
+
+ ///
+ /// Updates an item in the control.
+ ///
+ public void UpdateItem(ListViewItem listItem, object item)
+ {
+ ConfiguredEndpoint endpoint = listItem.Tag as ConfiguredEndpoint;
+
+ if (endpoint == null)
+ {
+ listItem.Tag = endpoint;
+ return;
+ }
+
+ string hostname = "";
+ string protocol = "";
+
+ Uri uri = endpoint.EndpointUrl;
+
+ if (uri != null)
+ {
+ hostname = uri.DnsSafeHost;
+ protocol = uri.Scheme;
+ }
+
+ String user = "";
+ UserTokenPolicy policy = endpoint.SelectedUserTokenPolicy;
+ if (policy != null)
+ {
+ StringBuilder buffer = new StringBuilder();
+ buffer.Append(policy.TokenType);
+ if (endpoint.UserIdentity != null)
+ {
+ buffer.Append("/");
+ buffer.Append(endpoint.UserIdentity);
+ }
+ user = buffer.ToString();
+ }
+
+ listItem.Content = String.Format("Application: {0}\r\nHost: {1}\r\nProtocol: {2}\r\nSecurity: {3}/{4}\r\nUser: {5}",
+ endpoint.Description.Server.ApplicationName,
+ hostname,
+ protocol,
+ SecurityPolicies.GetDisplayName(endpoint.Description.SecurityPolicyUri),
+ endpoint.Description.SecurityMode,
+ user);
+ }
+ #endregion
+
+ #region Event Handlers
+ private async void NewMI_Click(object sender, EventArgs e)
+ {
+ try
+ {
+ ApplicationDescription server = new DiscoveredServerListDlg().ShowDialog(null, m_configuration);
+
+ if (server == null)
+ {
+ return;
+ }
+
+ ConfiguredEndpoint endpoint = await new ConfiguredServerDlg().ShowDialog(server, m_configuration);
+
+ if (endpoint == null)
+ {
+ return;
+ }
+
+ AddItem(endpoint);
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
+ }
+ }
+
+ private async void ConfigureMI_Click(object sender, EventArgs e)
+ {
+ try
+ {
+ ConfiguredEndpoint endpoint = SelectedTag as ConfiguredEndpoint;
+
+ if (endpoint == null)
+ {
+ return;
+ }
+
+ endpoint = await new ConfiguredServerDlg().ShowDialog(endpoint, m_configuration);
+
+ if (endpoint == null)
+ {
+ return;
+ }
+
+ UpdateItem((ListViewItem)ItemsLV.SelectedItems[0], endpoint);
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
+ }
+ }
+
+ private void DeleteMI_Click(object sender, EventArgs e)
+ {
+ try
+ {
+ ConfiguredEndpoint endpoint = SelectedTag as ConfiguredEndpoint;
+
+ if (endpoint == null)
+ {
+ return;
+ }
+
+ ItemsLV.Items.Remove(ItemsLV.SelectedItems[0]);
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
+ }
+ }
+#endregion
+ }
+}
diff --git a/SampleApplications/SDK/Controls/Endpoints/ConfiguredServerListDlg.xaml b/SampleApplications/SDK/Controls/Endpoints/ConfiguredServerListDlg.xaml
new file mode 100644
index 0000000000..eb34d95ba3
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Endpoints/ConfiguredServerListDlg.xaml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
diff --git a/SampleApplications/SDK/Controls/Endpoints/ConfiguredServerListDlg.xaml.cs b/SampleApplications/SDK/Controls/Endpoints/ConfiguredServerListDlg.xaml.cs
new file mode 100644
index 0000000000..3706800887
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Endpoints/ConfiguredServerListDlg.xaml.cs
@@ -0,0 +1,112 @@
+/* ========================================================================
+ * Copyright (c) 2005-2013 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 Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Controls.Primitives;
+
+namespace Opc.Ua.Client.Controls
+{
+ ///
+ /// Allows the user to browse a list of servers.
+ ///
+ public partial class ConfiguredServerListDlg : Page
+ {
+ #region Constructors
+ ///
+ /// Initializes the dialog.
+ ///
+ public ConfiguredServerListDlg()
+ {
+ InitializeComponent();
+ }
+ #endregion
+
+ #region Private Fields
+ private ConfiguredEndpoint m_endpoint;
+ private ApplicationConfiguration m_configuration;
+ #endregion
+
+ #region Public Interface
+ ///
+ /// Displays the dialog.
+ ///
+ public ConfiguredEndpoint ShowDialog(ApplicationConfiguration configuration, bool createNew)
+ {
+ m_configuration = configuration;
+ m_endpoint = null;
+
+ // create a default collection if none provided.
+ if (createNew)
+ {
+ ApplicationDescription server = new DiscoveredServerListDlg().ShowDialog(null, m_configuration);
+
+ if (server != null)
+ {
+ return new ConfiguredEndpoint(server, EndpointConfiguration.Create(configuration));
+ }
+
+ return null;
+ }
+
+ ServersCTRL.Initialize(null, configuration);
+
+ OkBTN.IsEnabled = false;
+
+ Popup myPopup = new Popup();
+ myPopup.Child = this;
+ myPopup.IsOpen = true;
+
+ return m_endpoint;
+ }
+ #endregion
+
+ #region Event Handlers
+ private void ServersCTRL_ItemsSelected(object sender, ListItemActionEventArgs e)
+ {
+ try
+ {
+ m_endpoint = null;
+
+ foreach (ConfiguredEndpoint server in e.Items)
+ {
+ m_endpoint = server;
+ break;
+ }
+
+ OkBTN.IsEnabled = m_endpoint != null;
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
+ }
+ }
+ #endregion
+ }
+}
diff --git a/SampleApplications/SDK/Controls/Endpoints/DiscoveredServerListCtrl.xaml b/SampleApplications/SDK/Controls/Endpoints/DiscoveredServerListCtrl.xaml
new file mode 100644
index 0000000000..8f6b956841
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Endpoints/DiscoveredServerListCtrl.xaml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
diff --git a/SampleApplications/SDK/Controls/Endpoints/DiscoveredServerListCtrl.xaml.cs b/SampleApplications/SDK/Controls/Endpoints/DiscoveredServerListCtrl.xaml.cs
new file mode 100644
index 0000000000..79d90b67cd
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Endpoints/DiscoveredServerListCtrl.xaml.cs
@@ -0,0 +1,348 @@
+/* ========================================================================
+ * Copyright (c) 2005-2013 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 Opc.Ua;
+using Opc.Ua.Client.Controls;
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Windows.UI.Xaml.Controls;
+
+namespace Opc.Ua.Client.Controls
+{
+ ///
+ /// Displays a list of servers.
+ ///
+ public sealed partial class DiscoveredServerListCtrl : UserControl
+ {
+ #region Constructors
+ ///
+ /// Initalize the control.
+ ///
+ public DiscoveredServerListCtrl()
+ {
+ InitializeComponent();
+ }
+ #endregion
+
+ #region Private Fields
+ private ApplicationConfiguration m_configuration;
+ private int m_discoveryTimeout;
+ private int m_discoverCount = 0;
+ private bool m_updating = false;
+ private int m_updateCount = 0;
+ private string m_discoveryUrl;
+ #endregion
+
+ #region Public Interface
+ ///
+ /// The timeout in milliseconds to use when discovering servers.
+ ///
+ [System.ComponentModel.DefaultValue(5000)]
+ public int DiscoveryTimeout
+ {
+ get { return m_discoveryTimeout; }
+ set { m_discoveryTimeout = value; }
+ }
+
+ ///
+ /// Gets or sets the discovery URL used to find the servers displayed in the control.
+ ///
+ /// The discovery URL.
+ public string DiscoveryUrl
+ {
+ get { return m_discoveryUrl; }
+ set { m_discoveryUrl = value; }
+ }
+
+ ///
+ /// Displays a list of servers in the control.
+ ///
+ public void Initialize(ConfiguredEndpointCollection endpoints, ApplicationConfiguration configuration)
+ {
+ Interlocked.Exchange(ref m_configuration, configuration);
+
+ ItemsLV.Items.Clear();
+
+ foreach (ApplicationDescription server in endpoints.GetServers())
+ {
+ AddItem(server);
+ }
+ }
+
+ ///
+ /// Displays a list of servers in the control.
+ ///
+ public void Initialize(string hostname, ApplicationConfiguration configuration)
+ {
+ Interlocked.Exchange(ref m_configuration, configuration);
+
+ ItemsLV.Items.Clear();
+
+ if (String.IsNullOrEmpty(hostname))
+ {
+ hostname = Utils.GetHostName();
+ }
+
+ this.Instructions.Text = Utils.Format("Discovering servers on host '{0}'.", hostname);
+
+ // get a list of well known discovery urls to use.
+ StringCollection discoveryUrls = null;
+
+ if (configuration != null && configuration.ClientConfiguration != null)
+ {
+ discoveryUrls = configuration.ClientConfiguration.WellKnownDiscoveryUrls;
+ }
+
+ if (discoveryUrls == null || discoveryUrls.Count == 0)
+ {
+ discoveryUrls = new StringCollection(Utils.DiscoveryUrls);
+ }
+
+ // update the urls with the hostname.
+ StringCollection urlsToUse = new StringCollection();
+
+ foreach (string discoveryUrl in discoveryUrls)
+ {
+ urlsToUse.Add(Utils.Format(discoveryUrl, hostname));
+ }
+
+ Interlocked.Increment(ref m_discoverCount);
+ Task.Run(() =>
+ {
+ OnDiscoverServers(urlsToUse);
+ });
+ }
+
+ public ListViewItem AddItem(object item, int index = -1)
+ {
+ ListViewItem listItem = null;
+
+ if (m_updating)
+ {
+ if (m_updateCount < ItemsLV.Items.Count)
+ {
+ listItem = (ListViewItem)ItemsLV.Items[m_updateCount];
+ }
+
+ m_updateCount++;
+ }
+
+ if (listItem == null)
+ {
+ listItem = new ListViewItem();
+ }
+
+ listItem.Name = String.Format("{0}", item);
+ listItem.Tag = item;
+
+ // calculate new index.
+ int newIndex = index;
+
+ if (index < 0 || index > ItemsLV.Items.Count)
+ {
+ newIndex = ItemsLV.Items.Count;
+ }
+
+ // update columns.
+ listItem.Tag = item;
+
+ if (listItem.Parent == null)
+ {
+ // add to control.
+ if (index >= 0 && index <= ItemsLV.Items.Count)
+ {
+ ItemsLV.Items.Insert(index, listItem);
+ }
+ else
+ {
+ ItemsLV.Items.Add(listItem);
+ }
+ }
+
+ // return new item.
+ return listItem;
+ }
+
+ ///
+ /// Updates the list of servers displayed in the control.
+ ///
+ private void OnUpdateServers(object state)
+ {
+ ItemsLV.Items.Clear();
+
+ ApplicationDescriptionCollection servers = state as ApplicationDescriptionCollection;
+
+ if (servers != null)
+ {
+ foreach (ApplicationDescription server in servers)
+ {
+ if (server.ApplicationType == ApplicationType.DiscoveryServer)
+ {
+ continue;
+ }
+
+ AddItem(server);
+ }
+ }
+
+ if (ItemsLV.Items.Count == 0)
+ {
+ this.Instructions.Text = Utils.Format("No servers to display.");
+ }
+ }
+
+ ///
+ /// Attempts fetch the list of servers from the discovery server.
+ ///
+ private void OnDiscoverServers(object state)
+ {
+ try
+ {
+ int discoverCount = m_discoverCount;
+
+ // do nothing if a valid list is not provided.
+ IList discoveryUrls = state as IList;
+
+ if (discoveryUrls == null)
+ {
+ return;
+ }
+
+ // process each url.
+ foreach (string discoveryUrl in discoveryUrls)
+ {
+ Uri url = Utils.ParseUri(discoveryUrl);
+
+ if (url != null)
+ {
+ if (DiscoverServers(url))
+ {
+ return;
+ }
+
+ // check if another discover operation has started.
+ if (discoverCount != m_discoverCount)
+ {
+ return;
+ }
+ }
+ }
+
+ // display empty list.
+ OnUpdateServers(null);
+ }
+ catch (Exception e)
+ {
+ Utils.Trace(e, "Unexpected error discovering servers.");
+ }
+ }
+
+ ///
+ /// Fetches the servers from the discovery server.
+ ///
+ private bool DiscoverServers(Uri discoveryUrl)
+ {
+ // use a short timeout.
+ EndpointConfiguration configuration = EndpointConfiguration.Create(m_configuration);
+ configuration.OperationTimeout = m_discoveryTimeout;
+
+ DiscoveryClient client = null;
+
+ try
+ {
+ client = DiscoveryClient.Create(
+ discoveryUrl,
+ EndpointConfiguration.Create(m_configuration));
+
+ ApplicationDescriptionCollection servers = client.FindServers(null);
+ m_discoveryUrl = discoveryUrl.ToString();
+ OnUpdateServers(servers);
+ return true;
+ }
+ catch (Exception e)
+ {
+ Utils.Trace("DISCOVERY ERROR - Could not fetch servers from url: {0}. Error=({2}){1}", discoveryUrl, e.Message, e.GetType());
+ return false;
+ }
+ finally
+ {
+ if (client != null)
+ {
+ client.Close();
+ }
+ }
+ }
+ #endregion
+
+ #region Overridden Methods
+ ///
+ /// Updates an item in the control.
+ ///
+ public void UpdateItem(ListViewItem listItem, object item)
+ {
+ ApplicationDescription server = listItem.Tag as ApplicationDescription;
+
+ if (server == null)
+ {
+ listItem.Tag = server;
+ return;
+ }
+
+ string hostname = "";
+
+ // extract host from application uri.
+ Uri uri = Utils.ParseUri(server.ApplicationUri);
+
+ if (uri != null)
+ {
+ hostname = uri.DnsSafeHost;
+ }
+
+ // get the host name from the discovery urls.
+ if (String.IsNullOrEmpty(hostname))
+ {
+ foreach (string discoveryUrl in server.DiscoveryUrls)
+ {
+ Uri url = Utils.ParseUri(discoveryUrl);
+
+ if (url != null)
+ {
+ hostname = url.DnsSafeHost;
+ break;
+ }
+ }
+ }
+
+ listItem.Content = String.Format("Name: {0}, type: {1}, host: {2}, URI: {3}", server.ApplicationName, server.ApplicationType, hostname, server.ApplicationUri);
+ }
+ #endregion
+ }
+}
diff --git a/SampleApplications/SDK/Controls/Endpoints/DiscoveredServerListDlg.xaml b/SampleApplications/SDK/Controls/Endpoints/DiscoveredServerListDlg.xaml
new file mode 100644
index 0000000000..e747166bc4
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Endpoints/DiscoveredServerListDlg.xaml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
diff --git a/SampleApplications/SDK/Controls/Endpoints/DiscoveredServerListDlg.xaml.cs b/SampleApplications/SDK/Controls/Endpoints/DiscoveredServerListDlg.xaml.cs
new file mode 100644
index 0000000000..64e2b5a123
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Endpoints/DiscoveredServerListDlg.xaml.cs
@@ -0,0 +1,160 @@
+/* ========================================================================
+ * Copyright (c) 2005-2013 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 Opc.Ua;
+using Opc.Ua.Client.Controls;
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using Windows.UI.Xaml.Controls;
+
+namespace Opc.Ua.Client.Controls
+{
+ ///
+ /// Allows the user to browse a list of servers.
+ ///
+ public partial class DiscoveredServerListDlg : Page
+ {
+ #region Constructors
+ ///
+ /// Initializes the dialog.
+ ///
+ public DiscoveredServerListDlg()
+ {
+ InitializeComponent();
+ }
+ #endregion
+
+ #region Private Fields
+ private string m_hostname;
+ private ApplicationDescription m_server;
+ private ApplicationConfiguration m_configuration;
+ #endregion
+
+ #region Public Interface
+ ///
+ /// Displays the dialog.
+ ///
+ public ApplicationDescription ShowDialog(string hostname, ApplicationConfiguration configuration)
+ {
+ m_configuration = configuration;
+
+ if (String.IsNullOrEmpty(hostname))
+ {
+ hostname = Utils.GetHostName();
+ }
+
+ m_hostname = hostname;
+ m_server = null;
+
+ List hostnames = new List();
+
+ HostNameCTRL.Initialize(hostname, hostnames);
+ ServersCTRL.Initialize(hostname, configuration);
+
+ OkBTN.IsEnabled = false;
+
+ return m_server;
+ }
+ #endregion
+
+ #region Event Handlers
+ private void HostNameCTRL_HostSelected(object sender, SelectHostCtrlEventArgs e)
+ {
+ try
+ {
+ if (m_hostname != e.Hostname)
+ {
+ m_hostname = e.Hostname;
+ ServersCTRL.Initialize(m_hostname, m_configuration);
+ m_server = null;
+ OkBTN.IsEnabled = false;
+ }
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
+ }
+ }
+
+ private void HostNameCTRL_HostConnected(object sender, SelectHostCtrlEventArgs e)
+ {
+ try
+ {
+ m_hostname = e.Hostname;
+ ServersCTRL.Initialize(m_hostname, m_configuration);
+ m_server = null;
+ OkBTN.IsEnabled = false;
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
+ }
+ }
+
+ private void ServersCTRL_ItemsSelected(object sender, ListItemActionEventArgs e)
+ {
+ try
+ {
+ m_server = null;
+
+ foreach (ApplicationDescription server in e.Items)
+ {
+ m_server = server;
+ break;
+ }
+
+ OkBTN.IsEnabled = m_server != null;
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
+ }
+ }
+
+ private void ServersCTRL_ItemsPicked(object sender, ListItemActionEventArgs e)
+ {
+ try
+ {
+ m_server = null;
+
+ foreach (ApplicationDescription server in e.Items)
+ {
+ m_server = server;
+ break;
+ }
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
+ }
+ }
+ #endregion
+ }
+}
diff --git a/SampleApplications/SDK/Controls/Endpoints/EndpointSelectorCtrl.xaml b/SampleApplications/SDK/Controls/Endpoints/EndpointSelectorCtrl.xaml
new file mode 100644
index 0000000000..f3874094e3
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Endpoints/EndpointSelectorCtrl.xaml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
diff --git a/SampleApplications/SDK/Controls/Endpoints/EndpointSelectorCtrl.xaml.cs b/SampleApplications/SDK/Controls/Endpoints/EndpointSelectorCtrl.xaml.cs
new file mode 100644
index 0000000000..4ae1430685
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Endpoints/EndpointSelectorCtrl.xaml.cs
@@ -0,0 +1,379 @@
+/* ========================================================================
+ * Copyright (c) 2005-2013 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.Reflection;
+using System.Threading.Tasks;
+using Windows.System;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Input;
+
+namespace Opc.Ua.Client.Controls
+{
+ ///
+ /// A control which displays a list of endpoints
+ ///
+ public sealed partial class EndpointSelectorCtrl : UserControl
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public EndpointSelectorCtrl()
+ {
+ InitializeComponent();
+ }
+
+ #region Private Fields
+ private int m_selectedIndex;
+ private ApplicationConfiguration m_configuration;
+ private ConfiguredEndpointCollection m_endpoints;
+ private event ConnectEndpointEventHandler m_ConnectEndpoint;
+ private event EventHandler m_EndpointsChanged;
+ #endregion
+
+ #region Public Interface
+ ///
+ /// Raised when the user presses the connect button.
+ ///
+ public event ConnectEndpointEventHandler ConnectEndpoint
+ {
+ add { m_ConnectEndpoint += value; }
+ remove { m_ConnectEndpoint -= value; }
+ }
+
+ ///
+ /// Raised when the endpoints displayed in the control are changed.
+ ///
+ public event EventHandler EndpointsChanged
+ {
+ add { m_EndpointsChanged += value; }
+ remove { m_EndpointsChanged -= value; }
+ }
+
+ ///
+ /// The endpoint currently displayed in the control.
+ ///
+ public ConfiguredEndpoint SelectedEndpoint
+ {
+ get
+ {
+ ConfiguredEndpoint item = EndpointCB.SelectedItem as ConfiguredEndpoint;
+
+ if (item != null)
+ {
+ return item;
+ }
+
+ if (String.IsNullOrEmpty(EndpointCB.SelectedItem.ToString()))
+ {
+ return null;
+ }
+
+ return m_endpoints.Create(EndpointCB.SelectedItem.ToString());
+ }
+
+ set
+ {
+ if (value == null)
+ {
+ EndpointCB.SelectedItem = null;
+ EndpointCB.SelectedIndex = -1;
+ return;
+ }
+
+ for (int ii = 1; ii < EndpointCB.Items.Count; ii++)
+ {
+ ConfiguredEndpoint item = EndpointCB.Items[ii] as ConfiguredEndpoint;
+
+ if (Object.ReferenceEquals(item, value))
+ {
+ EndpointCB.SelectedItem = item;
+ return;
+ }
+ }
+
+ // must be a new endpoint.
+ m_endpoints.Add(value);
+
+ // raise notification.
+ if (m_EndpointsChanged != null)
+ {
+ m_EndpointsChanged(this, null);
+ }
+
+ EndpointCB.Items.Add(value);
+ EndpointCB.SelectedIndex = EndpointCB.Items.IndexOf(value);
+ }
+ }
+
+ ///
+ /// Initializes the control with a list of endpoints.
+ ///
+ public void Initialize(ConfiguredEndpointCollection endpoints, ApplicationConfiguration configuration)
+ {
+ if (endpoints == null) throw new ArgumentNullException("endpoints");
+
+ m_endpoints = endpoints;
+ m_configuration = configuration;
+
+ EndpointCB.Items.Clear();
+ EndpointCB.SelectedIndex = -1;
+ EndpointCB.Items.Add("");
+
+ if (endpoints != null)
+ {
+ foreach (ConfiguredEndpoint endpoint in m_endpoints.Endpoints)
+ {
+ EndpointCB.Items.Add(endpoint);
+ }
+ }
+
+ if (EndpointCB.Items.Count > 1)
+ {
+ EndpointCB.SelectedIndex = m_selectedIndex = 1;
+ }
+ }
+ #endregion
+
+ #region Event Handlers
+ private async void ConnectButton_Click(object sender, RoutedEventArgs e)
+ {
+ try
+ {
+ // get selected endpoint.
+ ConfiguredEndpoint endpoint = SelectedEndpoint;
+
+ if (endpoint == null)
+ {
+ return;
+ }
+
+ // raise event.
+ if (m_ConnectEndpoint != null)
+ {
+ ConnectEndpointEventArgs args = new ConnectEndpointEventArgs(endpoint, true);
+
+ await m_ConnectEndpoint(this, args);
+
+ // save endpoint in drop down.
+ if (args.UpdateControl)
+ {
+ // must update the control because the display text may have changed.
+ Initialize(m_endpoints, m_configuration);
+ SelectedEndpoint = endpoint;
+ }
+ }
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
+ }
+ }
+
+ private void EndpointCB_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ try
+ {
+ if (EndpointCB.SelectedIndex != 0)
+ {
+ m_selectedIndex = EndpointCB.SelectedIndex;
+ return;
+ }
+
+ // modify configuration.
+ ConfiguredEndpoint endpoint = new ConfiguredServerListDlg().ShowDialog(m_configuration, true);
+
+ if (endpoint == null)
+ {
+ EndpointCB.SelectedIndex = m_selectedIndex;
+ return;
+ }
+
+ m_endpoints.Add(endpoint);
+
+ // raise notification.
+ if (m_EndpointsChanged != null)
+ {
+ m_EndpointsChanged(this, null);
+ }
+
+ // update dropdown.
+ Initialize(m_endpoints, m_configuration);
+
+ // update selection.
+ for (int ii = 0; ii < m_endpoints.Endpoints.Count; ii++)
+ {
+ if (Object.ReferenceEquals(endpoint, m_endpoints.Endpoints[ii]))
+ {
+ EndpointCB.SelectedIndex = ii + 1;
+ break;
+ }
+ }
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
+ }
+ }
+
+ private void EndpointCB_PointerPressed(object sender, PointerRoutedEventArgs e)
+ {
+ ConfiguredEndpoint endpoint = EndpointCB.SelectedValue as ConfiguredEndpoint;
+ if (endpoint != null)
+ {
+ InputTB.Text = endpoint.ToString();
+ }
+ else
+ {
+ InputTB.Text = "opc.tcp://";
+ }
+ InputTB.Visibility = Visibility.Visible;
+ EndpointCB.Visibility = Visibility.Collapsed;
+ }
+
+ private void InputTB_LostFocus(object sender, RoutedEventArgs e)
+ {
+ try
+ {
+ InputTB.Visibility = Visibility.Collapsed;
+ EndpointCB.Visibility = Visibility.Visible;
+ ConfiguredEndpoint endpoint = EndpointCB.SelectedValue as ConfiguredEndpoint;
+ if (endpoint == null ||
+ InputTB.Text != endpoint.ToString())
+ {
+ endpoint = m_endpoints.Create(InputTB.Text);
+ SelectedEndpoint = endpoint;
+ }
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
+ }
+ }
+
+ private void InputTB_KeyDown(object sender, KeyRoutedEventArgs e)
+ {
+ try
+ {
+ if (e.Key == VirtualKey.Enter)
+ {
+ InputTB.Visibility = Visibility.Collapsed;
+ EndpointCB.Visibility = Visibility.Visible;
+ }
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
+ }
+ }
+
+ private async void EndpointCB_KeyDown(object sender, KeyRoutedEventArgs e)
+ {
+ try
+ {
+ if (e.Key == VirtualKey.Delete)
+ {
+ // ignore "New"
+ if (m_selectedIndex == 0) return;
+
+ ConfiguredEndpoint endpoint = SelectedEndpoint;
+ MessageDlg dialog = new MessageDlg(
+ "Delete Endpoint?\r\n" + endpoint.EndpointUrl,
+ MessageDlgButton.Yes, MessageDlgButton.No);
+ if (await dialog.ShowAsync() == MessageDlgButton.Yes)
+ {
+ int oldIndex = m_selectedIndex;
+ m_endpoints.Remove(endpoint);
+ EndpointCB.Items.Remove(endpoint);
+ if (oldIndex > 0)
+ {
+ EndpointCB.SelectedIndex = m_selectedIndex = oldIndex-1;
+ }
+
+ // raise notification.
+ if (m_EndpointsChanged != null)
+ {
+ m_EndpointsChanged(this, null);
+ }
+ }
+ }
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
+ }
+ }
+ #endregion
+ }
+
+ #region ConnectEndpointEventArgs Class
+ ///
+ /// Contains arguments for a ConnectEndpoint event.
+ ///
+ public class ConnectEndpointEventArgs : EventArgs
+ {
+ ///
+ /// Initializes the object.
+ ///
+ public ConnectEndpointEventArgs(ConfiguredEndpoint endpoint, bool updateControl)
+ {
+ m_endpoint = endpoint;
+ m_updateControl = updateControl;
+ }
+
+ ///
+ /// The endpoint selected in the control.
+ ///
+ public ConfiguredEndpoint Endpoint
+ {
+ get { return m_endpoint; }
+ }
+
+ ///
+ /// Whether the endpoint should be saved in the control after the event completes.
+ ///
+ public bool UpdateControl
+ {
+ get { return m_updateControl; }
+ set { m_updateControl = value; }
+ }
+
+#region Private Fields
+ private ConfiguredEndpoint m_endpoint;
+ private bool m_updateControl;
+#endregion
+ }
+
+ ///
+ /// The delegate used to receive connect endpoint notifications.
+ ///
+ public delegate Task ConnectEndpointEventHandler(object sender, ConnectEndpointEventArgs e);
+#endregion
+}
diff --git a/SampleApplications/SDK/Controls/Endpoints/HostListCtrl.xaml b/SampleApplications/SDK/Controls/Endpoints/HostListCtrl.xaml
new file mode 100644
index 0000000000..eec5cd5b3b
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Endpoints/HostListCtrl.xaml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
diff --git a/SampleApplications/SDK/Controls/Endpoints/HostListCtrl.xaml.cs b/SampleApplications/SDK/Controls/Endpoints/HostListCtrl.xaml.cs
new file mode 100644
index 0000000000..3f2fdcd868
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Endpoints/HostListCtrl.xaml.cs
@@ -0,0 +1,240 @@
+/* ========================================================================
+ * Copyright (c) 2005-2013 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.Text;
+using System.Net;
+using Windows.UI.Xaml.Controls;
+using Opc.Ua.Configuration;
+using Opc.Ua;
+using System.Threading.Tasks;
+
+namespace Opc.Ua.Client.Controls
+{
+ ///
+ /// A list of hosts.
+ ///
+ public sealed partial class HostListCtrl : UserControl
+ {
+ #region Constructors
+ ///
+ /// Initalize the control.
+ ///
+ public HostListCtrl()
+ {
+ InitializeComponent();
+ m_enumerator = new HostEnumerator();
+ m_enumerator.HostsDiscovered += new EventHandler(HostEnumerator_HostsDiscovered);
+ }
+ #endregion
+
+ #region Private Fields
+ private HostEnumerator m_enumerator;
+ private bool m_waitingForHosts;
+ private bool m_updating = false;
+ private int m_updateCount = 0;
+ #endregion
+
+ #region Public Interface
+ ///
+ /// Displays a list of servers in the control.
+ ///
+ public void Initialize(string domain)
+ {
+ ItemsLV.Items.Clear();
+
+ this.Instructions.Text = Utils.Format("Discovering hosts on domain '{0}'.", domain);
+
+ m_waitingForHosts = true;
+ m_enumerator.Start(domain);
+ }
+ #endregion
+
+ #region Private Methods
+ ///
+ /// Finds the addresses for the specified host.
+ ///
+ private async Task OnFetchAddresses(object state)
+ {
+ ListViewItem listItem = state as ListViewItem;
+
+ if (listItem == null)
+ {
+ return;
+ }
+
+ string hostname = listItem.Tag as string;
+
+ if (hostname == null)
+ {
+ return;
+ }
+
+ try
+ {
+ IPAddress[] addresses = await Utils.GetHostAddresses(hostname);
+
+ StringBuilder buffer = new StringBuilder();
+
+ for (int ii = 0; ii < addresses.Length; ii++)
+ {
+ if (buffer.Length > 0)
+ {
+ buffer.Append(", ");
+ }
+
+ buffer.AppendFormat("{0}", addresses[ii]);
+ }
+
+ await Task.Run(() =>
+ {
+ OnUpdateAddress(new object[] { listItem, buffer.ToString() });
+ });
+ }
+ catch (Exception e)
+ {
+ Utils.Trace(e, "Could not get ip addresses for host: {0}", hostname);
+ await Task.Run(() =>
+ {
+ OnUpdateAddress(new object[] { listItem, e.Message });
+ });
+ }
+ }
+
+ ///
+ /// Updates the addresses for a host.
+ ///
+ private void OnUpdateAddress(object state)
+ {
+ ListViewItem listItem = ((object[])state)[0] as ListViewItem;
+
+ if (listItem == null)
+ {
+ return;
+ }
+
+ string addresses = ((object[])state)[1] as string;
+
+ if (addresses == null)
+ {
+ return;
+ }
+
+ listItem.Content = String.Format("Host: {0}\r\nAddress: {1}", listItem.Tag, addresses);
+ }
+ #endregion
+
+ #region Overridden Methods
+ ///
+ /// Updates an item in the control.
+ ///
+ public async void UpdateItem(ListViewItem listItem, object item)
+ {
+ string hostname = listItem.Tag as string;
+
+ if (hostname == null)
+ {
+ listItem.Tag = hostname;
+ return;
+ }
+
+ listItem.Content = String.Format("Host: {0}\r\nAddress: ", hostname);
+
+ await OnFetchAddresses(listItem);
+
+ }
+ #endregion
+
+ #region Event Handlers
+ private void HostEnumerator_HostsDiscovered(object sender, HostEnumeratorEventArgs e)
+ {
+ // check if this is the first callback.
+ if (m_waitingForHosts)
+ {
+ ItemsLV.Items.Clear();
+ m_waitingForHosts = false;
+ }
+
+ // populate list with hostnames.
+ if (e != null && e.Hostnames != null)
+ {
+ foreach (string hostname in e.Hostnames)
+ {
+ AddItem(hostname);
+ }
+ }
+ }
+
+ ///
+ /// Adds an item to the list.
+ ///
+ public ListViewItem AddItem(object item, int index = -1)
+ {
+ ListViewItem listItem = null;
+
+ if (m_updating)
+ {
+ if (m_updateCount < ItemsLV.Items.Count)
+ {
+ listItem = (ListViewItem)ItemsLV.Items[m_updateCount];
+ }
+
+ m_updateCount++;
+ }
+
+ if (listItem == null)
+ {
+ listItem = new ListViewItem();
+ }
+
+ listItem.Name = String.Format("{0}", item);
+ listItem.Tag = item;
+
+ // update columns.
+ UpdateItem(listItem, item);
+
+ if (listItem.Parent == null)
+ {
+ // add to control.
+ if (index >= 0 && index <= ItemsLV.Items.Count)
+ {
+ ItemsLV.Items.Insert(index, listItem);
+ }
+ else
+ {
+ ItemsLV.Items.Add(listItem);
+ }
+ }
+
+ // return new item.
+ return listItem;
+ }
+ #endregion
+ }
+}
diff --git a/SampleApplications/SDK/Controls/Endpoints/HostListDlg.xaml b/SampleApplications/SDK/Controls/Endpoints/HostListDlg.xaml
new file mode 100644
index 0000000000..83c0870a88
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Endpoints/HostListDlg.xaml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
diff --git a/SampleApplications/SDK/Controls/Endpoints/HostListDlg.xaml.cs b/SampleApplications/SDK/Controls/Endpoints/HostListDlg.xaml.cs
new file mode 100644
index 0000000000..4f980137f7
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Endpoints/HostListDlg.xaml.cs
@@ -0,0 +1,163 @@
+/* ========================================================================
+ * Copyright (c) 2005-2013 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 Opc.Ua.Client.Controls;
+using Opc.Ua.Configuration;
+using System;
+using System.Net;
+using System.Reflection;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Controls.Primitives;
+
+namespace Opc.Ua.Client.Controls
+{
+ ///
+ /// Allows the user to browse a list of servers.
+ ///
+ public sealed partial class HostListDlg : Page
+ {
+ #region Constructors
+ ///
+ /// Initializes the dialog.
+ ///
+ public HostListDlg()
+ {
+ InitializeComponent();
+ }
+ #endregion
+
+ #region Private Fields
+ private string m_domain;
+ private string m_hostname;
+ #endregion
+
+ #region Public Interface
+ ///
+ /// Displays the dialog.
+ ///
+ public string ShowDialog(string domain)
+ {
+ if (String.IsNullOrEmpty(domain))
+ {
+ domain = CredentialCache.DefaultNetworkCredentials.Domain;
+ }
+
+ m_domain = domain;
+
+ DomainNameCTRL.Initialize(m_domain, null);
+ HostsCTRL.Initialize(m_domain);
+ OkBTN.IsEnabled = false;
+
+ Popup myPopup = new Popup();
+ myPopup.Child = this;
+ myPopup.IsOpen = true;
+
+ return m_hostname;
+ }
+ #endregion
+
+ #region Event Handlers
+ private void DomainNameCTRL_HostSelected(object sender, SelectHostCtrlEventArgs e)
+ {
+ try
+ {
+ if (m_domain != e.Hostname)
+ {
+ m_domain = e.Hostname;
+ HostsCTRL.Initialize(m_domain);
+ m_hostname = null;
+ OkBTN.IsEnabled = false;
+ }
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
+ }
+ }
+
+ private void DomainNameCTRL_HostConnected(object sender, SelectHostCtrlEventArgs e)
+ {
+ try
+ {
+ m_domain = e.Hostname;
+ HostsCTRL.Initialize(m_domain);
+ m_hostname = null;
+ OkBTN.IsEnabled = false;
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
+ }
+ }
+
+ private void HostsCTRL_ItemsSelected(object sender, ListItemActionEventArgs e)
+ {
+ try
+ {
+ m_hostname = null;
+
+ foreach (string hostname in e.Items)
+ {
+ m_hostname = hostname;
+ break;
+ }
+
+ OkBTN.IsEnabled = !String.IsNullOrEmpty(m_hostname);
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
+ }
+ }
+
+ private void HostsCTRL_ItemsPicked(object sender, ListItemActionEventArgs e)
+ {
+ try
+ {
+ m_hostname = null;
+
+ foreach (string hostname in e.Items)
+ {
+ m_hostname = hostname;
+ break;
+ }
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
+ }
+ }
+ #endregion
+
+ private void OkBTN_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
+ {
+
+ }
+ }
+}
diff --git a/SampleApplications/SDK/Controls/Endpoints/SelectHostCtrl.xaml b/SampleApplications/SDK/Controls/Endpoints/SelectHostCtrl.xaml
new file mode 100644
index 0000000000..09d7331270
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Endpoints/SelectHostCtrl.xaml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
diff --git a/SampleApplications/SDK/Controls/Endpoints/SelectHostCtrl.xaml.cs b/SampleApplications/SDK/Controls/Endpoints/SelectHostCtrl.xaml.cs
new file mode 100644
index 0000000000..8e30f735e2
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Endpoints/SelectHostCtrl.xaml.cs
@@ -0,0 +1,256 @@
+/* ========================================================================
+ * Copyright (c) 2005-2013 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 Opc.Ua;
+using Opc.Ua.Client.Controls;
+using Opc.Ua.Configuration;
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.Reflection;
+using Windows.System;
+using Windows.UI.Xaml.Controls;
+
+namespace Opc.Ua.Client.Controls
+{
+ ///
+ /// Displays a drop down list of hosts.
+ ///
+ public sealed partial class SelectHostCtrl : UserControl
+ {
+ #region Constructors
+ ///
+ /// Initializes the control.
+ ///
+ public SelectHostCtrl()
+ {
+ InitializeComponent();
+ }
+ #endregion
+
+ #region Private Fields
+ private int m_selectedIndex;
+ private bool m_selectDomains;
+ private event EventHandler m_HostSelected;
+ private event EventHandler m_HostConnected;
+ #endregion
+
+ #region Public Interface
+ ///
+ /// Whether the control is used to select domains instead of hosts.
+ ///
+ [System.ComponentModel.DefaultValue(false)]
+ public bool SelectDomains
+ {
+ get { return m_selectDomains; }
+ set { m_selectDomains = value; }
+ }
+
+ ///
+ /// The text displayed on the connect button.
+ ///
+ [System.ComponentModel.DefaultValue("Connect")]
+ public string CommandText
+ {
+ get { return ConnectBTN.Content.ToString(); }
+ set { ConnectBTN.Content = value; }
+ }
+
+ ///
+ /// Displays a set of hostnames in the control.
+ ///
+ public void Initialize(string defaultHost, IList hostnames)
+ {
+ HostsCB.Items.Clear();
+
+ // add option to browse for hosts.
+ HostsCB.Items.Add("");
+
+ // add any existing hosts.
+ if (hostnames != null)
+ {
+ foreach (string hostname in hostnames)
+ {
+ HostsCB.Items.Add(hostname);
+ }
+ }
+
+ // set a suitable default hostname.
+ if (String.IsNullOrEmpty(defaultHost))
+ {
+ if (!m_selectDomains)
+ {
+ defaultHost = Utils.GetHostName();
+ }
+ else
+ {
+ defaultHost = CredentialCache.DefaultNetworkCredentials.Domain;
+ }
+
+ if (hostnames != null && hostnames.Count > 0)
+ {
+ defaultHost = hostnames[0];
+ }
+ }
+
+ // set the current selection.
+ m_selectedIndex = HostsCB.Items.IndexOf(HostsCB.FindName(defaultHost));
+
+ if (m_selectedIndex == -1)
+ {
+ HostsCB.Items.Add(defaultHost);
+ m_selectedIndex = HostsCB.SelectedIndex;
+ }
+
+ HostsCB.SelectedIndex = m_selectedIndex;
+ }
+
+ ///
+ /// Raised when a host is selected in the control.
+ ///
+ public event EventHandler HostSelected
+ {
+ add { m_HostSelected += value; }
+ remove { m_HostSelected -= value; }
+ }
+
+ ///
+ /// Raised when the connect button is clicked.
+ ///
+ public event EventHandler HostConnected
+ {
+ add { m_HostConnected += value; }
+ remove { m_HostConnected -= value; }
+ }
+ #endregion
+
+ #region Event Handlers
+ private void HostsCB_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ try
+ {
+ if (HostsCB.SelectedIndex != 0)
+ {
+ if (m_HostSelected != null)
+ {
+ m_HostSelected(this, new SelectHostCtrlEventArgs((string)HostsCB.SelectedItem));
+ }
+
+ m_selectedIndex = HostsCB.SelectedIndex;
+ return;
+ }
+
+ if (!m_selectDomains)
+ {
+ // prompt user to select a host.
+ string hostname = new HostListDlg().ShowDialog(null);
+
+ if (hostname == null)
+ {
+ HostsCB.SelectedIndex = m_selectedIndex;
+ return;
+ }
+
+ // set the current selection.
+ m_selectedIndex = HostsCB.Items.IndexOf(hostname);
+ if (m_selectedIndex == -1)
+ {
+ HostsCB.Items.Add(hostname);
+ m_selectedIndex = HostsCB.SelectedIndex;
+ }
+ }
+
+ HostsCB.SelectedIndex = m_selectedIndex;
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
+ }
+ }
+
+ private void ConnectBTN_Click(object sender, EventArgs e)
+ {
+ try
+ {
+ int index = HostsCB.SelectedIndex;
+ if (index == 0)
+ {
+ return;
+ }
+
+ if (m_HostConnected != null)
+ {
+ if (index == -1)
+ {
+ if (!String.IsNullOrEmpty(HostsCB.SelectedItem.ToString()))
+ {
+ m_HostConnected(this, new SelectHostCtrlEventArgs(HostsCB.SelectedItem.ToString()));
+ }
+
+ m_selectedIndex = HostsCB.Items.IndexOf(HostsCB.SelectedIndex);
+ return;
+ }
+
+ m_HostConnected(this, new SelectHostCtrlEventArgs((string)HostsCB.SelectedItem));
+ }
+ }
+ catch (Exception exception)
+ {
+ GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
+ }
+ }
+ #endregion
+ }
+
+ #region SelectHostCtrlEventArgs Class
+ ///
+ /// The event arguments passed when the SelectHostCtrlEventArgs raises events.
+ ///
+ public class SelectHostCtrlEventArgs : EventArgs
+ {
+ ///
+ /// Initilizes the object with the current hostname.
+ ///
+ public SelectHostCtrlEventArgs(string hostname)
+ {
+ m_hostname = hostname;
+ }
+
+ ///
+ /// The current hostname.
+ ///
+ public string Hostname
+ {
+ get { return m_hostname; }
+ }
+
+ private string m_hostname;
+ }
+ #endregion
+}
diff --git a/SampleApplications/SDK/Controls/Endpoints/UsernameTokenDlg.xaml b/SampleApplications/SDK/Controls/Endpoints/UsernameTokenDlg.xaml
new file mode 100644
index 0000000000..bd1428c695
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Endpoints/UsernameTokenDlg.xaml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
diff --git a/SampleApplications/SDK/Controls/Endpoints/UsernameTokenDlg.xaml.cs b/SampleApplications/SDK/Controls/Endpoints/UsernameTokenDlg.xaml.cs
new file mode 100644
index 0000000000..f14c6e1ed7
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Endpoints/UsernameTokenDlg.xaml.cs
@@ -0,0 +1,91 @@
+/* ========================================================================
+ * Copyright (c) 2005-2013 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 Opc.Ua;
+using System;
+using System.Text;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Controls.Primitives;
+
+namespace Opc.Ua.Client.Controls
+{
+ ///
+ /// Prompts the user to provide a user name and password.
+ ///
+ public sealed partial class UsernameTokenDlg : Page
+ {
+ #region Constructors
+ ///
+ /// Constructs a new instance.
+ ///
+ public UsernameTokenDlg()
+ {
+ InitializeComponent();
+ }
+ #endregion
+
+ #region Private Fields
+ #endregion
+
+ #region Public Interface
+ ///
+ /// Displays the dialog.
+ ///
+ public bool ShowDialog(UserNameIdentityToken token)
+ {
+ if (token != null)
+ {
+ UserNameCB.SelectedItem = token.UserName;
+
+ if (token.Password != null && token.Password.Length > 0)
+ {
+ PasswordTB.Password = new UTF8Encoding().GetString(token.Password);
+ }
+ }
+
+ Popup myPopup = new Popup();
+ myPopup.Child = this;
+ myPopup.IsOpen = true;
+
+ token.UserName = UserNameCB.SelectedItem.ToString();
+
+ if (!String.IsNullOrEmpty(PasswordTB.Password))
+ {
+ token.Password = new UTF8Encoding().GetBytes(PasswordTB.Password);
+ }
+ else
+ {
+ token.Password = null;
+ }
+
+ return true;
+ }
+ #endregion
+ }
+}
diff --git a/SampleApplications/SDK/Controls/Opc.Ua.Client.Controls.csproj b/SampleApplications/SDK/Controls/Opc.Ua.Client.Controls.csproj
new file mode 100644
index 0000000000..ede1fee8e9
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Opc.Ua.Client.Controls.csproj
@@ -0,0 +1,293 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {0BACFD1F-8BD1-45E2-81AD-F9DBB5FBE028}
+ Library
+ Properties
+ Opc.Ua.Client.Controls
+ Opc.Ua.Client.Controls
+ en-US
+ UAP
+ 10.0.10240.0
+ 10.0.10240.0
+ 14
+ 512
+ {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ prompt
+ 4
+
+
+ ARM
+ true
+ bin\ARM\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ ARM
+ false
+ prompt
+ true
+
+
+ ARM
+ bin\ARM\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ ARM
+ false
+ prompt
+ true
+
+
+ x64
+ true
+ bin\x64\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ x64
+ false
+ prompt
+ true
+
+
+ x64
+ bin\x64\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ x64
+ false
+ prompt
+ true
+
+
+ x86
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ x86
+ false
+ prompt
+ true
+
+
+
+
+ x86
+ bin\x86\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ x86
+ false
+ prompt
+ true
+
+
+
+
+
+
+
+ BaseListCtrl.xaml
+
+
+ BaseTreeCtrl.xaml
+
+
+ DataListCtrl.xaml
+
+
+ DateTimeValueEditCtrl.xaml
+
+
+ ExceptionDlg.xaml
+
+
+
+ MessageDlg.xaml
+
+
+ NodeIdCtrl.xaml
+
+
+ NodeIdValueEditDlg.xaml
+
+
+ ReferenceTypeCtrl.xaml
+
+
+ SimpleValueEditCtrl.xaml
+
+
+ ConfiguredServerDlg.xaml
+
+
+ ConfiguredServerListCtrl.xaml
+
+
+ ConfiguredServerListDlg.xaml
+
+
+ DiscoveredServerListCtrl.xaml
+
+
+ DiscoveredServerListDlg.xaml
+
+
+ EndpointSelectorCtrl.xaml
+
+
+ HostListCtrl.xaml
+
+
+ HostListDlg.xaml
+
+
+ SelectHostCtrl.xaml
+
+
+ UsernameTokenDlg.xaml
+
+
+
+
+
+
+
+ {aa9d8d17-5dbd-4e77-8496-e32177573bf3}
+ Opc.Ua.Core
+
+
+ {b89bfa9d-419f-49b4-8210-286e7167e646}
+ Opc.Ua.Client
+
+
+ {26a56753-9326-48c3-95bb-11594293b7a8}
+ Opc.Ua.Configuration
+
+
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ MSBuild:Compile
+ Designer
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+
+ 14.0
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/SampleApplications/SDK/Controls/Properties/AssemblyInfo.cs b/SampleApplications/SDK/Controls/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..4d9968c2bd
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Properties/AssemblyInfo.cs
@@ -0,0 +1,64 @@
+/* ========================================================================
+ * Copyright (c) 2005-2013 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.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Opc.Ua.Client.Controls")]
+[assembly: AssemblyDescription("UA Client Controls Library")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("OPC Foundation")]
+[assembly: AssemblyProduct("OPC UA SDK")]
+[assembly: AssemblyCopyright(AssemblyVersionInfo.Copyright)]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("9ef9957a-78fc-4102-9469-4c7b501d301b")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion(AssemblyVersionInfo.CurrentVersion)]
+[assembly: AssemblyFileVersion(AssemblyVersionInfo.CurrentFileVersion)]
diff --git a/SampleApplications/SDK/Controls/Properties/AssemblyVersionInfo.cs b/SampleApplications/SDK/Controls/Properties/AssemblyVersionInfo.cs
new file mode 100644
index 0000000000..0b0b5ea13e
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Properties/AssemblyVersionInfo.cs
@@ -0,0 +1,47 @@
+/* ========================================================================
+ * Copyright (c) 2005-2013 The OPC Foundation, Inc. All rights reserved.
+ *
+ * OPC Reciprocal Community License ("RCL") Version 1.00
+ *
+ * Unless explicitly acquired and licensed from Licensor under another
+ * license, the contents of this file are subject to the Reciprocal
+ * Community License ("RCL") Version 1.00, or subsequent versions
+ * as allowed by the RCL, and You may not copy or use this file in either
+ * source code or executable form, except in compliance with the terms and
+ * conditions of the RCL.
+ *
+ * All software distributed under the RCL is provided strictly on an
+ * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+ * AND LICENSOR HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
+ * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, QUIET ENJOYMENT, OR NON-INFRINGEMENT. See the RCL for specific
+ * language governing rights and limitations under the RCL.
+ *
+ * The complete license agreement can be found here:
+ * http://opcfoundation.org/License/RCL/1.00/
+ * ======================================================================*/
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+///
+/// Defines string constants for SDK version information.
+///
+internal static class AssemblyVersionInfo
+{
+ ///
+ /// The current copy right notice.
+ ///
+ public const string Copyright = "Copyright © 2004-2013 OPC Foundation, Inc";
+
+ ///
+ /// The current build version.
+ ///
+ public const string CurrentVersion = "1.02.334.6";
+
+ ///
+ /// The current build file version.
+ ///
+ public const string CurrentFileVersion = "1.02.334.6";
+}
diff --git a/SampleApplications/SDK/Controls/Properties/Opc.Ua.Client.Controls.rd.xml b/SampleApplications/SDK/Controls/Properties/Opc.Ua.Client.Controls.rd.xml
new file mode 100644
index 0000000000..08b158c457
--- /dev/null
+++ b/SampleApplications/SDK/Controls/Properties/Opc.Ua.Client.Controls.rd.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/SampleApplications/SDK/Controls/project.json b/SampleApplications/SDK/Controls/project.json
new file mode 100644
index 0000000000..dc670c4ddf
--- /dev/null
+++ b/SampleApplications/SDK/Controls/project.json
@@ -0,0 +1,17 @@
+{
+ "dependencies": {
+ "Microsoft.NETCore.UniversalWindowsPlatform": "5.0.0",
+ "WinRTXamlToolkit.UWP": "1.9.4"
+ },
+ "frameworks": {
+ "uap10.0": {}
+ },
+ "runtimes": {
+ "win10-arm": {},
+ "win10-arm-aot": {},
+ "win10-x86": {},
+ "win10-x86-aot": {},
+ "win10-x64": {},
+ "win10-x64-aot": {}
+ }
+}
\ No newline at end of file
diff --git a/SampleApplications/SDK/Server/AddressSpace/BaseEvent.cs b/SampleApplications/SDK/Server/AddressSpace/BaseEvent.cs
new file mode 100644
index 0000000000..8c41d8c192
--- /dev/null
+++ b/SampleApplications/SDK/Server/AddressSpace/BaseEvent.cs
@@ -0,0 +1,221 @@
+/* ========================================================================
+ * Copyright (c) 2005-2013 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.Generic;
+using System.ServiceModel;
+using System.Runtime.Serialization;
+
+#pragma warning disable 0618
+
+namespace Opc.Ua.Server
+{
+#if LEGACY_CORENODEMANAGER
+ [Obsolete("The BaseEvent class is obsolete and is not supported. See Opc.Ua.BaseEventState for a replacement.")]
+ public partial class BaseEvent : IFilterTarget
+ {
+ #region IFilterTarget Members
+ ///
+ public bool IsTypeOf(
+ FilterContext context,
+ NodeId typeDefinitionId)
+ {
+ if (context == null) throw new ArgumentNullException("context");
+
+ return context.TypeTree.IsTypeOf(TypeDefinitionId, typeDefinitionId);
+ }
+
+ ///
+ public bool IsInView(
+ FilterContext context,
+ NodeId viewId)
+ {
+ // events instances are not in any view.
+ return false;
+ }
+
+ ///
+ public virtual bool IsRelatedTo(
+ FilterContext context,
+ NodeId source,
+ NodeId targetTypeId,
+ NodeId referenceTypeId,
+ int hops)
+ {
+ // events instances do not have any relationships to other nodes.
+ return false;
+ }
+
+ ///
+ public virtual object GetAttributeValue(
+ FilterContext context,
+ NodeId typeDefinitionId,
+ IList relativePath,
+ uint attributeId,
+ NumericRange indexRange)
+ {
+ if (context == null) throw new ArgumentNullException("context");
+
+ // read the attribute value.
+ DataValue dataValue = ReadAttributeValue(
+ context,
+ typeDefinitionId,
+ relativePath,
+ attributeId,
+ indexRange);
+
+ if (StatusCode.IsBad(dataValue.StatusCode))
+ {
+ return dataValue.StatusCode;
+ }
+
+ // return the value.
+ return dataValue.Value;
+ }
+ #endregion
+
+ #region Public Methods
+ ///
+ /// Sets the EventId, EventType, Time, ReceiveTime, TimeZone and DaylightSavingsTime properties.
+ ///
+ public void InitializeNewEvent()
+ {
+ EventId.Value = Guid.NewGuid().ToByteArray();
+ EventType.Value = ExpandedNodeId.ToNodeId(this.TypeDefinitionId, Server.NamespaceUris);
+ Time.Value = DateTime.UtcNow;
+ ReceiveTime.Value = DateTime.UtcNow;
+ }
+ #endregion
+ }
+
+ #region GenericEvent Class
+ ///
+ /// Represents an instance of the BaseEventType ObjectType in the address space.
+ ///
+ [Obsolete("The GenericEvent class is obsolete and is not supported. See Opc.Ua.InstanceStateSnapshot for a replacement.")]
+ public partial class GenericEvent : BaseEvent
+ {
+ #region Constructors
+ ///
+ /// Initializes the object with default values.
+ ///
+ protected GenericEvent(IServerInternal server, NodeSource parent)
+ :
+ base(server, parent)
+ {
+ m_values = new Dictionary();
+ }
+
+ ///
+ /// Creates a new instance of the node without any parent.
+ ///
+ public static GenericEvent Construct(IServerInternal server, NodeId typeDefinitionId)
+ {
+ GenericEvent instance = new GenericEvent(server, (NodeSource)null);
+ instance.Initialize(null, null, null, 0, typeDefinitionId);
+ return instance;
+ }
+ #endregion
+
+ #region ICloneable Members
+ ///
+ public override NodeSource Clone(NodeSource parent)
+ {
+ lock (DataLock)
+ {
+ GenericEvent clone = new GenericEvent(Server, parent);
+ clone.Initialize(this);
+ return clone;
+ }
+ }
+ #endregion
+
+ #region Public Methods
+ ///
+ /// Sets the value of a property for an event.
+ ///
+ public void SetProperty(QualifiedName browseName, object value)
+ {
+ m_values[browseName] = value;
+ }
+ #endregion
+
+ #region Overridden Methods
+ ///
+ public override object GetAttributeValue(
+ FilterContext context,
+ NodeId typeDefinitionId,
+ IList relativePath,
+ uint attributeId,
+ NumericRange indexRange)
+ {
+ if (context == null) throw new ArgumentNullException("context");
+
+ // check type definition.
+ if (!Server.TypeTree.IsTypeOf(this.TypeDefinitionId, typeDefinitionId))
+ {
+ return null;
+ }
+
+ // lookup extended properties.
+ if (relativePath == null || relativePath.Count == 1)
+ {
+ object value = null;
+
+ if (m_values.TryGetValue(relativePath[0], out value))
+ {
+ return value;
+ }
+ }
+
+ // read the attribute value.
+ DataValue dataValue = ReadAttributeValue(
+ context,
+ typeDefinitionId,
+ relativePath,
+ attributeId,
+ indexRange);
+
+ if (StatusCode.IsBad(dataValue.StatusCode))
+ {
+ return dataValue.StatusCode;
+ }
+
+ // return the value.
+ return dataValue.Value;
+ }
+ #endregion
+
+ #region Private Fields
+ private Dictionary m_values;
+ #endregion
+ }
+ #endregion
+#endif
+}
diff --git a/SampleApplications/SDK/Server/AddressSpace/DataTypeDictionary.cs b/SampleApplications/SDK/Server/AddressSpace/DataTypeDictionary.cs
new file mode 100644
index 0000000000..f50ce89969
--- /dev/null
+++ b/SampleApplications/SDK/Server/AddressSpace/DataTypeDictionary.cs
@@ -0,0 +1,314 @@
+/* ========================================================================
+ * Copyright (c) 2005-2013 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.Generic;
+using System.Text;
+using System.Xml;
+using System.Runtime.Serialization;
+using System.Reflection;
+using System.IO;
+
+namespace Opc.Ua.Server
+{
+#if LEGACY_CORENODEMANAGER
+ ///
+ /// A variable that contains live automation data.
+ ///
+ [Obsolete("The DataTypeDictionary class is obsolete and is not supported. See Opc.Ua.DataTypeDictionaryState for a replacement.")]
+ public partial class DataTypeDictionary
+ {
+ #region Public Methods
+ ///
+ /// Sets an embedded resource.
+ ///
+ public void SetDictionarySource(Assembly assembly, string resourcePath, string namespaceUri)
+ {
+ SpecifyDataTypeVersion(Property.Construct(Server));
+ SpecifyNamespaceUri(Property.Construct(Server));
+
+ lock (DataLock)
+ {
+ m_assembly = assembly;
+ m_filePath = resourcePath;
+ MinimumSamplingInterval = MinimumSamplingIntervals.Continuous;
+ UpdateValue(null, StatusCodes.BadWaitingForInitialData);
+
+ DataTypeVersion.Value = Utils.Format("{0}", m_assembly.GetName().Version);
+ NamespaceUri.Value = namespaceUri;
+ }
+ }
+
+ ///
+ /// Sets a file as the dictionary source and specifies a minimum interval between scans.
+ ///
+ public void SetDictionarySource(string fileName, string searchPath, int minimumScanRate)
+ {
+ lock (DataLock)
+ {
+ // construct the filepath.
+ FileInfo fileInfo = new FileInfo(fileName);
+
+ if (!fileInfo.Exists)
+ {
+ if (String.IsNullOrEmpty(searchPath))
+ {
+ searchPath = GetDefaultHttpPath();
+ }
+
+ if (!String.IsNullOrEmpty(searchPath))
+ {
+ if (searchPath.StartsWith(Uri.UriSchemeHttp))
+ {
+ if (!searchPath.EndsWith("/"))
+ {
+ searchPath += "/";
+ }
+
+ fileName = String.Format("{0}{1}", searchPath, fileName);
+ }
+ else
+ {
+ if (!searchPath.EndsWith("\\"))
+ {
+ searchPath += "\\";
+ }
+
+ fileName = String.Format("{0}{1}", searchPath, fileName);
+ }
+ }
+ }
+
+ m_filePath = fileName;
+ MinimumSamplingInterval = minimumScanRate;
+ UpdateValue(null, StatusCodes.BadWaitingForInitialData);
+ }
+ }
+ #endregion
+
+ #region I/O Support Functions
+ ///
+ /// Returns the data type path for the DataTypeDescription.
+ ///
+ protected virtual string GetDataTypePath(string typeName)
+ {
+ string path = typeName;
+
+ if (m_typeSystemId == Objects.XmlSchema_TypeSystem)
+ {
+ path = String.Format("//xs:element[@name='{0}']", typeName);
+ }
+
+ return path;
+ }
+
+ ///
+ /// Returns the data dictionary from cache or disk (updates the data type version as well).
+ ///
+ protected virtual byte[] ReadDictionary(double maxAge)
+ {
+ byte[] dictionary = Value;
+
+ // return cached value.
+ if (dictionary != null)
+ {
+ if (Timestamp.AddMilliseconds(MinimumSamplingInterval) > DateTime.UtcNow)
+ {
+ return dictionary;
+ }
+
+ if (Timestamp.AddMilliseconds(maxAge) > DateTime.UtcNow)
+ {
+ return dictionary;
+ }
+
+ if (m_assembly != null)
+ {
+ return dictionary;
+ }
+ }
+
+ // read from source.
+ try
+ {
+ if (m_assembly != null)
+ {
+ dictionary = ReadDictionaryFromResource(m_filePath);
+ }
+ else if (m_filePath.StartsWith(Uri.UriSchemeHttp))
+ {
+ dictionary = ReadDictionaryFromHttpFile(m_filePath);
+ }
+ else
+ {
+ dictionary = ReadDictionaryFromDiskFile(m_filePath);
+ }
+
+ return dictionary;
+ }
+ catch (Exception e)
+ {
+ ServiceResult error = ServiceResult.Create(e, StatusCodes.BadOutOfService, "Could not access data dictionary file: {0}.", m_filePath);
+ UpdateStatus(error);
+ return null;
+ }
+ }
+
+ ///
+ /// Returns the default HTTP path to use from the hosting process.
+ ///
+ protected virtual string GetDefaultHttpPath()
+ {
+ foreach (Uri endpointAddress in Server.EndpointAddresses)
+ {
+ if (!endpointAddress.Scheme.StartsWith(Uri.UriSchemeHttp))
+ {
+ continue;
+ }
+
+ string url = endpointAddress.ToString();
+
+ int index = url.LastIndexOf('/');
+
+ if (index != -1)
+ {
+ url = url.Substring(0, index+1);
+ }
+
+ return url;
+ }
+
+ return null;
+ }
+
+ ///
+ /// Loads a file from a HTTP URL.
+ ///
+ protected virtual byte[] ReadDictionaryFromHttpFile(string url)
+ {
+ System.Net.WebRequest request = System.Net.WebRequest.Create(url);
+ System.Net.WebResponse response = request.GetResponse();
+ Stream istrm = response.GetResponseStream();
+
+ byte[] dictionary = ReadDictionary(istrm);
+
+ // use the current time as the dictionary version.
+ m_dataTypeVersion.Value = XmlConvert.ToString(DateTime.UtcNow, XmlDateTimeSerializationMode.Utc);
+
+ return dictionary;
+ }
+
+ ///
+ /// Reads the dictionary from a disk file.
+ ///
+ protected virtual byte[] ReadDictionaryFromDiskFile(string filePath)
+ {
+ Stream istrm = File.Open(filePath, FileMode.Open);
+
+ byte[] dictionary = ReadDictionary(istrm);
+
+ // use the file modification time as the dictionary version.
+ m_dataTypeVersion.Value = XmlConvert.ToString(new FileInfo(filePath).LastWriteTimeUtc, XmlDateTimeSerializationMode.Utc);
+
+ return dictionary;
+ }
+
+ ///
+ /// Reads the dictionary from an embedded resource.
+ ///
+ protected virtual byte[] ReadDictionaryFromResource(string filePath)
+ {
+ Stream istrm = m_assembly.GetManifestResourceStream(filePath);
+
+ byte[] dictionary = ReadDictionary(istrm);
+
+ // use the assembly version as the version.
+ DataTypeVersion.Value = Utils.Format("{0}", m_assembly.GetName().Version);
+
+ return dictionary;
+ }
+
+ ///
+ /// Reads the dictionary from the stream.
+ ///
+ protected virtual byte[] ReadDictionary(Stream istrm)
+ {
+ BinaryReader reader = new BinaryReader(istrm);
+ MemoryStream ostrm = new MemoryStream();
+
+ try
+ {
+ byte[] buffer = new byte[4096];
+
+ while (true)
+ {
+ int bytesRead = reader.Read(buffer, 0, buffer.Length);
+
+ if (bytesRead <= 0)
+ {
+ break;
+ }
+
+ ostrm.Write(buffer, 0, bytesRead);
+ }
+
+ ostrm.Close();
+ return ostrm.ToArray();
+ }
+ finally
+ {
+ reader.Close();
+ }
+ }
+ #endregion
+
+ #region Overridden Methods
+ ///
+ /// Looks up the type system id.
+ ///
+ protected override void OnAfterCreate(object configuration)
+ {
+ base.OnAfterCreate(configuration);
+
+ m_typeSystemId = NodeManager.FindTargetId(
+ this.NodeId,
+ ReferenceTypeIds.Organizes,
+ true,
+ null);
+ }
+ #endregion
+
+ #region Private Fields
+ private NodeId m_typeSystemId;
+ private Assembly m_assembly;
+ private string m_filePath;
+ #endregion
+ }
+#endif
+}
diff --git a/SampleApplications/SDK/Server/AddressSpace/MethodSource.cs b/SampleApplications/SDK/Server/AddressSpace/MethodSource.cs
new file mode 100644
index 0000000000..2a87633be1
--- /dev/null
+++ b/SampleApplications/SDK/Server/AddressSpace/MethodSource.cs
@@ -0,0 +1,685 @@
+/* ========================================================================
+ * Copyright (c) 2005-2013 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.Text;
+using System.Xml;
+using System.IO;
+using System.Runtime.Serialization;
+using System.Reflection;
+using System.Threading;
+
+#pragma warning disable 0618
+
+namespace Opc.Ua.Server
+{
+#if LEGACY_CORENODEMANAGER
+ ///
+ /// The state of a state machine.
+ ///
+ [Obsolete("The MethodSource class is obsolete and is not supported. See Opc.Ua.MethodState for a replacement.")]
+ public class MethodSource : BaseInstanceSource, ICallable, IMethod
+ {
+ #region Constructors
+ ///
+ /// Initializes the object with default values.
+ ///
+ public MethodSource(IServerInternal server, NodeSource parent) : base(server, parent)
+ {
+ m_arguments = new MethodArguments();
+ m_callbacks = new Dictionary();
+ m_executable = m_userExecutable = true;
+ }
+
+ ///
+ /// Creates a new instance of the node.
+ ///
+ public static MethodSource Construct(
+ IServerInternal server,
+ NodeSource parent,
+ NodeId referenceTypeId,
+ NodeId nodeId,
+ QualifiedName browseName,
+ uint numericId)
+ {
+ MethodSource instance = new MethodSource(server, parent);
+ instance.Initialize(referenceTypeId, nodeId, browseName, numericId, null);
+ return instance;
+ }
+
+ ///
+ /// Initializes the object with default values.
+ ///
+ public MethodSource(IServerInternal server, MethodArguments arguments) : base(server, null)
+ {
+ if (arguments == null) throw new ArgumentNullException("arguments");
+
+ m_arguments = arguments;
+ m_callbacks = new Dictionary();
+ m_executable = m_userExecutable = true;
+ }
+ #endregion
+
+ #region ICloneable Members
+ ///
+ public override NodeSource Clone(NodeSource parent)
+ {
+ lock (DataLock)
+ {
+ MethodSource clone = new MethodSource(Server, parent);
+ clone.Initialize(this);
+ return clone;
+ }
+ }
+ #endregion
+
+ #region INode Members
+ ///
+ public override NodeClass NodeClass
+ {
+ get
+ {
+ return NodeClass.Method;
+ }
+ }
+ #endregion
+
+ #region ILocalNode Members
+ ///
+ public override bool SupportsAttribute(uint attributeId)
+ {
+ lock (DataLock)
+ {
+ switch (attributeId)
+ {
+ case Attributes.Executable:
+ case Attributes.UserExecutable:
+ {
+ return true;
+ }
+
+ default:
+ {
+ return base.SupportsAttribute(attributeId);
+ }
+ }
+ }
+ }
+ #endregion
+
+ #region IMethod Members
+ ///
+ public bool Executable
+ {
+ get
+ {
+ lock (DataLock)
+ {
+ return m_executable;
+ }
+ }
+
+ set
+ {
+ lock (DataLock)
+ {
+ m_executable = value;
+ }
+ }
+ }
+
+ ///
+ public bool UserExecutable
+ {
+ get
+ {
+ lock (DataLock)
+ {
+ return m_userExecutable;
+ }
+ }
+
+ set
+ {
+ lock (DataLock)
+ {
+ m_userExecutable = value;
+ }
+ }
+ }
+ #endregion
+
+ #region ICallable Members
+ ///
+ public virtual ServiceResult Call(
+ OperationContext context,
+ NodeId methodId,
+ object methodHandle,
+ NodeId objectId,
+ IList