Skip to content

File LabelControl.xaml.cs

File List > PGRControls > LabelControl.xaml.cs

Go to the documentation of this file

//=============================================================================
// Copyright (c) 2026 FLIR Integrated Imaging Solutions, Inc. All Rights Reserved.
//
// This software is the confidential and proprietary information of FLIR
// Integrated Imaging Solutions, Inc. ("Confidential Information"). You
// shall not disclose such Confidential Information and shall use it only in
// accordance with the terms of the license agreement you entered into
// with FLIR Integrated Imaging Solutions, Inc. (FLIR).
//
// FLIR MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
// SOFTWARE, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE, OR NON-INFRINGEMENT. FLIR SHALL NOT BE LIABLE FOR ANY DAMAGES
// SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
// THIS SOFTWARE OR ITS DERIVATIVES.
//=============================================================================

using System;
using SpinnakerNET.GenApi;
using System.Windows;
using System.Windows.Threading;
using System.ComponentModel;
using System.Runtime.ExceptionServices;
using System.Security;
using System.Threading;

namespace SpinnakerNET.GUI
{
    namespace WPFControls
    {


        public sealed partial class LabelControl : BaseClass
        {
#region FIELDS
            private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(LabelControl));
            private bool _disposed = false;
            private IValue _node;
            private string _unit = "";
            private IFloat _floatNode;
            private IInteger _integerNode;
            private IEnum _enumNode;
            private IString _stringNode;
            private string _contentLabel;

            public delegate void ControlUpdated(INode node);
            public event ControlUpdated OnControlUpdated;

            // GenICam callback update thread
            BackgroundWorker _updateWorker;

            DateTime lastPollTime;

            private bool _forceUpdateEvenIfNotVisible = false;
#endregion

#region PROPERTIES
            public string ContentLabel
            {
                get
                {
                    return _contentLabel;
                }
                set
                {
                    _contentLabel = value;
                    NotifyPropertyChanged("ContentLabel");
                }
            }

            public System.Windows.Visibility ContentVisibility
            {
                get
                {
                    return this.content.Visibility;
                }
                set
                {
                    this.content.Visibility = value;
                }
            }

            public bool ForceUpdateEvenIfNotVisible
            {
                get
                {
                    return _forceUpdateEvenIfNotVisible;
                }
                set
                {
                    _forceUpdateEvenIfNotVisible = value;
                }
            }
#endregion

#region Constructor
            public LabelControl()
            {
                InitializeComponent();
                _timer = new System.Windows.Forms.Timer();
                ContentLabel = "";
                _updateWorker = new BackgroundWorker();
                _updateWorker.DoWork += _updateWorker_DoWork;
                _updateWorker.RunWorkerCompleted += _updateWorker_RunWorkerCompleted;
                lastPollTime = DateTime.Now;
            }

            internal LabelControl(LabelControl originalControl)
            {
                InitializeComponent();
                _timer = new System.Windows.Forms.Timer();
                ContentLabel = "";
                _updateWorker = new BackgroundWorker();
                _updateWorker.DoWork += _updateWorker_DoWork;
                _updateWorker.RunWorkerCompleted += _updateWorker_RunWorkerCompleted;

                // Common Properties
                this.SetMapper(originalControl.GetMapper());
                this.Connect(
                    originalControl.NodeMap, originalControl.GetNodeToControl(), originalControl.GetControlNameLabel());
                this.SetNameLabelBoldness(originalControl.NameLabelBoldness);
                this.SetVisibility(originalControl.GetVisibility());
                this.SetControlID(originalControl.GetControlID());
                this.SetMin(originalControl.GetMin());
                this.SetMax(originalControl.GetMax());
                this.SetControlNameLabel(originalControl.ControlNameLabel);
                this.SetNameLabelVisibility(originalControl.NameLabelVisibility);
                this.SetNameLabelBoldness(originalControl.GetNameLabelBoldness());
                try
                {
                    this.SetToolTip(originalControl.GetToolTip());
                }
                catch (System.Exception /*ex*/)
                {
                }
                this.SetMaximumControlSize(originalControl.GetMaximumControlSize());
                this.SetMinimumControlSize(originalControl.GetMinimumControlSize());
                this.SetControlHeight(originalControl.GetControlHeight());
                this.SetControlWidth(originalControl.GetControlWidth());
                this.SetRefreshTime(originalControl.GetRefreshTime());
                this.SetMargin(originalControl.GetMargin());
                this.ContentVisibility = originalControl.ContentVisibility;
            }

