3using System.Threading.Tasks;
4using System.Collections.Generic;
7using System.Xml.Schema;
10using System.Windows.Controls;
30 private readonly Dictionary<string, bool> nodes =
new Dictionary<string, bool>();
31 private readonly Dictionary<string, bool> failed =
new Dictionary<string, bool>();
32 private readonly
bool subscription;
36 this.request = Request;
42 if (!(this.request is
null))
44 this.Request_OnErrorsReceived(
this, Request.
Errors);
45 this.request.OnErrorsReceived += this.Request_OnErrorsReceived;
47 this.Request_OnFieldsReceived(
this, Request.
ReadFields);
48 this.request.OnFieldsReceived += this.Request_OnFieldsReceived;
50 this.Request_OnStateChanged(
this, Request.
State);
51 this.request.OnStateChanged += this.Request_OnStateChanged;
55 [Obsolete(
"Use DisposeAsync() instead.")]
60 this.DisposeAsync().Wait();
68 public async Task DisposeAsync()
70 if (!(this.request is
null))
75 this.request.OnStateChanged -= this.Request_OnStateChanged;
76 this.request.OnFieldsReceived -= this.Request_OnFieldsReceived;
77 this.request.OnErrorsReceived -= this.Request_OnErrorsReceived;
80 if (this.SensorDataListView.View is GridView GridView)
82 Registry.SetValue(
MainWindow.registryKey,
"SensorDataTimestampWidth", (
int)GridView.Columns[0].Width, RegistryValueKind.DWord);
83 Registry.SetValue(
MainWindow.registryKey,
"SensorDataFieldWidth", (
int)GridView.Columns[1].Width, RegistryValueKind.DWord);
84 Registry.SetValue(
MainWindow.registryKey,
"SensorDataValueWidth", (
int)GridView.Columns[2].Width, RegistryValueKind.DWord);
85 Registry.SetValue(
MainWindow.registryKey,
"SensorDataUnitWidth", (
int)GridView.Columns[3].Width, RegistryValueKind.DWord);
86 Registry.SetValue(
MainWindow.registryKey,
"SensorDataStatusWidth", (
int)GridView.Columns[4].Width, RegistryValueKind.DWord);
87 Registry.SetValue(
MainWindow.registryKey,
"SensorDataTypeWidth", (
int)GridView.Columns[5].Width, RegistryValueKind.DWord);
95 private void UserControl_SizeChanged(
object Sender, SizeChangedEventArgs e)
97 if (this.SensorDataListView.View is GridView GridView)
99 GridView.Columns[2].Width = Math.Max(this.ActualWidth - GridView.Columns[0].ActualWidth - GridView.Columns[1].ActualWidth -
100 GridView.Columns[3].ActualWidth - GridView.Columns[4].ActualWidth - GridView.Columns[5].ActualWidth -
101 SystemParameters.VerticalScrollBarWidth - 8, 10);
105 private Task Request_OnErrorsReceived(
object _, IEnumerable<ThingError> NewErrors)
107 MainWindow.UpdateGui(this.OnErrorsReceived, NewErrors);
108 return Task.CompletedTask;
111 private Task OnErrorsReceived(
object P)
113 IEnumerable<ThingError> NewErrors = (IEnumerable<ThingError>)P;
114 string LastKey =
null;
122 if (LastKey is
null || Key != LastKey)
125 this.failed[Key] =
true;
126 this.nodes[Key] =
true;
129 this.SensorDataListView.Items.Add(
new ErrorItem(Error));
132 this.NodesFailedLabel.Content = this.failed.Count.ToString();
133 this.NodesTotalLabel.Content = this.nodes.Count.ToString();
136 return Task.CompletedTask;
139 private Task Request_OnFieldsReceived(
object _, IEnumerable<Field> NewFields)
141 MainWindow.UpdateGui(this.OnFieldsReceived, NewFields);
142 return Task.CompletedTask;
145 private Task OnFieldsReceived(
object P)
147 IEnumerable<Field> NewFields = (IEnumerable<Field>)P;
148 string LastKey =
null;
156 if (LastKey is
null || Key != LastKey)
159 this.nodes[Key] =
true;
165 this.NodesTotalLabel.Content = this.nodes.Count.ToString();
166 this.FieldsLabel.Content = this.SensorDataListView.Items.Count.ToString();
169 return Task.CompletedTask;
174 MainWindow.UpdateGui(this.OnStateChanged, NewState);
175 return Task.CompletedTask;
178 private async Task OnStateChanged(
object P)
185 this.StateLabel.Content =
"Requested";
189 this.StateLabel.Content =
"Accepted";
193 this.StateLabel.Content =
"Started";
197 this.StateLabel.Content =
"Receiving";
201 this.StateLabel.Content =
"Done";
206 this.StateLabel.Content =
"Cancelled";
210 this.StateLabel.Content =
"Failure";
215 this.StateLabel.Content = NewState.ToString();
220 private async Task Done()
224 this.NodesTotalLabel.Content = this.nodes.Count;
225 this.NodesOkLabel.Content = this.nodes.Count - this.failed.Count;
230 List<FieldSubscriptionRule> Rules =
new List<FieldSubscriptionRule>();
249 this.request.OnStateChanged -= this.Request_OnStateChanged;
250 this.request.OnFieldsReceived -= this.Request_OnFieldsReceived;
251 this.request.OnErrorsReceived -= this.Request_OnErrorsReceived;
254 this.request = await this.node.SubscribeSensorDataMomentaryReadout(Rules.ToArray());
256 this.request.OnStateChanged += this.Request_OnStateChanged;
257 this.request.OnFieldsReceived += this.Request_OnFieldsReceived;
258 this.request.OnErrorsReceived += this.Request_OnErrorsReceived;
262 public void NewButton_Click(
object Sender, RoutedEventArgs e)
264 this.SensorDataListView.Items.Clear();
267 public void SaveButton_Click(
object Sender, RoutedEventArgs e)
269 this.SaveAsButton_Click(Sender, e);
272 public void SaveAsButton_Click(
object Sender, RoutedEventArgs e)
274 SaveFileDialog Dialog =
new SaveFileDialog()
277 CheckPathExists =
true,
278 CreatePrompt =
false,
280 Filter =
"XML Files (*.xml)|*.xml|HTML Files (*.html,*.htm)|*.html,*.htm|All Files (*.*)|*.*",
281 Title =
"Save Sensor data readout"
284 bool? Result = Dialog.ShowDialog(
MainWindow.FindWindow(
this));
286 if (Result.HasValue && Result.Value)
290 if (Dialog.FilterIndex == 2)
292 StringBuilder Xml =
new StringBuilder();
298 string Html =
XSL.
Transform(Xml.ToString(), sensorDataToHtml);
300 File.WriteAllText(Dialog.FileName, Html, System.Text.Encoding.UTF8);
304 using (FileStream f = File.Create(Dialog.FileName))
315 MessageBox.Show(
MainWindow.FindWindow(
this), ex.Message,
"Unable to save file.", MessageBoxButton.OK, MessageBoxImage.Error);
320 private static readonly XslCompiledTransform sensorDataToHtml =
XSL.
LoadTransform(
"Waher.Client.WPF.Transforms.SensorDataToHTML.xslt");
321 private static readonly XmlSchema schema1 =
XSL.
LoadSchema(
"Waher.Client.WPF.Schema.SensorData.xsd");
322 private static readonly XmlSchema schema2 =
XSL.
LoadSchema(
"Waher.Client.WPF.Schema.sensor-data.xsd");
323 private const string sensorDataNamespace =
"http://waher.se/Schema/SensorData.xsd";
324 private const string sensorDataRoot =
"SensorData";
326 private void SaveAsXml(XmlWriter w)
328 List<Field> Fields =
new List<Field>();
330 foreach (
FieldItem Item
in this.SensorDataListView.Items)
331 Fields.Add(Item.
Field);
333 w.WriteStartElement(sensorDataRoot, sensorDataNamespace);
334 w.WriteAttributeString(
"state", this.StateLabel.Content.ToString());
335 w.WriteAttributeString(
"nodesOk", this.NodesOkLabel.Content.ToString());
336 w.WriteAttributeString(
"nodesFailed", this.NodesFailedLabel.Content.ToString());
337 w.WriteAttributeString(
"nodesTotal", this.NodesTotalLabel.Content.ToString());
338 w.WriteAttributeString(
"fields", this.FieldsLabel.Content.ToString());
341 if (Fields.Count > 0)
348 public void OpenButton_Click(
object Sender, RoutedEventArgs e)
352 OpenFileDialog Dialog =
new OpenFileDialog()
355 CheckFileExists =
true,
356 CheckPathExists =
true,
358 Filter =
"XML Files (*.xml)|*.xml|All Files (*.*)|*.*",
361 Title =
"Open sensor data readout"
364 bool? Result = Dialog.ShowDialog(
MainWindow.FindWindow(
this));
366 if (Result.HasValue && Result.Value)
368 XmlDocument Xml =
new XmlDocument()
370 PreserveWhitespace =
true
372 Xml.Load(Dialog.FileName);
374 this.Load(Xml, Dialog.FileName);
380 MessageBox.Show(ex.Message,
"Unable to load file.", MessageBoxButton.OK, MessageBoxImage.Error);
384 public void Load(XmlDocument Xml,
string FileName)
388 XSL.
Validate(FileName, Xml, sensorDataRoot, sensorDataNamespace, schema1, schema2);
390 this.SensorDataListView.Items.Clear();
394 this.StateLabel.Content =
XML.
Attribute(Xml.DocumentElement,
"state",
string.Empty);
395 this.NodesOkLabel.Content =
XML.
Attribute(Xml.DocumentElement,
"nodesOk",
string.Empty);
396 this.NodesFailedLabel.Content =
XML.
Attribute(Xml.DocumentElement,
"nodesFailed",
string.Empty);
397 this.NodesTotalLabel.Content =
XML.
Attribute(Xml.DocumentElement,
"nodesTotal",
string.Empty);
398 this.FieldsLabel.Content =
XML.
Attribute(Xml.DocumentElement,
"fields",
string.Empty);
400 foreach (XmlNode N
in Xml.DocumentElement.ChildNodes)
411 if (!(Response.Item1 is
null))
420 if (!(Response.Item2 is
null))
424 string Key = Error.
Key;
425 this.failed[Key] =
true;
426 this.nodes[Key] =
true;
430 this.NodesFailedLabel.Content = this.failed.Count.ToString();
431 this.NodesTotalLabel.Content = this.nodes.Count.ToString();
438 private void UserControl_Loaded(
object Sender, RoutedEventArgs e)
440 if (this.SensorDataListView.View is GridView GridView)
444 Value = Registry.GetValue(
MainWindow.registryKey,
"SensorDataTimestampWidth", (
int)GridView.Columns[0].Width);
445 if (!(Value is
null) && Value is
int i && i > 0)
446 GridView.Columns[0].Width = i;
448 Value = Registry.GetValue(
MainWindow.registryKey,
"SensorDataFieldWidth", (
int)GridView.Columns[1].Width);
449 if (!(Value is
null) && Value is
int i2 && i2 > 0)
450 GridView.Columns[1].Width = i2;
452 Value = Registry.GetValue(
MainWindow.registryKey,
"SensorDataValueWidth", (
int)GridView.Columns[2].Width);
453 if (!(Value is
null) && Value is
int i3 && i3 > 0)
454 GridView.Columns[2].Width = i3;
456 Value = Registry.GetValue(
MainWindow.registryKey,
"SensorDataUnitWidth", (
int)GridView.Columns[3].Width);
457 if (!(Value is
null) && Value is
int i4 && i4 > 0)
458 GridView.Columns[3].Width = i4;
460 Value = Registry.GetValue(
MainWindow.registryKey,
"SensorDataStatusWidth", (
int)GridView.Columns[4].Width);
461 if (!(Value is
null) && Value is
int i5 && i5 > 0)
462 GridView.Columns[4].Width = i5;
464 Value = Registry.GetValue(
MainWindow.registryKey,
"SensorDataTypeWidth", (
int)GridView.Columns[5].Width);
465 if (!(Value is
null) && Value is
int i6 && i6 > 0)
466 GridView.Columns[5].Width = i6;
Represents one item in a sensor data readout.
Represents one item in a sensor data readout.
Field Field
Sensor data field.
Interaction logic for SensorDataView.xaml
void InitializeComponent()
InitializeComponent
Interaction logic for xaml
Abstract base class for tree nodes in the connection view.
virtual void ViewClosed()
Method called when the view has been closed.
Helps with common XML-related tasks.
static string Attribute(XmlElement E, string Name)
Gets the value of an XML attribute.
static XmlWriterSettings WriterSettings(bool Indent, bool OmitXmlDeclaration)
Gets an XML writer settings object.
Static class managing loading of XSL resources stored as embedded resources or in content files.
static XmlSchema LoadSchema(string ResourceName)
Loads an XML schema from an embedded resource.
static XslCompiledTransform LoadTransform(string ResourceName)
Loads an XSL transformation from an embedded resource.
static string Transform(string XML, XslCompiledTransform Transform)
Transforms an XML document using an XSL transform.
static void Validate(string ObjectID, XmlDocument Xml, params XmlSchema[] Schemas)
Validates an XML document given a set of XML schemas.
Static class managing the application event log. Applications and services log events on this static ...
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
static Exception UnnestException(Exception Exception)
Unnests an exception, to extract the relevant inner exception.
Maintains the status of a field subscription rule.
Implements an XMPP sensor client interface.
static SensorData ParseFields(XmlElement Content)
Parses sensor data field definitions.
Manages a sensor data client request.
Field[] ReadFields
Fields received during the readout.
ThingError[] Errors
Errors logged during the readout. If an error reference lacks a reference to a node (i....
SensorDataReadoutState State
Current state of readout.
string Id
Requesst identity.
Manages a sensor data server request.
static bool OutputFields(XmlWriter Xml, IEnumerable< Field > Fields, string Id, bool Done)
Outputs a set of fields to XML using the field format specified in the neuro-foundation....
Manages a sensor data client request.
Maintains the status of a subscription.
Represents a boolean value that can be either true or false.
Represents a date and optional time value.
Represents a duration value. Duration values adhere to the type specified by xsd:duration.
Base class for all sensor data fields.
ThingReference Thing
Reference to the thing to which the field belongs.
string Name
Unlocalized field name.
Represents a 32-bit integer value.
Represents a 64-bit integer value.
Represents a physical quantity value.
Represents a string value.
Represents a time value. Time values adhere to the type specified by xsd:time.
Contains information about an error on a thing
string Key
Key for thing reference: [NodeId[, SourceId[, Partition]]]
Interface for tab view user controls in the client.
SensorDataReadoutState
Sensor Data Readout States.