Files
UA-.NETStandard/SampleApplications/Samples/Client/ClientPage.xaml.cs
T
Karl Deiretsbacher dc880584de Update ClientPage.xaml.cs
Replaced the dual license with MIT to make it consistent with all other sample source files.
2020-01-22 09:53:03 +01:00

583 lines
20 KiB
C#

/* ========================================================================
* Copyright (c) 2005-2019 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;
using Opc.Ua.Client.Controls;
using Opc.Ua.Configuration;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Core;
using Windows.UI.Xaml.Media;
using Windows.UI.Text;
using Windows.UI;
using System.Threading;
namespace Opc.Ua.SampleClient
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public partial class ClientPage : Page
{
#region Private Fields
private Session m_session;
private ApplicationInstance m_application;
private Opc.Ua.Server.StandardServer m_server;
private ConfiguredEndpointCollection m_endpoints;
private ApplicationConfiguration m_configuration;
private ServiceMessageContext m_context;
private ClientPage m_masterPage;
private List<ClientPage> m_pages;
#endregion
public ClientPage()
{
InitializeComponent();
}
public ClientPage(
ServiceMessageContext context,
ApplicationInstance application,
ClientPage masterPage,
ApplicationConfiguration configuration)
{
InitializeComponent();
if (!configuration.SecurityConfiguration.AutoAcceptUntrustedCertificates)
{
configuration.CertificateValidator.CertificateValidation += new CertificateValidationEventHandler(CertificateValidator_CertificateValidation);
}
m_masterPage = masterPage;
m_context = context;
m_application = application;
m_server = application.Server as Opc.Ua.Server.StandardServer;
if (m_masterPage == null)
{
m_pages = new List<ClientPage>();
}
m_configuration = configuration;
SessionsCTRL.Configuration = configuration;
SessionsCTRL.MessageContext = context;
SessionsCTRL.AddressSpaceCtrl = BrowseCTRL;
SessionsCTRL.NodeSelected += SessionCtrl_NodeSelected;
// get list of cached endpoints.
m_endpoints = m_configuration.LoadCachedEndpoints(true);
m_endpoints.DiscoveryUrls = configuration.ClientConfiguration.WellKnownDiscoveryUrls;
// hook up endpoint selector
EndpointSelectorCTRL.Initialize(m_endpoints, m_configuration);
EndpointSelectorCTRL.ConnectEndpoint += EndpointSelectorCTRL_ConnectEndpoint;
EndpointSelectorCTRL.EndpointsChanged += EndpointSelectorCTRL_OnChange;
BrowseCTRL.SessionTreeCtrl = SessionsCTRL;
BrowseCTRL.NodeSelected += BrowseCTRL_NodeSelected;
// exception dialog
GuiUtils.ExceptionMessageDlg += ExceptionMessageDlg;
ServerUrlTB.Text = "None";
}
void RemoveAllClickEventsFromButton()
{
CommandBTN.Click -= ContextMenu_OnDelete;
CommandBTN.Click -= ContextMenu_OnCancel;
CommandBTN.Click -= ContextMenu_OnDisconnect;
CommandBTN.Click -= ContextMenu_OnReport;
}
private void SessionCtrl_NodeSelected(object sender, TreeNodeActionEventArgs e)
{
if (e.Node != null)
{
MonitoredItem item = e.Node as MonitoredItem;
if (e.Node is MonitoredItem)
{
CommandBTN.Visibility = Visibility.Visible;
CommandBTN.Content = "Delete";
RemoveAllClickEventsFromButton();
CommandBTN.Click += ContextMenu_OnDelete;
CommandBTN.Tag = e.Node;
}
else if (e.Node is Subscription)
{
CommandBTN.Visibility = Visibility.Visible;
CommandBTN.Content = "Cancel";
RemoveAllClickEventsFromButton();
CommandBTN.Click += ContextMenu_OnCancel;
CommandBTN.Tag = e.Node;
}
else if (e.Node is Session)
{
CommandBTN.Visibility = Visibility.Visible;
CommandBTN.Content = "Disconnect";
RemoveAllClickEventsFromButton();
CommandBTN.Click += ContextMenu_OnDisconnect;
CommandBTN.Tag = e.Node;
// Update current session object
m_session = (Session)e.Node;
}
else
{
RemoveAllClickEventsFromButton();
CommandBTN.Visibility = Visibility.Collapsed;
CommandBTN.Tag = null;
}
}
}
private void BrowseCTRL_NodeSelected(object sender, TreeNodeActionEventArgs e)
{
if (e.Node != null)
{
ReferenceDescription reference = e.Node as ReferenceDescription;
if (reference != null && reference.NodeClass == NodeClass.Variable)
{
CommandBTN.Visibility = Visibility.Visible;
CommandBTN.Content = "Report";
RemoveAllClickEventsFromButton();
CommandBTN.Click += ContextMenu_OnReport;
CommandBTN.Tag = e.Node;
}
else
{
RemoveAllClickEventsFromButton();
CommandBTN.Visibility = Visibility.Collapsed;
CommandBTN.Tag = null;
}
}
}
private void ContextMenu_OnDisconnect(object sender, RoutedEventArgs e)
{
try
{
SessionsCTRL.Delete(CommandBTN.Tag as Session);
}
catch (Exception exception)
{
GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
}
}
private void ContextMenu_OnCancel(object sender, RoutedEventArgs e)
{
try
{
SessionsCTRL.Delete(CommandBTN.Tag as Subscription);
}
catch (Exception exception)
{
GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
}
}
private void ContextMenu_OnDelete(object sender, RoutedEventArgs e)
{
try
{
var monitoredItem = CommandBTN.Tag as MonitoredItem;
if (monitoredItem == null)
return;
var subscription = monitoredItem.Subscription;
SessionsCTRL.Delete(monitoredItem);
if (subscription.MonitoredItemCount == 0)
{
// Remove subscription if no more items
CommandBTN.Tag = subscription;
ContextMenu_OnCancel(sender, e);
}
}
catch (Exception exception)
{
GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
}
}
private void ContextMenu_OnReport(object sender, RoutedEventArgs e)
{
try
{
// can only subscribe to local variables.
ReferenceDescription reference = CommandBTN.Tag as ReferenceDescription;
if (m_session != null && reference != null)
{
CreateMonitoredItem(
m_session, null, (NodeId)reference.NodeId, MonitoringMode.Reporting);
}
}
catch (Exception exception)
{
GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
}
}
void CertificateValidator_CertificateValidation(CertificateValidator validator, CertificateValidationEventArgs e)
{
ManualResetEvent ev = new ManualResetEvent(false);
Dispatcher.RunAsync(
CoreDispatcherPriority.Normal,
async () =>
{
await GuiUtils.HandleCertificateValidationError(this, validator, e);
ev.Set();
}
).AsTask().Wait();
ev.WaitOne();
}
public void OpenPage()
{
if (m_masterPage == null)
{
ClientPage page = new ClientPage(m_context, m_application, this, m_configuration);
m_pages.Add(page);
page.Unloaded += Window_PageClosing;
}
else
{
m_masterPage.OpenPage();
}
}
async void Window_PageClosing(object sender, RoutedEventArgs e)
{
if (m_masterPage == null && m_pages.Count > 0)
{
MessageDlg dialog = new MessageDlg("Close all sessions?", MessageDlgButton.Yes, MessageDlgButton.No);
MessageDlgButton result = await dialog.ShowAsync();
if (result != MessageDlgButton.Yes)
{
return;
}
}
BrowseCTRL.Clear();
for (int ii = 0; ii < m_pages.Count; ii++)
{
if (Object.ReferenceEquals(m_pages[ii], sender))
{
m_pages.RemoveAt(ii);
break;
}
}
}
/// <summary>
/// Provides a user defined method.
/// </summary>
protected virtual async void DoTest(Session session)
{
MessageDlg dialog = new MessageDlg("A handy place to put test code.");
await dialog.ShowAsync();
}
async Task EndpointSelectorCTRL_ConnectEndpoint(object sender, ConnectEndpointEventArgs e)
{
try
{
// disable Connect while connecting button
EndpointSelectorCTRL.IsEnabled = false;
// Connect
e.UpdateControl = await Connect(e.Endpoint);
}
catch (Exception exception)
{
GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
e.UpdateControl = false;
}
finally
{
// enable Connect button
EndpointSelectorCTRL.IsEnabled = true;
}
}
private void EndpointSelectorCTRL_OnChange(object sender, EventArgs e)
{
try
{
m_endpoints.Save();
}
catch (Exception exception)
{
GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
}
}
/// <summary>
/// Connects to a server.
/// </summary>
public async Task<bool> Connect(ConfiguredEndpoint endpoint)
{
bool result = false;
if (endpoint == null)
{
return false;
}
// connect dialogs
Session session = await SessionsCTRL.Connect(endpoint);
if (session != null)
{
//hook up new session
session.KeepAlive += new KeepAliveEventHandler(StandardClient_KeepAlive);
StandardClient_KeepAlive(session, null);
// BrowseCTRL.SetView(session, BrowseViewType.Objects, null);
result = true;
}
return result;
}
/// <summary>
/// Updates the status control when a keep alive event occurs.
/// </summary>
async void StandardClient_KeepAlive(Session sender, KeepAliveEventArgs e)
{
if (!Dispatcher.HasThreadAccess)
{
await Dispatcher.RunAsync(
CoreDispatcherPriority.Normal,
() =>
{
StandardClient_KeepAlive( sender, e);
});
return;
}
if (sender != null && sender.Endpoint != null)
{
ServerUrlTB.Text = Utils.Format(
"{0} ({1}) {2}",
sender.Endpoint.EndpointUrl,
sender.Endpoint.SecurityMode,
(sender.EndpointConfiguration.UseBinaryEncoding) ? "UABinary" : "XML");
}
else
{
ServerUrlTB.Text = "None";
}
if (e != null && m_session != null)
{
SessionsCTRL.UpdateSessionNode(m_session);
if (ServiceResult.IsGood(e.Status))
{
ServerStatusTB.Text = Utils.Format(
"Server Status: {0} {1:yyyy-MM-dd HH:mm:ss} {2}/{3}",
e.CurrentState,
e.CurrentTime.ToLocalTime(),
m_session.OutstandingRequestCount,
m_session.DefunctRequestCount);
ServerStatusTB.Foreground = new SolidColorBrush(Colors.Black);
ServerStatusTB.FontWeight = FontWeights.Normal;
}
else
{
ServerStatusTB.Text = String.Format(
"{0} {1}/{2}", e.Status,
m_session.OutstandingRequestCount,
m_session.DefunctRequestCount);
ServerStatusTB.Foreground = new SolidColorBrush(Colors.Red);
ServerStatusTB.FontWeight = FontWeights.Bold;
}
}
}
async void ExceptionMessageDlg(string message)
{
await Dispatcher.RunAsync(
CoreDispatcherPriority.Normal,
async () =>
{
MessageDlg dialog = new MessageDlg(message);
await dialog.ShowAsync();
});
}
private void MainPage_PageClosing(object sender, RoutedEventArgs e)
{
try
{
SessionsCTRL.Close();
if (m_masterPage == null)
{
m_application.Stop();
}
}
catch (Exception exception)
{
GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
}
}
private void DiscoverServersMI_Click(object sender, EventArgs e)
{
try
{
ConfiguredEndpoint endpoint = new ConfiguredServerListDlg().ShowDialog(m_configuration, true);
if (endpoint != null)
{
EndpointSelectorCTRL.SelectedEndpoint = endpoint;
return;
}
}
catch (Exception exception)
{
GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
}
}
private void NewWindowMI_Click(object sender, EventArgs e)
{
try
{
this.OpenPage();
}
catch (Exception exception)
{
GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
}
}
private void Discovery_RegisterMI_Click(object sender, EventArgs e)
{
try
{
if (m_server != null)
{
OnRegister(null);
}
}
catch (Exception exception)
{
GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
}
}
private async void OnRegister(object sender)
{
try
{
Opc.Ua.Server.StandardServer server = m_server;
if (server != null)
{
await server.RegisterWithDiscoveryServer();
}
}
catch (Exception exception)
{
Utils.Trace(exception, "Could not register with the LDS");
}
}
public void CreateMonitoredItem(
Session session, Subscription subscription, NodeId nodeId, MonitoringMode mode)
{
if (subscription == null)
{
subscription = session.DefaultSubscription;
if (session.AddSubscription(subscription))
subscription.Create();
}
else
{
session.AddSubscription(subscription);
}
// add the new monitored item.
MonitoredItem monitoredItem = new MonitoredItem(subscription.DefaultItem);
monitoredItem.StartNodeId = nodeId;
monitoredItem.AttributeId = Attributes.Value;
monitoredItem.DisplayName = nodeId.Identifier.ToString();
monitoredItem.MonitoringMode = mode;
monitoredItem.SamplingInterval = mode == MonitoringMode.Sampling ? 1000 : 0;
monitoredItem.QueueSize = 0;
monitoredItem.DiscardOldest = true;
monitoredItem.Notification += new MonitoredItemNotificationEventHandler(MonitoredItem_Notification);
subscription.AddItem(monitoredItem);
subscription.ApplyChanges();
}
private async void MonitoredItem_Notification(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs e)
{
if (e.NotificationValue == null)
{
return;
}
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal,() =>
{
try
{
XmlEncoder encoder = new XmlEncoder(monitoredItem.Subscription.Session.MessageContext);
e.NotificationValue.Encode(encoder);
ServerStatusTB.Text = encoder.Close();
}
catch (Exception ex)
{
Utils.Trace(ex, "Error processing monitored item notification.");
}
});
}
private void Task_TestMI_Click(object sender, EventArgs e)
{
try
{
DoTest(m_session);
}
catch (Exception exception)
{
GuiUtils.HandleException(String.Empty, GuiUtils.CallerName(), exception);
}
}
}
}