File ComboBoxControl.xaml.cs¶
File List > PGRControls > ComboBoxControl.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.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using SpinnakerNET.GenApi;
using System.Windows.Threading;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Runtime.ExceptionServices;
using System.Security;
using System.Threading;
namespace SpinnakerNET.GUI
{
namespace WPFControls
{
public sealed partial class ComboBoxControl : BaseClass
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(ComboBoxControl));
private static readonly log4net.ILog analytics = log4net.LogManager.GetLogger("Analytics");
#region FIELDS
private IEnum _enumNode;
private Dictionary<string, long>_entryTable;
private bool _skipCallback = false;
private bool _disposed = false;
private ObservableCollection<Entry>_entries;
private Entry _currentlySelectedEntry;
private bool _isEnabled; // whether combobox is enabled
private bool _userEditing = false;
// GenICam callback update thread
BackgroundWorker _updateWorker;
#endregion
#region PROPERTIES
public ObservableCollection<Entry>Entries
{
get
{
if (_entries == null)
{
_entries = new ObservableCollection<Entry>();
}
return _entries;
}
private set
{
_entries = value;
NotifyPropertyChanged("Entries");
}
}
public Entry CurrentlySelectedEntry
{
get
{
return _currentlySelectedEntry;
}
set
{
_currentlySelectedEntry = value;
NotifyPropertyChanged("CurrentlySelectedEntry");
}
}
public bool IsCBOEnabled
{
get
{
return _isEnabled;
}
private set
{
_isEnabled = value;
NotifyPropertyChanged("IsCBOEnabled");
}
}
public double ControlMargin
{
get
{
return this.Margin.Left;
}
set
{
this.Margin = new Thickness(value);
}
}
#endregion
#region Constructor
public ComboBoxControl()
{
InitializeComponent();
_entryTable = new Dictionary<string, long>();
this.DataContext = this;
_updateWorker = new BackgroundWorker();
_updateWorker.DoWork += _updateWorker_DoWork;
_updateWorker.RunWorkerCompleted += _updateWorker_RunWorkerCompleted;
}
~ComboBoxControl()
{
Disconnect();
}
internal ComboBoxControl(ComboBoxControl originalControl)
{
InitializeComponent();
_entryTable = new Dictionary<string, long>();
this.DataContext = this;
_updateWorker = new BackgroundWorker();
_updateWorker.DoWork += _updateWorker_DoWork;
_updateWorker.RunWorkerCompleted += _updateWorker_RunWorkerCompleted;
this.Entries = originalControl.Entries;
this.CurrentlySelectedEntry = originalControl.CurrentlySelectedEntry;
// Common Properties
this.SetMapper(originalControl.GetMapper());
this.Connect(
originalControl.NodeMap, originalControl.GetNodeToControl(), originalControl.GetControlNameLabel());
this.SetNameLabelBoldness(originalControl.NameLabelBoldness);
this.SetVisibility(originalControl.Visibility);
this.SetControlID(originalControl.ControlID);
this.SetMin(originalControl.GetMin());
this.SetMax(originalControl.GetMax());
this.SetControlNameLabel(originalControl.ControlNameLabel);
this.SetNameLabelVisibility(originalControl.GetNameLabelVisibility());
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());
}
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
public override void Connect(INodeMap nodemap, string nodename, string namelabel = "")
{
if (nodename.Length != 0 && nodemap != null)
{
_initializing = true;
// Acquire device serial number
if (string.IsNullOrWhiteSpace(_serialNumber))
{
_serialNumber = RetrieveSerialNumber(nodemap);
}
// Acquire device model name
if (string.IsNullOrWhiteSpace(_deviceModelName))
{
_deviceModelName = RetrieveModelName(nodemap);
}
try
{
this._nodeMap = nodemap;
this._propertyToControl = nodename;
_enumNode = nodemap.GetNode<IEnum>(this._propertyToControl);
if (_enumNode == null)
{
throw new Exception("Feature not found");
}
this._nodeType = _enumNode.GetType();
ControlToolTip = _enumNode.ToolTip;
_featureAvailable = _enumNode.IsImplemented;
if (namelabel.Length > 0)
{
SetControlNameLabel(namelabel);
SetNameLabelVisibility(System.Windows.Visibility.Visible);
SetToolTip(_enumNode.ToolTip.ToString());
}
else
{
SetControlNameLabel(_enumNode.DisplayName);
}
PopulateEntries();
// Register GenIcam callback
_enumNode.Updated += enumNode_Updated;
_callbackRegistered = true;
RegisterInterfaceEvents();
}
catch (System.Exception ex)
{
// Debug.WriteLine(string.Format("Problem accessing {0} node", this._propertyToControl));
_featureAvailable = false;
log.Debug(
string.Format(
"{1}Problem accessing {0} node.", this._propertyToControl, FormattedSerialNumber),
ex);
throw new Exception(string.Format(
"{2}Problem accessing {0} node. {1}",
this._propertyToControl,
ex.Message,
FormattedSerialNumber));
}
finally
{
_initializing = false;
}
}
else
{
Entries.Clear();
Entry entry = new Entry("N/A", -1);
Entries.Add(entry);
CurrentlySelectedEntry = entry;
IsCBOEnabled = false;
_featureAvailable = false;
}
}
private void PopulateEntries()
{
if (_entries == null)
{
_entries = new ObservableCollection<Entry>();
}
else
{
Entries.Clear();
}
if (_enumNode == null)
{
log.Debug(string.Format("{1} {0} node is null.", this._propertyToControl, FormattedSerialNumber));
return;
}
try
{
foreach(var node in _enumNode.Entries)
{
// Keep track of all possible entries and their Node value
if (node.IsImplemented && node.IsAvailable)
{
Entry newEntry = new Entry(node.DisplayName, node.Value);
if (newEntry != null)
{
Entries.Add(newEntry);
}
}
}
}
catch (System.Exception ex)
{
Debug.WriteLine(
string.Format("Problem updating ComboBox for {0}. {1}", PropertyToControl, ex.Message));
}
UpdateControlStatus();
}
public override void Disconnect()
{
try
{
if (_enumNode != null && _callbackRegistered)
{
_enumNode.Updated -= enumNode_Updated;
}
_enumNode = null;
_mapper = null;
_callbackRegistered = false;
base.Disconnect();
}
catch (System.Exception /*ex*/)
{
}
}
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 Refresh()
{
if (_enumNode == null || _nodeMap == null)
{
return;
}
PopulateEntries();
}
#endregion
#region EVENT_HANDLERS
void timer_Tick(object sender, EventArgs e)
{
try
{
PopulateEntries();
}
catch (System.Exception /*ex*/)
{
Debug.WriteLine(string.Format("Problem retrieving new value from {0} node", _propertyToControl));
}
}
[HandleProcessCorruptedStateExceptions]
[SecurityCritical]
private void
_updateWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
return;
}
try
{
_isUpdating = true;
_skipCallback = 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);
if (currentNodeStatus.IsReadable)
{
try
{
logMessage += string.Format(", Value=\"{0}\"", currentNodeStatus.CurrentEnumValue.String);
}
catch (Exception ex)
{
log.Debug(string.Format(
"Exception while getting the value of currentNodeStatus.CurrentEnumValue: Error: {0}",
ex.Message));
}
}
LogNodeCallback(log, currentNodeStatus.NodeName, logMessage);
if (ControlNameLabel != currentNodeStatus.NodeDisplayName)
{
ControlNameLabel = currentNodeStatus.NodeDisplayName;
}
if (!Dispatcher.CheckAccess())
{
Dispatcher.BeginInvoke(
(Action)(() => {
if (_entries == null)
{
_entries = new ObservableCollection<Entry>();
}
else
{
Entries.Clear();
}
if (Entries != currentNodeStatus.Entries)
{
Entries = currentNodeStatus.Entries;
}
foreach(var entry in Entries)
{
if (currentNodeStatus.CurrentEnumValue.Int == entry.Value)
{
combobox.SelectionChanged -= combobox_SelectionChanged;
CurrentlySelectedEntry = entry;
combobox.SelectionChanged += combobox_SelectionChanged;
break;
}
}
}),
DispatcherPriority.Background,
null);
}
else
{
if (_entries == null)
{
_entries = new ObservableCollection<Entry>();
}
else
{
Entries.Clear();
}
if (Entries != currentNodeStatus.Entries)
{
Entries = currentNodeStatus.Entries;
}
foreach(var entry in Entries)
{
if (currentNodeStatus.CurrentEnumValue.Int == entry.Value)
{
combobox.SelectionChanged -= combobox_SelectionChanged;
CurrentlySelectedEntry = entry;
combobox.SelectionChanged += combobox_SelectionChanged;
break;
}
}
}
if (currentNodeStatus.IsWritable)
{
IsEditable = true;
IsCBOEnabled = true;
}
else
{
IsCBOEnabled = false;
IsEditable = false;
}
}
catch (System.Exception ex)
{
log.Debug(
string.Format(
"{1}Problem updating control for {0} node", _propertyToControl, FormattedSerialNumber),
ex);
}
finally
{
_initializing = false;
_isUpdating = false;
_skipCallback = false;
}
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 enumNode_Updated(INode node)
{
if (_userEditing || _initializing)
{
return;
}
if (_skipCallback)
{
return;
}
if (_nodeMap == null)
{
return;
}
if (_updateWorker.IsBusy || _isUpdating)
{
return;
}
if (!IsVisible)
{
return;
}
_updateWorker.RunWorkerAsync(node);
}
new private void PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
}
private void combobox_DropDownOpened(object sender, EventArgs e)
{
_userEditing = true;
}
private void combobox_DropDownClosed(object sender, EventArgs e)
{
_userEditing = false;
}
public static RoutedEvent SelectionChangeEvent = EventManager.RegisterRoutedEvent(
"SelectionChange",
RoutingStrategy.Bubble,
typeof(RoutedEventHandler),
typeof(ComboBoxControl));
public event RoutedEventHandler SelectionChange
{
add
{
AddHandler(SelectionChangeEvent, value);
}
remove
{
RemoveHandler(SelectionChangeEvent, value);
}
}
public void OnSelectionChange()
{
RoutedEventArgs args = new RoutedEventArgs(SelectionChangeEvent, this);
RaiseEvent(args);
}
private void combobox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (_initializing)
{
return;
}
try
{
if (_enumNode != null && _enumNode.IsWritable && CurrentlySelectedEntry != null)
{
_skipCallback = true;
// Log user initiated changes
LogNodeUpdateAction(log, _enumNode, CurrentlySelectedEntry.Name);
AnalyticsNodeUpdateAction(analytics, _enumNode, CurrentlySelectedEntry.Name);
_enumNode.Value = CurrentlySelectedEntry.Value;
_skipCallback = false;
// Update Dependency
if (_dependencyControlList != null && _dependencyControlList.Count > 0)
{
_dependencyControlList.Refresh();
}
Refresh();
// Notify event listeners on combobox selection change
OnSelectionChange();
}
}
catch (Exception ex)
{
log.Debug(
string.Format("There was a problem updating {0} node. {1}", _propertyToControl, ex.Message));
}
}
public void UpdateControlStatus()
{
if (_nodeMap == null)
{
IsEditable = false;
IsCBOEnabled = false;
return;
}
try
{
_initializing = true;
_enumNode = _nodeMap.GetNode<IEnum>(this._propertyToControl);
if (_enumNode != null && _enumNode.IsReadable)
{
// Enable combobox
IsCBOEnabled = true;
long nodeValue = _enumNode.Value.Int;
foreach(var entry in Entries)
{
if (nodeValue == entry.Value)
{
CurrentlySelectedEntry = entry;
break;
}
}
if (_enumNode.IsWritable)
{
IsCBOEnabled = true;
IsEditable = true;
}
else
{
IsCBOEnabled = false;
IsEditable = false;
}
}
else
{
IsEditable = false;
IsCBOEnabled = false;
}
}
catch (System.Exception /*ex*/)
{
}
finally
{
_initializing = false;
}
}
#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
public class Entry : INotifyPropertyChanged
{
string _name = "";
long _value = 0;
#region INOTIFYPROPERTYCHANGED_IMPLEMENTATION
public void NotifyPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
public Entry(string name, long value)
{
this._name = name;
this._value = value;
}
public string Name
{
get
{
return _name;
}
set
{
this._name = value;
NotifyPropertyChanged("Name");
}
}
public long Value
{
get
{
return _value;
}
set
{
this._value = value;
NotifyPropertyChanged("Value");
}
}
}
}
}
}