            protected override void Dispose(bool disposing)
            {
                if (!_disposed)
                {
                    if (disposing)
                    {
                    }

                    // Consider GenICam callbacks as unmanaged resource
                    Disconnect();
                    _disposed = true;
                }
                // Call Dispose in the base class.
                base.Dispose(disposing);
            }
#endregion

#region ICAMERACONTROL_IMPLEMENTATION
            public override void SetRefreshTime(int seconds)
            {
                this._refreshTime = seconds;

                // Start timer if an valid refresh time was provided
                if (this._refreshTime > 0)
                {
                    try
                    {
                        _timer = new System.Windows.Forms.Timer();
                        _timer.Interval = this._refreshTime;
                        _timer.Tick += new EventHandler(timer_Tick);
                        _timer.Start();
                    }
                    catch (System.Exception /*ex*/)
                    {
                    }
                }
            }

            public override void Connect(INodeMap nodemap, string nodename, string namelabel = "")
            {
                if (nodemap != null && nodename != null && nodename.Length > 0)
                {
                    // Acquire device serial number
                    if (string.IsNullOrWhiteSpace(_serialNumber))
                    {
                        _serialNumber = RetrieveSerialNumber(nodemap);
                    }

                    // Acquire device model name
                    if (string.IsNullOrWhiteSpace(_deviceModelName))
                    {
                        _deviceModelName = RetrieveModelName(nodemap);
                    }

                    try
                    {
                        // Get Name Label from GenICam Node
                        this._node = nodemap.GetNode<IValue>(nodename);

                        if (_node == null)
                        {
                            _featureAvailable = false;
                            throw new Exception($"Feature {nodename} not found");
                        }

                        this._nodeMap = nodemap;
                        this._propertyToControl = nodename;
                    }
                    catch (Exception ex)
                    {
                        log.Debug(string.Format("{0}Problem accessing {1}.", FormattedSerialNumber, nodename), ex);
                    }

                    if (_node != null)
                    {
                        try
                        {
                            _initializing = true;
                            this._nodeType = _node.GetType();
                            RegisterGeniCamCallback(nodemap, nodename, _node);
                            UpdateLabelDisplay(nodemap, nodename, _node);
                            SetToolTip(_node.ToolTip.ToString());
                            // RegisterInterfaceEvents();
                            _featureAvailable = _node.IsImplemented;
                        }
                        catch (System.Exception ex)
                        {
                            log.Debug(
                                string.Format(
                                    "{1}Problem accessing {0} node.", this._propertyToControl, FormattedSerialNumber),
                                ex);
                            throw new Exception(string.Format("Problem accessing {0} node", this._propertyToControl));
                        }
                        finally
                        {
                            _initializing = false;
                        }
                    }
                    else
                    {
                        _featureAvailable = false;
                    }
                }
                else
                {
                    // Standard label control with user specified text
                    this.ControlNameLabel = namelabel;
                    SetControlNameLabel(this._controlNameLabel);
                    this.content.Visibility = System.Windows.Visibility.Collapsed;
                    _featureAvailable = true;
                }
            }

            public override void Disconnect()
            {
                try
                {
                    UnregisterGeniCamCallback(NodeMap, PropertyToControl, _node);

                    _node = null;
                    _floatNode = null;
                    _integerNode = null;
                    _boolNode = null;

                    _mapper = null;
                    _nodeMap = null;

                    base.Disconnect();
                }
                catch (System.Exception /*ex*/)
                {
                }
            }

