Skip to content

File ButtonControl.xaml.cs

File List > PGRControls > ButtonControl.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 System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Threading;
using SpinnakerNET.GenApi;
using System.ComponentModel;
using System.Runtime.ExceptionServices;
using System.Security;
using System.Threading;

namespace SpinnakerNET.GUI
{
    namespace WPFControls
    {


        public sealed partial class ButtonControl : BaseClass
        {
            private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(ButtonControl));
            private static readonly log4net.ILog analytics = log4net.LogManager.GetLogger("Analytics");
#region Properties
            // Basic Properties
            private SpinnakerNET.GenApi.ICommand _commandNode;
            private bool _disposed = false;
            private string _buttonLabel = "Execute";
            private bool _isButtonEnabled;

            // GenICam callback update thread
            BackgroundWorker _updateWorker;

            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);
            }

            public bool IsButtonEnabled
            {
                get
                {
                    return _isButtonEnabled;
                }
                set
                {
                    _isButtonEnabled = value;
                    NotifyPropertyChanged("IsButtonEnabled");
                }
            }

            public System.Windows.Visibility ButtonVisibility
            {
                get
                {
                    return this.button.Visibility;
                }
                set
                {
                    this.button.Visibility = value;
                    NotifyPropertyChanged("ButtonVisibility");
                }
            }

            public string ButtonLabel
            {
                get
                {
                    return _buttonLabel;
                }
                set
                {
                    _buttonLabel = value;
                    NotifyPropertyChanged("ButtonLabel");
                }
            }
#endregion

#region CONSTRUCTOR
            public ButtonControl()
            {
                InitializeComponent();

                _updateWorker = new BackgroundWorker();
                _updateWorker.DoWork += _updateWorker_DoWork;
                _updateWorker.RunWorkerCompleted += _updateWorker_RunWorkerCompleted;
            }

            // Copy Constructor
            internal ButtonControl(ButtonControl originalControl)
            {
                InitializeComponent();

                _updateWorker = new BackgroundWorker();
                _updateWorker.DoWork += _updateWorker_DoWork;
                _updateWorker.RunWorkerCompleted += _updateWorker_RunWorkerCompleted;

                this.SetMapper(originalControl.GetMapper());
                this.Connect(
                    originalControl.NodeMap, originalControl.GetNodeToControl(), originalControl.GetControlNameLabel());
                this.SetNameLabelBoldness(originalControl.NameLabelBoldness);
                this.SetVisibility(originalControl.ControlVisibility);
                this.SetControlID(originalControl.ControlID);
                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());
            }
#endregion

#region IPGRControlInterface

            public void SetButtonLabel(string label)
            {
                ButtonLabel = label;
            }

            public override void Refresh()
            {
                UpdateControlStatus();
            }

            public string GetButtonLabel()
            {
                return ButtonLabel;
            }

            public override void Connect(INodeMap nodemap, string nodename, string label = "")
            {
                this._propertyToControl = nodename;
                this._nodeMap = nodemap;

                if (nodemap != 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
                    {
                        IValue node = nodemap.GetNode<IValue>(nodename);

                        if (node == null)
                        {
                            throw new Exception("Feature not found");
                        }

                        this._nodeType = node.GetType();
                        if (_nodeType != typeof (Command))
                        {
                            log.Error(string.Format("{1}{0} is not a command node!", nodename, FormattedSerialNumber));
                            throw new Exception(
                                string.Format("{1}{0} is not a command node!", nodename, FormattedSerialNumber));
                        }
                        _featureAvailable = node.IsImplemented;
                    }
                    catch (System.Exception ex)
                    {
                        log.Debug(string.Format(
                            "{2}Problem connecting to node {0} {1}!", nodename, ex.Message, FormattedSerialNumber));
                        _featureAvailable = false;
                        UpdateControlStatus();
                        throw new Exception(
                            string.Format("Problem accessing {0} node. {1}", this._propertyToControl, ex.Message));
                    }

                    _initializing = true;

                    try
                    {
                        UpdateControlValues(this._nodeType, this._nodeMap, this._propertyToControl, label);
                        UpdateControlStatus();
                        RegisterGenICamCallbacks();
                        // RegisterInterfaceEvents();
                    }
                    catch (System.Exception ex)
                    {
                        log.Error(string.Format(
                            "{2}Problem accessing {0} node. {1}",
                            this._propertyToControl,
                            ex.Message,
                            FormattedSerialNumber));
                        throw new Exception(
                            string.Format("Problem accessing {0} node. {1}", this._propertyToControl, ex.Message));
                    }
                    finally
                    {
                        _initializing = false;
                    }
                }
                else
                {
                    _featureAvailable = false;
                }
            }

            public override void Disconnect()
            {
                try
                {
                    if (_commandNode != null)
                    {
                        _commandNode.Updated -= node_Updated;
                    }
                    _commandNode = null;
                    base.Disconnect();
                }
                catch (System.Exception /*ex*/)
                {
                }
            }
#endregion

#region UI_CONTROL_UPDATE
            private void UpdateControlStatus()
            {
                if (_nodeMap == null)
                {
                    IsEditable = false;
                    IsButtonEnabled = false;
                    return;
                }

                try
                {
                    IValue node = _nodeMap.GetNode<IValue>(_propertyToControl);

                    if (node == null || !node.IsAvailable)
                    {
                        IsEditable = false;
                        IsButtonEnabled = false;
                        return;
                    }

                    if (!node.IsWritable)
                    {
                        IsButtonEnabled = false;
                        IsEditable = false;
                        return;
                    }
                    else
                    {
                        IsEditable = true;
                        if (!IsButtonEnabled)
                        {
                            IsButtonEnabled = true;
                        }
                    }
                }
                catch (System.Exception /*ex*/)
                {
                }
            }

            private void UpdateControlValues(Type type, INodeMap nodemap, string nodename, string namelabel = "")
            {
                if (type == typeof (Command))
                {
                    try
                    {
                        _commandNode = nodemap.GetNode<SpinnakerNET.GenApi.ICommand>(nodename);
                    }
                    catch (System.Exception /*ex*/)
                    {
                        Console.Out.WriteLine(string.Format("Problem obtaining {0} from NodeMap.", nodename));
                        return;
                    }

                    ControlNameLabel = namelabel.Length == 0 ? _commandNode.DisplayName : namelabel;

                    // Set tooltip
                    button.ToolTip = _commandNode.ToolTip;
                }
                else
                {
                    // Unhandled node type detected
                    log.Error(string.Format(
                        "{0}Unexpected control type for {1} node from Nodemap.", FormattedSerialNumber, nodename));
                    throw new Exception(string.Format("Unexpected control type!"));
                }
            }

#endregion

#region GENICAM_CALLBACK
            private void RegisterGenICamCallbacks()
            {
                if (_commandNode != null)
                {
                    _commandNode.Updated += node_Updated;
                }
            }

            [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;
                }

                try
                {
                    Dispatcher.Invoke(() => {
                        _isUpdating = true;
                        _initializing = true;

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

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

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

                        LogNodeCallback(log, currentNodeStatus.NodeName, logMessage);

                        if (_controlNameLabel != currentNodeStatus.NodeDisplayName)
                        {
                            ControlNameLabel = currentNodeStatus.NodeDisplayName;
                            refreshRequired = true;
                        }

                        if (!currentNodeStatus.IsAvailable)
                        {
                            IsEditable = false;
                            IsButtonEnabled = false;
                        }

                        if (!currentNodeStatus.IsWritable)
                        {
                            IsButtonEnabled = false;
                            IsEditable = false;
                        }
                        else
                        {
                            IsEditable = true;
                            if (!IsButtonEnabled)
                            {
                                IsButtonEnabled = true;
                            }
                            refreshRequired = true;
                        }
                    });
                }
                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;
            }

            private void node_Updated(INode node)
            {
                if (_nodeMap == null)
                {
                    return;
                }

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

                if (!IsVisible)
                {
                    return;
                }

                _updateWorker.RunWorkerAsync(node);
            }

#endregion

#region UI_Event_Handlers

            new public void PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
            {
                e.Handled = true;
            }

            private void button_Click(object sender, RoutedEventArgs e)
            {
                if (_commandNode != null)
                {
                    try
                    {
                        // Set busy indicator
                        Mouse.OverrideCursor = Cursors.Wait;

                        if (_commandNode.IsWritable)
                        {
                            // Log user initiated changes
                            LogNodeUpdateAction(log, _commandNode, "Executed");
                            AnalyticsNodeUpdateAction(analytics, _commandNode, "Executed");

                            _commandNode.Execute();

                            // Poll for command completion
                            while (!_commandNode.IsDone(true))
                            {
                                // Sleep short duration
                                Thread.Sleep(2);
                            }
                        }
                        else
                        {
                            MessageBox.Show("Command is currently not executable.");
                        }
                    }
                    catch (Exception ex)
                    {
                        log.Error(string.Format("There was a problem executing {0}", _commandNode.Name), ex);
                    }
                    finally
                    {
                        Mouse.OverrideCursor = null;
                    }
                }
            }

#endregion

#region ORIENTATION_CONTROL
            public override Orientation ContentOrientation
            {
                get
                {
                    return rootLayout.Orientation;
                }
                set
                {
                    rootLayout.Orientation = value;
                }
            }

            public void SetContentOrientation(Orientation newOrientation)
            {
                this.ContentOrientation = newOrientation;
            }

            public Orientation GetContentOrientation()
            {
                return this.ContentOrientation;
            }
#endregion
        }

    }
}