            private void UnregisterGeniCamCallback(INodeMap nodemap, string nodename, IValue node)
            {
                if (nodemap == null || node == null)
                {
                    return;
                }

                Type type = node.GetType();
                if (type == typeof (Float) && _floatNode != null && _callbackRegistered)
                {
                    _floatNode.Updated -= LabelControlNode_Updated;
                }
                else if (type == typeof (Integer) && _integerNode != null && _callbackRegistered)
                {
                    _integerNode.Updated -= LabelControlNode_Updated;
                }
                else if (type == typeof (BoolNode) && _boolNode != null && _callbackRegistered)
                {
                    _boolNode.Updated -= LabelControlNode_Updated;
                }
                else if (type == typeof (Enumeration) && _enumNode != null && _callbackRegistered)
                {
                    _enumNode.Updated -= LabelControlNode_Updated;
                }
                else if (type == typeof (StringNode) && _stringNode != null && _callbackRegistered)
                {
                    _stringNode.Updated -= LabelControlNode_Updated;
                }
                else
                {
                }
            }

            private void RegisterGeniCamCallback(INodeMap nodemap, string nodename, IValue node)
            {
                Type type = node.GetType();
                if (type == typeof (Float))
                {
                    _floatNode = nodemap.GetNode<IFloat>(nodename);
                    _floatNode.Updated += LabelControlNode_Updated;
                }
                else if (type == typeof (Integer) || type == typeof (IntReg))
                {
                    _integerNode = nodemap.GetNode<IInteger>(nodename);

                    _integerNode.Updated += LabelControlNode_Updated;
                }
                else if (type == typeof (BoolNode))
                {
                    _boolNode = nodemap.GetNode<IBool>(nodename);
                    _boolNode.Updated += LabelControlNode_Updated;
                }
                else if (type == typeof (Enumeration))
                {
                    _enumNode = nodemap.GetNode<Enumeration>(nodename);
                    _enumNode.Updated += LabelControlNode_Updated;
                }
                else if (type == typeof (StringNode))
                {
                    _stringNode = nodemap.GetNode<StringNode>(nodename);
                    _stringNode.Updated += LabelControlNode_Updated;
                }
                else
                {
                }

                _callbackRegistered = true;
            }

            internal override CameraControlCollection GetDependencyControls()
            {
                return null;
            }
#endregion

#region EVENT_HANDLER
            void timer_Tick(object sender, EventArgs e)
            {
                Refresh();
            }

            [HandleProcessCorruptedStateExceptions]
            [SecurityCritical]
            private void
            _updateWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
            {
                bool refreshRequired = false;

                if (e.Cancelled)
                {
                    return;
                }

                if (_nodeMap == null)
                {
                    // Nodemap is no longer valid. Control must have been disconnected.
                    return;
                }

                // Go through each item to see if update is necessary
                try
                {
                    _isUpdating = true;
                    _initializing = true;

                    INode node = e.Result as INode;
                    NodeStatus currentNodeStatus = new NodeStatus(node, _mapper);
                    if (currentNodeStatus.ExceptionObject != null)
                    {
                        return;
                    }

                    string logMessage =
                        string.Format("Spinnaker Callback: Feature=\"{0}\"", currentNodeStatus.NodeName);

                    if (currentNodeStatus.IsReadable)
                    {
                        logMessage += string.Format(", Value=\"{0}\"", currentNodeStatus.CurrentValue);
                    }

                    LogNodeCallback(log, currentNodeStatus.NodeName, logMessage);

                    if (ControlNameLabel != currentNodeStatus.NodeDisplayName)
                    {
                        SetControlNameLabel(currentNodeStatus.NodeDisplayName);
                    }

                    if (this._unit != currentNodeStatus.Unit)
                    {
                        _unit = currentNodeStatus.Unit;
                    }

                    if (currentNodeStatus.IsReadable && ContentLabel != currentNodeStatus.CurrentStringValue)
                    {
                        UpdateLabelDisplay(_nodeMap, _propertyToControl, _node);
                        refreshRequired = true;
                    }

                    if (OnControlUpdated != null)
                    {
                        OnControlUpdated(currentNodeStatus.CurrentNode);
                    }
                }
                catch (System.Exception ex)
                {
                    log.Debug(
                        string.Format(
                            "{1}Problem updating control for {0} node", _propertyToControl, FormattedSerialNumber),
                        ex);
                }
                finally
                {
                    _initializing = false;
                    _isUpdating = false;
                }

                if (!refreshRequired)
                {
                    return;
                }

                if (!Dispatcher.CheckAccess())
                {
                    Dispatcher.BeginInvoke((Action)(() => { Refresh(); }), DispatcherPriority.Background, null);
                }
                else
                {
                    Refresh();
                }
            }

            private void _updateWorker_DoWork(object sender, DoWorkEventArgs e)
            {
                // Limit the refresh rate
                Thread.Sleep(1000 / _maxRefreshRateHz);

                INode node = e.Argument as INode;
                e.Result = node;
            }

            void LabelControlNode_Updated(INode node)
            {
                // Sanity check
                if (_nodeMap == null)
                {
                    return;
                }

                if (_updateWorker.IsBusy || _isUpdating)
                {
                    return;
                }

                // Update control if it is part of the footer, where visibility appears as false
                if (!_forceUpdateEvenIfNotVisible && !IsVisible)
                {
                    return;
                }

                _updateWorker.RunWorkerAsync(node);
            }
#endregion

#region UI_UPDATE
            private void UpdateLabelDisplay(INodeMap nodemap, string nodename, IValue node)
            {
                if (nodemap == null || nodename.Length == 0)
                {
                    return;
                }

                Type type = node.GetType();
                if (type == typeof (Float))
                {
                    if (_floatNode == null)
                    {
                        _floatNode = nodemap.GetNode<IFloat>(nodename);
                    }

                    SetControlNameLabel(_floatNode.DisplayName);
                    this._unit = _floatNode.Unit;

                    if (!_floatNode.IsReadable)
                    {
                        return;
                    }

                    string temp = "";

                    if (_mapper != null)
                    {
                        temp = _mapper.FormatNodeValueToString(_propertyToControl, "", DecimalPlaces);
                    }
                    else
                    {
                        temp = NumericFormatter.FormatNumericToString(_floatNode.Value, DecimalPlaces);
                    }

                    this.ContentLabel = temp + string.Format("{0}", _unit.Length > 0 ? " " + _unit : "");
                }
                else if (type == typeof (Integer) || type == typeof (IntReg))
                {
                    if (_integerNode == null)
                    {
                        _integerNode = nodemap.GetNode<IInteger>(nodename);
                    }

                    SetControlNameLabel(_integerNode.DisplayName);

                    if (!_integerNode.IsReadable)
                    {
                        return;
                    }

                    if (_mapper != null)
                    {
                        this.ContentLabel = _mapper.FormatNodeValueToString(_propertyToControl);
                    }
                    else
                    {
                        this.ContentLabel = _integerNode.Value.ToString();
                    }
                }
                else
                {
                    if (_node == null)
                    {
                        _node = _nodeMap.GetNode<IValue>(nodename);
                    }

                    SetControlNameLabel(_node.DisplayName);

                    if (!_node.IsReadable)
                    {
                        return;
                    }

                    if (_mapper != null)
                    {
                        this.ContentLabel = _mapper.FormatNodeValueToString(_propertyToControl);
                    }
                }
            }

            public void InvalidateNode()
            {
                TimeSpan duration = DateTime.Now - lastPollTime;

                if (_node != null)
                {
                    long pollTime = _node.PollingTime == -1 ? 2000 : _node.PollingTime;

                    if (duration.TotalMilliseconds > pollTime)
                    {

                        _node.Invalidate();

                        lastPollTime = DateTime.Now;
                    }
                }
            }

            public override void Refresh()
            {
                try
                {
                    _initializing = true;

                    UpdateLabelDisplay(_nodeMap, _propertyToControl, _node);
                }
                catch (System.Exception ex)
                {
                    log.Warn(
                        string.Format(
                            "{1}Problem retrieving new value from {0} node", _propertyToControl, FormattedSerialNumber),
                        ex);
                }
                finally
                {
                    _initializing = false;
                }
            }
#endregion

#region HELPER

#endregion
        }

    }
}