Skip to content

File ImageDrawingControl.xaml.cs

File List > PGRControls > ImageDrawingControl.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 SpinnakerNET;
using SpinnakerNET.GenApi;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Xml.Linq;
using System.Xml.Serialization;
using Visibility = System.Windows.Visibility;

namespace SpinnakerNET.GUI
{
    namespace WPFControls
    {


        public partial class ImageDrawingControl : BaseClass, INotifyPropertyChanged, ISettings
        {
#region Fields
            private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(ImageDrawingControl));
            private static readonly log4net.ILog analytics = log4net.LogManager.GetLogger("Analytics");
            private DXImageDrawingWindow _DXDrawingWindow;
            private IDrawingControl _drawingControl;
            private IManagedCamera _camera;
            private bool _isMultiStreamCamera = false;
            private bool _isStereoCamera = false;
            private bool _isGrabbingImages = false;
            private bool _isConnected = false;

            private ViewerParser _viewerParser;
            private bool _useDefaultStatusBar = false;
            private bool _disposed = false;
            private PersistentSettings _settings;
            private bool _applyingSettings = false;
            private bool _delayApplyingSettings = false;
            public delegate void ImageGrabbedEvent(ref IManagedImage image);

            public Label _ErrorTextLabel;
            InferenceTextControl _inferenceTextLabel;

            private const string AnalyticsEventCategory = "ImageDrawingControl";

            private readonly object _instanceLock = new object();
#endregion

            public bool ColorCorrectionAvailable
            {
                get
                {
                    return (_DXDrawingWindow != null && _DXDrawingWindow.ColorCorrectionAvailable);
                }
            }

            public void ApplySettings(PersistentSettings settings)
            {
                if (_viewerParser != null && _viewerParser.IsBusy)
                {
                    _delayApplyingSettings = true;
                    _settings = settings;
                    return;
                }

                if (_DXDrawingWindow == null)
                {
                    return;
                }

                _applyingSettings = true;
                _DXDrawingWindow.IsInitializingContextMenu = true;

                _DXDrawingWindow.HoldImageEnable = settings.ImageDrawingWindowPersistentSettings.HoldLastImage;
                _DXDrawingWindow.CurrentColorProcessingMethod =
                    settings.ImageDrawingWindowPersistentSettings.ColorProcessingAlgorithm;
                _DXDrawingWindow.StretchToFitEnable = settings.ImageDrawingWindowPersistentSettings.StretchToFit;
                _DXDrawingWindow.DrawImageEnable = settings.ImageDrawingWindowPersistentSettings.EnableDrawImage;
                _DXDrawingWindow.EnableCrosshairDraw =
                    settings.ImageDrawingWindowPersistentSettings.EnableCrosshairDraw;
                _DXDrawingWindow.CrosshairColorBrush = (SolidColorBrush)new BrushConverter().ConvertFromString(
                    settings.ImageDrawingWindowPersistentSettings.CrosshairColorStr);
                _DXDrawingWindow.CurrentRotationAngle = settings.ImageDrawingWindowPersistentSettings.RotationAngle;

                _DXDrawingWindow.CurrentDisparityProcessingMethod =
                    settings.ImageDrawingWindowPersistentSettings.DisparityProcessingMethod;

                _DXDrawingWindow.IsInitializingContextMenu = false;

                // Selected items
                if (_viewerParser == null)
                {
                    _delayApplyingSettings = true;
                    _settings = settings;
                    _applyingSettings = false;
                    return;
                }

                var selectedItems = settings.ImageDrawingWindowPersistentSettings.SelectedItems != null
                    ? new HashSet<string>(settings.ImageDrawingWindowPersistentSettings.SelectedItems)
                    : null;
                bool hasPersistedSelections = selectedItems != null && selectedItems.Count > 0;

                foreach (var model in _viewerParser.Models)
                {
                    foreach (var child in model.Children)
                    {
                        if (hasPersistedSelections)
                        {
                            child.IsVisible = selectedItems.Contains(child.Name);
                        }
                        else if (selectedItems != null && selectedItems.Contains(child.Name))
                        {
                            child.IsVisible = true;
                        }
                    }

                    // Also apply settings to SubModels (e.g., Chunk Data Status subcategory)
                    if (model.SubModels != null)
                    {
                        foreach (var subModel in model.SubModels)
                        {
                            foreach (var subChild in subModel.Children)
                            {
                                if (hasPersistedSelections)
                                {
                                    subChild.IsVisible = selectedItems.Contains(subChild.Name);
                                }
                                else if (selectedItems != null && selectedItems.Contains(subChild.Name))
                                {
                                    subChild.IsVisible = true;
                                }
                            }
                        }
                    }
                }
                _applyingSettings = false;
            }

            public void FetchSettings(PersistentSettings settings)
            {
                settings.ImageDrawingWindowPersistentSettings.HoldLastImage = _DXDrawingWindow.HoldImageEnable;
                settings.ImageDrawingWindowPersistentSettings.ColorProcessingAlgorithm =
                    _DXDrawingWindow.CurrentColorProcessingMethod;
                settings.ImageDrawingWindowPersistentSettings.StretchToFit = _DXDrawingWindow.StretchToFitEnable;
                settings.ImageDrawingWindowPersistentSettings.EnableDrawImage = _DXDrawingWindow.DrawImageEnable;
                settings.ImageDrawingWindowPersistentSettings.EnableCrosshairDraw =
                    _DXDrawingWindow.EnableCrosshairDraw;
                settings.ImageDrawingWindowPersistentSettings.CrosshairColorStr =
                    _DXDrawingWindow.CrosshairColorBrush.ToString();
                settings.ImageDrawingWindowPersistentSettings.RotationAngle = _DXDrawingWindow.CurrentRotationAngle;
                settings.ImageDrawingWindowPersistentSettings.ShowInferenceLabel = _DXDrawingWindow.ShowInferenceLabel;
                settings.ImageDrawingWindowPersistentSettings.SelectedImageName = _DXDrawingWindow.SelectedImageName;
                settings.ImageDrawingWindowPersistentSettings.ImageDisplayDarkMode =
                    _DXDrawingWindow.ToggleDisplayBackground;
                settings.ImageDrawingWindowPersistentSettings.DisparityProcessingMethod =
                    _DXDrawingWindow.CurrentDisparityProcessingMethod;

                if (_viewerParser == null || _viewerParser.IsBusy)
                {
                    return;
                }

                // Fetch checked items
                settings.ImageDrawingWindowPersistentSettings.SelectedItems.Clear();

                foreach (var model in _viewerParser.Models)
                {
                    foreach (var child in model.Children)
                    {
                        if (child.IsVisible &&
                            !settings.ImageDrawingWindowPersistentSettings.SelectedItems.Contains(child.Name))
                        {
                            settings.ImageDrawingWindowPersistentSettings.SelectedItems.Add(child.Name);
                        }
                    }

                    // Also fetch settings from SubModels (e.g., Chunk Data Status subcategory)
                    if (model.SubModels != null)
                    {
                        foreach (var subModel in model.SubModels)
                        {
                            foreach (var subChild in subModel.Children)
                            {
                                if (subChild.IsVisible &&
                                    !settings.ImageDrawingWindowPersistentSettings.SelectedItems.Contains(subChild.Name))
                                {
                                    settings.ImageDrawingWindowPersistentSettings.SelectedItems.Add(subChild.Name);
                                }
                            }
                        }
                    }
                }
            }

            public void SaveSettings()
            {
                if (_initializing || _applyingSettings)
                {
                    return;
                }

                _settings.LoadPersistentSettings();
                FetchSettings(_settings);
                _settings.SavePersistentSettings();
            }

            private void DXDrawingWindow_OnSettingsChanged()
            {
                SaveSettings();
            }

            public void SetZoomPercentage(double zoomPercentage)
            {
                if (_drawingControl != null)
                {
                    _drawingControl.SetZoomPercentage(zoomPercentage);
                }
            }

#region Constructor

            public bool DoLoadImageFromDiskUserSelection(out string filename)
            {
                filename = string.Empty;
                if (_DXDrawingWindow != null)
                {
                    _DXDrawingWindow.InitializeUIExternal();
                }
                else
                {
                    return false;
                }

                try
                {
                    // Delegate to DXImageDrawingWindow to handle the file loading and display
                    bool loadSuccess = _DXDrawingWindow.DoLoadFileAndDisplay(out filename);

                    if (loadSuccess)
                    {
                        // Detect image payload and configure display accordingly
                        DetectAndConfigureDisplay();

                        // Set toolbar states
                        btn_zoomin.IsEnabled = true;
                        btn_zoomout.IsEnabled = true;
                        btn_loupe_tool.IsEnabled = true;
                        btn_Save.IsEnabled = true;
                    }

                    return loadSuccess;
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine($"Error loading image: {ex.Message}");
                    return false;
                }
            }

            private void DetectAndConfigureDisplay()
            {
                if (_DXDrawingWindow == null)
                {
                    return;
                }

                var imageList = _DXDrawingWindow.GetCachedImageList();

                if (imageList == null || imageList.Count == 0)
                {
                    return;
                }

                bool foundStereoFormat = false;
                bool found3DFormat = false;

                // Search through the image list for stereo payloads
                for (int i = 0; i < imageList.Count; i++)
                {
                    var image = imageList[i];

                    if (_DXDrawingWindow.IsDepthPayload(image.ImagePayloadType))
                    {
                        foundStereoFormat = true;
                    }
                    if (_DXDrawingWindow.Is3DFormat(image.PixelFormat))
                    {
                        found3DFormat = true;
                    }
                    if (foundStereoFormat && found3DFormat)
                    {
                        break;
                    }
                }

                if (foundStereoFormat)
                {
                    // Enable 2D/3D buttons and default to 2D view
                    IsStereoCamera = true;
                    btn_2D_view.IsEnabled = false;
                    btn_3D_view.IsEnabled = true;
                }

                if (found3DFormat)
                { 
                    // With a 3D Format we default to 3D view
                    btn_2D_view.IsEnabled = true;
                    btn_3D_view.IsEnabled = false;
                }
            }

            public ImageDrawingControl(bool streamOnlyMode = false)
            {
                _initializing = true;
                InitializeComponent();
                this.DataContext = this;

                if (streamOnlyMode)
                {
                    myExpander.Visibility = System.Windows.Visibility.Collapsed;
                    m_statusbar.Visibility = System.Windows.Visibility.Collapsed;
                }

                if (_settings == null)
                {
                    _settings = PersistentSettings.Instance;
                }

                // Use Dispatcher to catch the closing event
                Dispatcher.ShutdownStarted += new EventHandler(Dispatcher_ShutdownStarted);

                if (_DXDrawingWindow == null)
                {
                    // Create User Control
                    _DXDrawingWindow = new DXImageDrawingWindow(this);
                    _DXDrawingWindow.OnSettingsChanged += DXDrawingWindow_OnSettingsChanged;
                    _DXDrawingWindow.PropertyChanged += DXDrawingWindow_PropertyChanged;
                }

                if (_ErrorTextLabel == null)
                {
                    _ErrorTextLabel = new Label
                    {
                        Foreground = Brushes.Red,
                        FontSize = 20,
                        VerticalAlignment = VerticalAlignment.Top,
                        HorizontalAlignment = HorizontalAlignment.Left
                    };
                }

                if (_inferenceTextLabel == null)
                {
                    _inferenceTextLabel = _DXDrawingWindow.GetInferenceLabel();
                }

                m_drawingWindow.Children.Add(_DXDrawingWindow);
                m_drawingWindow.Children.Add(_ErrorTextLabel);
                m_drawingWindow.Children.Add(_inferenceTextLabel);

                _drawingControl = _DXDrawingWindow;

                _DXDrawingWindow.OnUpdateCursorInformation +=
                    new DXImageDrawingWindow.OnUpdateCursorInformationEvent(OnUpdateCursorInformation);
                _DXDrawingWindow.OnUpdateStreamInformation +=
                    new DXImageDrawingWindow.UpdateStreamInformationEvent(OnUpdateStreamInformation);
                _DXDrawingWindow.OnUpdateErrorText += new DXImageDrawingWindow.UpdateErrorTextEvent(OnUpdateErrorText);

                DisableControls();

                ApplySettings(_settings);

                _initializing = false;

            }

            protected override void Dispose(bool disposing)
            {
                if (!_disposed)
                {
                    if (disposing)
                    {
                    }
                    _disposed = true;
                }
                // Call Dispose in the base class.
                base.Dispose(disposing);
            }
#endregion

#region EVENT_HANDLER
            void OnUpdateStreamInformation(ImageStreamInformation information)
            {
                if (_viewerParser != null)
                {
                    foreach (var model in _viewerParser.Models)
                    {
                        foreach (var child in model.Children)
                        {
                            switch (child.UINamespace)
                            {
                                case UINameSpace.genicam:
                                case UINameSpace.gentl:
                                case UINameSpace.stream:
                                    if (child.IsVisible && child.GeniCamLabelControl != null)
                                    {
                                        child.GeniCamLabelControl.InvalidateNode();
                                    }
                                    continue;
                                case UINameSpace.viewerctrl:
                                case UINameSpace.undefined:
                                    break;
                            }

                            switch (child.ItemType)
                            {
                                case DynamicStatusBarItemTypes.bpp:
                                    child.Value = information.BPP;
                                    break;
                                case DynamicStatusBarItemTypes.cursorposition:
                                    child.Value = information.CursorPosition;
                                    break;
                                case DynamicStatusBarItemTypes.depthvalue:
                                    child.Value = information.DepthValue;
                                    break;
                                case DynamicStatusBarItemTypes.pointcount:
                                    child.Value = information.PointCount;
                                    break;
                                case DynamicStatusBarItemTypes.displayfps:
                                    child.Value = information.ConvertedDisplayedFPS;
                                    break;
                                case DynamicStatusBarItemTypes.displaysize:
                                    child.Value = information.DisplaySize;
                                    break;
                                case DynamicStatusBarItemTypes.height:
                                    child.Value = information.Height;
                                    break;
                                case DynamicStatusBarItemTypes.millisecond:
                                    child.Value = information.Milliseconds;
                                    break;
                                case DynamicStatusBarItemTypes.pixelformat:
                                    child.Value = information.PixelFormat;
                                    break;
                                case DynamicStatusBarItemTypes.pixelvalue:
                                    child.Value = information.PixelValue;
                                    break;
                                case DynamicStatusBarItemTypes.processedfps:
                                    child.Value = information.ProcessedFPS;
                                    break;
                                case DynamicStatusBarItemTypes.receivedfps:
                                    child.Value = information.ReceivedFPS;
                                    break;
                                case DynamicStatusBarItemTypes.cameraleaderfps:
                                    child.Value = information.CameraLeaderFPS;
                                    break;
                                case DynamicStatusBarItemTypes.seconds:
                                    child.Value = information.Seconds;
                                    break;
                                case DynamicStatusBarItemTypes.width:
                                    child.Value = information.Width;
                                    break;
                                case DynamicStatusBarItemTypes.zoomlevel:
                                    child.Value = information.ZoomLevel;
                                    break;
                                case DynamicStatusBarItemTypes.frameid:
                                    child.Value = information.FrameID;
                                    break;
                                case DynamicStatusBarItemTypes.timestamp:
                                    child.Value = information.Timestamp;
                                    break;
                                case DynamicStatusBarItemTypes.compressionratio:
                                    child.Value = information.CompressionRatio;
                                    break;
                                case DynamicStatusBarItemTypes.streamindex:
                                    child.Value = information.StreamIndex;
                                    break;
                                case DynamicStatusBarItemTypes.undefined:
                                    break;
                            }
                        }
                    }
                }
            }

            void OnUpdateCursorInformation(ImageStreamInformation information)
            {
                if (_viewerParser != null)
                {
                    foreach (var model in _viewerParser.Models)
                    {
                        foreach (var child in model.Children)
                        {
                            switch (child.ItemType)
                            {
                                case DynamicStatusBarItemTypes.cursorposition:
                                    child.Value = information.CursorPosition;
                                    break;
                                case DynamicStatusBarItemTypes.depthvalue:
                                    child.Value = information.DepthValue;
                                    break;
                                case DynamicStatusBarItemTypes.zoomlevel:
                                    child.Value = information.ZoomLevel;
                                    break;
                                case DynamicStatusBarItemTypes.pixelvalue:
                                    child.Value = information.PixelValue;
                                    break;
                                case DynamicStatusBarItemTypes.undefined:
                                    break;
                            }
                        }
                    }
                }
            }

            void OnUpdateErrorText(string errorText)
            {
                Dispatcher.Invoke(DispatcherPriority.Normal, (System.Threading.ThreadStart)delegate ()
                {
                    if (errorText == string.Empty)
                    {
                        _ErrorTextLabel.Visibility = System.Windows.Visibility.Collapsed;
                    }
                    else
                    {
                        _ErrorTextLabel.Content = errorText;
                        _ErrorTextLabel.Visibility = System.Windows.Visibility.Visible;
                    }
                });
            }

            private void DisableControls()
            {
                if (btn_loupe_tool.IsChecked.Equals(true))
                {
                    _drawingControl.ToggleLoupeTool();
                    btn_loupe_tool.IsChecked = false;
                }

                btn_Start.IsEnabled = false;
                btn_Snap.IsEnabled = false;
                btn_Stop.IsEnabled = false;
                btn_zoomin.IsEnabled = false;
                btn_zoomout.IsEnabled = false;
                btn_loupe_tool.IsEnabled = false;
                btn_Save.IsEnabled = false;
                btn_OptimizeFrameRate.IsEnabled = false;
                btn_Shading.IsEnabled = false;
                btn_Recorder.IsEnabled = false;
                btn_2D_view.IsEnabled = false;
                btn_3D_view.IsEnabled = false;
                OnUpdateErrorText(string.Empty);
            }

            private void Dispatcher_ShutdownStarted(object sender, EventArgs e)
            {
                if (_drawingControl != null)
                {
                    _drawingControl.CleanUp();
                }
            }

            private void DXDrawingWindow_PropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                if (e.PropertyName == nameof(_DXDrawingWindow.ColorCorrectionAvailable))
                {
                    NotifyPropertyChanged(nameof(ColorCorrectionAvailable));
                }
            }

#endregion

#region Streaming_Control
            public bool Connect(
                IManagedCamera camera,
                INodeMap map = null,
                bool BeginAcquisition = true,
                IManagedInterface parentInterface = null)
            {
                bool isCameraStreamModeTeledyneGigeVision = false;
                bool isCameraStreamModeLWF = false;
                bool isGigE = false;
                bool isUSB = false;
                bool isCXP = false;
                bool isFLIRFilterDriverInstalled = false;
                bool isTeledyneGigeVisionFilterDriverInstalled = false;
                bool isGigEStreamable = false;

                if (parentInterface != null)
                {
                    var flirFilterDriverStatusNode =
                        parentInterface.GetTLNodeMap().GetNode<SpinnakerNET.GenApi.Enumeration>(
                            "FLIRFilterDriverStatus");

                    if (flirFilterDriverStatusNode != null && flirFilterDriverStatusNode.IsReadable)
                    {
                        var flirFilterDriverEnabledNode = flirFilterDriverStatusNode.GetEntryByName("Enabled");
                        if (flirFilterDriverEnabledNode != null && flirFilterDriverEnabledNode.IsReadable)
                        {
                            isFLIRFilterDriverInstalled =
                                (flirFilterDriverStatusNode.Value.Int == flirFilterDriverEnabledNode.Value);
                        }
                    }
                    var teledyneGigeVisionFilterDriverStatusNode =
                        parentInterface.GetTLNodeMap().GetNode<SpinnakerNET.GenApi.Enumeration>(
                            "TeledyneGigeVisionFilterDriverStatus");

                    if (teledyneGigeVisionFilterDriverStatusNode != null &&
                        teledyneGigeVisionFilterDriverStatusNode.IsReadable)
                    {
                        var teledyneGigeVisionFilterDriverEnabledNode =
                            teledyneGigeVisionFilterDriverStatusNode.GetEntryByName("Enabled");
                        if (teledyneGigeVisionFilterDriverEnabledNode != null &&
                            teledyneGigeVisionFilterDriverEnabledNode.IsReadable)
                        {
                            isTeledyneGigeVisionFilterDriverInstalled =
                                (teledyneGigeVisionFilterDriverStatusNode.Value.Int ==
                                 teledyneGigeVisionFilterDriverEnabledNode.Value);
                        }
                    }
                }

                INodeMap cameraGenTLStreamNodemap = camera.GetTLStreamNodeMap();
                var streamMode = cameraGenTLStreamNodemap.GetNode<Enumeration>("StreamMode");
                if (streamMode != null && streamMode.IsReadable)
                {
                    if (streamMode.ToString().Equals("LWF"))
                    {
                        isCameraStreamModeLWF = true;
                    }
                    if (streamMode.ToString().Equals("TeledyneGigeVision"))
                    {
                        isCameraStreamModeTeledyneGigeVision = true;
                    }
                }

                var streamType = cameraGenTLStreamNodemap.GetNode<Enumeration>("StreamType");
                if (streamType != null && streamType.IsReadable)
                {
                    if (streamType.ToString().Equals("USB3Vision"))
                    {
                        isUSB = true;
                    }
                    if (streamType.ToString().Equals("GigEVision"))
                    {
                        isGigE = true;
                    }
                    if (streamType.ToString().Equals("CXP") || streamType.ToString().Equals("CoaXPress"))
                    {
                        isCXP = true;
                    }
                }

                if (_isConnected)
                {
                    throw new InvalidOperationException("Already connected.");
                }

                if (_drawingControl != null)
                {
                    _camera = camera;
                    if (base._nodeMap == null)
                    {
                        if (map != null)
                        {
                            base._nodeMap = map;
                        }
                        else
                        {
                            base._nodeMap = camera.GetNodeMap();
                        }
                    }

                    try
                    {
                        cboAcqModeSelector.Connect(_nodeMap, "AcquisitionMode");
                        cboAcqModeSelector.lockIcon.Visibility = System.Windows.Visibility.Collapsed;
                        cboAcqModeSelector.VerticalAlignment = VerticalAlignment.Center;
                        cboAcqModeSelector.label.HorizontalAlignment = HorizontalAlignment.Center;
                    }
                    catch (Exception ex)
                    {
                        log.Debug("Problem connecting Acquisition Mode ComboBox control.", ex);
                        cboAcqModeSelector.Visibility = System.Windows.Visibility.Collapsed;
                        cboSeparator.Visibility = System.Windows.Visibility.Collapsed;
                    }

                    if (string.IsNullOrWhiteSpace(base._serialNumber))
                    {
                        _serialNumber = RetrieveSerialNumber(_nodeMap);
                    }

                    if (ManagedImageUtilityStereo.IsStereoCamera(_camera))
                    {
                        btn_Save.ToolTip = "Save current image list to disk";
                    }
                    else
                    {
                        btn_Save.ToolTip = "Save current image to disk";
                    }

                    if (!_drawingControl.SetCamera(_camera, BeginAcquisition))
                    {
                        System.Windows.Forms.MessageBox.Show(
                            "Error setting new camera object!", "ImageDrawingControl Error");
                        this.IsEnabled = false;
                        return false;
                    }

                    try
                    {
                        if (camera == null)
                        {
                            return false;
                        }

                        // Always get static GUI XML
                        XElement _xmlRoot = XElement.Parse(Properties.Resources.StatusBarXml);

                        log.Debug(string.Format("{0}Viewer Parser Starting", FormattedSerialNumber));
                        _viewerParser = new ViewerParser(camera, base._nodeMap, null, null, _xmlRoot);
                        _viewerParser.UICreationCompletedEventCallback += parser_UICreationCompletedEventCallback;
                        _viewerParser.ParserUI();
                    }
                    catch (Exception ex)
                    {
                        log.Error(
                            string.Format("{0}ImageDrawingControl ViewerParser Exception.", FormattedSerialNumber), ex);
                        _useDefaultStatusBar = true;
                        throw;
                    }

                    InitializeControls(BeginAcquisition);
                    _isGrabbingImages = BeginAcquisition;
                    IsConnected = true;
                    RegisterInterfaceEvents();

                    isGigEStreamable =
                        (isFLIRFilterDriverInstalled && isCameraStreamModeLWF) || isCameraStreamModeTeledyneGigeVision;

                    btn_Start.IsEnabled = isUSB || (isGigE && isGigEStreamable) || isCXP;

                    // Collapse snap button when SingleFrame AcquisitionMode is unavailable
                    bool isSingleFrameModeAvailable = false;
                    INodeMap cameraNodemap = camera.GetNodeMap();
                    var acquisitionMode = cameraNodemap.GetNode<Enumeration>("AcquisitionMode");
                    if (acquisitionMode != null && acquisitionMode.IsReadable)
                    {
                        var singleFrameMode = acquisitionMode.GetEntryByName("SingleFrame");
                        if (singleFrameMode != null && singleFrameMode.IsReadable)
                        {
                            isSingleFrameModeAvailable = true;
                        }
                    }
                    btn_Snap.Visibility = (isSingleFrameModeAvailable ? Visibility.Visible : Visibility.Collapsed);
                    btn_Snap.IsEnabled = btn_Start.IsEnabled;

                    String streamTooltip = "Start Device Acquisition";
                    String snapTooltip = "Single Image Acquisition";

                    if (isGigE && !isGigEStreamable)
                    {
                        streamTooltip = "GigE Filter Driver needs to be installed to stream";
                        snapTooltip = "GigE Filter Driver needs to be installed to stream";
                    }

                    btn_Start.ToolTip = streamTooltip;
                    btn_Snap.ToolTip = snapTooltip;

                    IsMultiStreamCamera = _camera.GetNumDataStreams() > 1;
                    IsStereoCamera = ManagedImageUtilityStereo.IsStereoCamera(_camera);
                    if (!_settings.ImageDrawingWindowPersistentSettings.DoNotShowColPrsMethod)
                    {
                        if (IsColorCamera(_nodeMap))
                        {
                            Application.Current.Dispatcher.Invoke((Action)delegate
                            {
                                ColorProcessingWindow colorProcessWindow =
                                    new ColorProcessingWindow(_DXDrawingWindow)
                                    {
                                        ShowTopControls = true,
                                        ExpandSelector = false,
                                        HideTipAndAutoShowToggle = false
                                    };

                                // Center the window on the parent
                                Window parentWindow = Application.Current.MainWindow;
                                if (parentWindow != null)
                                {
                                    colorProcessWindow.Owner = parentWindow;
                                    colorProcessWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;
                                }
                                else
                                {
                                    colorProcessWindow.WindowStartupLocation = WindowStartupLocation.CenterScreen;
                                }
                                colorProcessWindow.EnsurePreSelectRecommended();
                                colorProcessWindow.Show();
                            });
                        }
                    }

                    if (IsStereoCamera)
                    {
                        btn_2D_view.IsEnabled = false;
                        btn_3D_view.IsEnabled = true;
                    }

                    return true;
                }
                else
                {
                    IsConnected = false;
                    return false;
                }
            }

            // Find the ContextMenu item, and the subItem, and checks that selection. Used for auto-enabling Compression
            // Ratio
            void setCheckedEnableContextMenu(string contextMenuItem, string subMenuItem)
            {
                foreach (MenuItem item in m_statusbar.ContextMenu.Items)
                {
                    if ((string)item.Header == contextMenuItem)
                    {
                        try
                        {
                            foreach (MenuItem itemInner in item.Items)
                            {
                                if ((string)itemInner.Header != null && (string)itemInner.Header == subMenuItem)
                                {
                                    itemInner.IsChecked = true;
                                    break;
                                }
                            }
                            break;
                        }
                        catch (Exception)
                        {
                            // Menu separator doesn't like to be cast to string
                            continue;
                        }
                    }
                }
            }
            void parser_UICreationCompletedEventCallback(WrapPanel panel)
            {
                if (!_useDefaultStatusBar)
                {
                    if (_delayApplyingSettings && _settings != null)
                    {
                        ApplySettings(_settings);

                        _delayApplyingSettings = false;
                    }

                    m_statusbar.Items.Clear();
                    m_statusbar.ContextMenu = _viewerParser.Menu;
                    m_statusbar.Items.Add(_viewerParser.Panel);
                    m_statusbar.ContextMenuClosing += ContextMenu_ContextMenuClosing;

                    // if compression ratio yes
                    if (_DXDrawingWindow != null && _DXDrawingWindow.UsingCompression)
                    {
                        setCheckedEnableContextMenu("Image Info", "Compression Ratio: ");
                    }
                }
                else
                {
                    // Fall back to default dynamic status bar
                    // InitializeChunkDataElements();
                }

                log.Debug(string.Format("{0}Viewer Parser Finished!", FormattedSerialNumber));
            }

            private void ContextMenu_ContextMenuClosing(object sender, ContextMenuEventArgs e)
            {
                SaveSettings();
            }

            protected override void OnDeviceRemoval(IManagedCamera camera)
            {
                if (_nodeMap == null)
                {
                    return;
                }

                string serial = camera.GetDeviceSerialNumber();

                try
                {
                    if (serial == _serialNumber)
                    {
                        // Device has been removed
                        Dispatcher.BeginInvoke((ThreadStart)delegate () { Disconnect(); });
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.Message);
                }
            }

            public void Start()
            {
                if (_isConnected)
                {
                    btn_Start_Click(this, null);
                    _isGrabbingImages = true;
                }
            }

            public void Snap()
            {
                if (_isConnected && btn_Snap.IsEnabled)
                {
                    btn_Snap_Click(this, null);
                }
            }

            public void Stop()
            {
                if (_isConnected)
                {
                    btn_Stop_Click(this, null);
                    _isGrabbingImages = false;
                }
            }

            public bool IsConnected
            {
                get
                {
                    return _isConnected;
                }

                private set
                {
                    if (_isConnected == value)
                    {
                        return;
                    }

                    _isConnected = value;
                    NotifyPropertyChanged(nameof(IsConnected));
                }
            }

            public bool IsStreaming()
            {
                return _isGrabbingImages;
            }

            public bool IsMultiStreamCamera
            {
                get
                {
                    return _isMultiStreamCamera;
                }
                set
                {
                    _isMultiStreamCamera = value;
                    NotifyPropertyChanged(nameof(IsMultiStreamCamera)); // Notify WPF of changes
                }
            }

            public bool IsStereoCamera
            {
                get
                {
                    return _isStereoCamera;
                }
                set
                {
                    _isStereoCamera = value;
                    NotifyPropertyChanged(nameof(IsStereoCamera)); // Notify WPF of changes
                }
            }

            public override void Disconnect()
            {
                lock (_instanceLock)
                {
                    if (!_isConnected)
                    {
                        return;
                    }

                    this.Dispatcher.Invoke(DispatcherPriority.Normal, (System.Threading.ThreadStart)delegate ()
                    {
                        _drawingControl.Disconnect();

                        try
                        {
                            cboAcqModeSelector.Disconnect();
                        }
                        catch (Exception ex)
                        {
                            log.Debug(ex);
                        }

                        if (_viewerParser != null)
                        {
                            _viewerParser.Cleanup();
                        }

                        DisableControls();
                        IsConnected = false;
                        _camera = null;

                        // Clear references to the underlying DXImageDrawingWindow so that it can be freely cleaned up
                        m_drawingWindow.Children.Clear();
                        _drawingControl = null;
                        _DXDrawingWindow = null;

                        base.Disconnect();
                    });
                }
            }

            public void SetRenderingMethod(bool GPURenderingEnabled)
            {
                if (_drawingControl != null)
                {
                    _drawingControl.SetRenderingMethod(GPURenderingEnabled);
                }
            }

            private void InitializeControls(bool BeginAcquisition)
            {
                btn_Start.IsEnabled = !BeginAcquisition;
                btn_Snap.IsEnabled = !BeginAcquisition;
                btn_Stop.IsEnabled = BeginAcquisition;
                btn_zoomin.IsEnabled = BeginAcquisition;
                btn_zoomout.IsEnabled = BeginAcquisition;
                btn_loupe_tool.IsEnabled = BeginAcquisition;
                btn_Save.IsEnabled = BeginAcquisition && _drawingControl.GetImageHoldingStatus();
                btn_OptimizeFrameRate.IsEnabled = !BeginAcquisition;
                btn_Shading.IsEnabled = _drawingControl.GetShadingAvailability();
                btn_Recorder.IsEnabled = !BeginAcquisition;
                btn_2D_view.IsEnabled = !BeginAcquisition;
                btn_3D_view.IsEnabled = !BeginAcquisition;
            }
#endregion

#region UI_Event_Handlers

            public void doStart()
            {
                if (!_initializing)
                {
                    try
                    {
                        _drawingControl.Start();

                        _isGrabbingImages = true;
                        btn_Snap.IsEnabled = false;
                        btn_Start.IsEnabled = false;
                        btn_Stop.IsEnabled = true;
                        btn_Save.IsEnabled = true;
                        btn_zoomin.IsEnabled = true;
                        btn_zoomout.IsEnabled = true;
                        btn_loupe_tool.IsEnabled = !_DXDrawingWindow.Enable3DView;
                        btn_OptimizeFrameRate.IsEnabled = false;
                    }
                    catch (Exception ex)
                    {
                        btn_Snap.IsEnabled = true;
                        btn_Start.IsEnabled = true;
                        btn_Stop.IsEnabled = false;
                        btn_zoomin.IsEnabled = false;
                        btn_zoomout.IsEnabled = false;
                        btn_loupe_tool.IsEnabled = false;
                        btn_Save.IsEnabled = false;
                        btn_OptimizeFrameRate.IsEnabled = true;

                        if (ex.GetType() == typeof(SpinnakerException))
                        {
                            SpinnakerException spinEx = (SpinnakerException)ex;

                            if (spinEx.ErrorCode == Error.SPINNAKER_ERR_INVALID_BUFFER)
                            {
                                System.Windows.Forms.MessageBox.Show(
                                    ex.Message.ToString(),
                                    "Invalid Buffer",
                                    System.Windows.Forms.MessageBoxButtons.OK,
                                    System.Windows.Forms.MessageBoxIcon.Error);
                            }
                            else if (spinEx.ErrorCode == Error.SPINNAKER_ERR_OUT_OF_MEMORY)
                            {
                                System.Windows.Forms.MessageBox.Show(
                                    ex.Message.ToString(),
                                    "Out of Memory",
                                    System.Windows.Forms.MessageBoxButtons.OK,
                                    System.Windows.Forms.MessageBoxIcon.Error);
                            }
                            else
                            {
                                // Re-throw unexpected Spinnaker exception
                                throw;
                            }
                        }
                        else
                        {
                            // Re-throw exception
                            throw;
                        }
                    }
                }
            }

            private void btn_Start_Click(object sender, RoutedEventArgs e)
            {
                doStart();
                AnalyticsEventLog(
                    analytics,
                    AnalyticsEventCategory,
                    "Play",
                    "",
                    (_camera != null && _camera.DeviceModelName.IsReadable) ? "N/A" : _camera.DeviceModelName);
            }

            public void setSnapState(bool isOn)
            {
                if (isOn)
                {
                    btn_Snap.Checked -= new RoutedEventHandler(btn_Snap_Click);
                    btn_Snap.IsHitTestVisible = false;
                    btn_Snap.IsEnabled = false;
                    btn_Start.IsEnabled = false;
                    btn_Stop.IsEnabled = true;
                    btn_zoomin.IsEnabled = true;
                    btn_zoomout.IsEnabled = true;
                    btn_loupe_tool.IsEnabled = true;
                    btn_Save.IsEnabled = false;
                    btn_OptimizeFrameRate.IsEnabled = false;
                }
                else
                {
                    btn_Snap.Checked += new RoutedEventHandler(btn_Snap_Click);
                    btn_Snap.IsHitTestVisible = true;
                    btn_Snap.IsEnabled = true;
                    btn_Snap.IsChecked = false;
                    btn_Start.IsEnabled = true;
                    btn_Stop.IsEnabled = false;
                    btn_Save.IsEnabled = true;
                    btn_loupe_tool.IsEnabled = true;
                    btn_OptimizeFrameRate.IsEnabled = true;
                }
            }

            private void btn_Snap_Click(object sender, RoutedEventArgs e)
            {
                if (btn_Snap.IsEnabled)
                {
                    setSnapState(true);
                    _drawingControl.Snap();

                    AnalyticsEventLog(
                        analytics,
                        AnalyticsEventCategory,
                        "Snap",
                        "",
                        (_camera != null && _camera.DeviceModelName.IsReadable) ? _camera.DeviceModelName : "N/A");
                }
            }

            public void doStop()
            {
                // Make sure camera has been set and initializing stage has been passed
                if (_camera != null && !_initializing)
                {
                    // Disable loupe tool before we dispatch our closing thread
                    if (Dispatcher.CheckAccess())
                    {
                        try
                        {
                            _isGrabbingImages = false;

                            if (_drawingControl != null)
                            {
                                _drawingControl.Stop();
                            }

                            // Reset error text
                            OnUpdateErrorText(string.Empty);

                            // Check whether we are holding image in drawing control
                            if (_drawingControl != null && _drawingControl.GetImageHoldingStatus())
                            {
                                btn_Save.IsEnabled = true;
                            }
                            else
                            {
                                btn_Save.IsEnabled = false;
                            }

                            if (btn_loupe_tool.IsChecked.Equals(true))
                            {
                                _drawingControl.ToggleLoupeTool();
                            }
                        }
                        catch (Exception ex)
                        {
                            log.Debug(string.Format("doStop with dispatch exception: {0}", ex));
                        }
                    }
                    else
                    {
                        this.Dispatcher.Invoke(DispatcherPriority.Normal, (System.Threading.ThreadStart)delegate ()
                        {
                            try
                            {
                                _isGrabbingImages = false;

                                _drawingControl.Stop();

                                // Reset error text
                                OnUpdateErrorText(string.Empty);

                                // Check whether we are holding image in drawing control
                                if (_drawingControl != null && _drawingControl.GetImageHoldingStatus())
                                {
                                    btn_Save.IsEnabled = true;
                                }
                                else
                                {
                                    btn_Save.IsEnabled = false;
                                }

                                if (btn_loupe_tool.IsChecked.Equals(true))
                                {
                                    _drawingControl.ToggleLoupeTool();
                                }
                            }
                            catch (Exception ex)
                            {
                                log.Debug(string.Format("doStop exception, camera not valid: {0}", ex));
                            }
                        });
                    }
                }
            }

            private void btn_Stop_Click(object sender, RoutedEventArgs e)
            {
                doStop();
                AnalyticsEventLog(
                    analytics,
                    AnalyticsEventCategory,
                    "Stop",
                    "",
                    (_camera != null && _camera.DeviceModelName.IsReadable) ? _camera.DeviceModelName : "N/A");
            }

            private void btn_Histogram_Click(object sender, RoutedEventArgs e)
            {

                if (_camera != null && !_initializing)
                {
                    _drawingControl.ToggleHistogramWindow();
                    AnalyticsEventLog(
                        analytics,
                        AnalyticsEventCategory,
                        "Histogram Toggle",
                        "",
                        (_camera.DeviceModelName.IsReadable) ? _camera.DeviceModelName : "");
                }
                else
                {
                    _drawingControl.ToggleHistogramWindow();
                }
            }

            private void btn_OptimizeFrameRate_Click(object sender, RoutedEventArgs e)
            {
                var dlgResult = MessageBox.Show(
                    string.Format(
                        "This will overwrite these settings of the camera:{0}" + "ADC Bit Depth,{0}" +
                            "Acquisition FrameRate Enable,{0}" + "Exposure Auto,{0}" + "Exposure Mode,{0}" +
                            "Exposure Time,{0}" + "Pixel Format,{0}" + "SCPS Packet Size (if GigE).{0}" +
                            "Gain Auto,{0}" + "Balance White Auto,{0}" + "{0}Continue?",
                        Environment.NewLine),
                    "Optimizing Frame Rate",
                    MessageBoxButton.YesNo,
                    MessageBoxImage.Information);

                if (dlgResult != MessageBoxResult.Yes)
                {
                    return;
                }

                if (_camera == null || _initializing)
                {
                    MessageBox.Show(
                        "The camera is initiliazing or does not exist.",
                        "Aborting",
                        MessageBoxButton.OK,
                        MessageBoxImage.Error);
                    return;
                }

                if (_camera.IsInitialized() == false)
                {
                    MessageBox.Show(
                        "The camera is not initialized.", "Aborting", MessageBoxButton.OK, MessageBoxImage.Error);
                    return;
                }

                INodeMap map;

                try
                {
                    map = _camera.GetNodeMap();
                }
                catch
                {
                    MessageBox.Show(
                        "A problem occured while trying to get the node map from the camera",
                        "Failed to Retrieve the NodeMap",
                        MessageBoxButton.OK,
                        MessageBoxImage.Error);
                    return;
                }

                AnalyticsEventLog(
                    analytics,
                    AnalyticsEventCategory,
                    "FPS Optimize",
                    "",
                    (_camera.DeviceModelName.IsReadable) ? _camera.DeviceModelName : "N/A");

                string nodeChangeErrorString = FormattedSerialNumber + "Couldn't set {0} node to {1}";

                if (_camera.AdcBitDepth != null && _camera.AdcBitDepth.IsReadable && _camera.AdcBitDepth.IsWritable)
                {
                    string[] adcBitDepthSymbolics = _camera.AdcBitDepth.Symbolics;
                    string targetAdcBitDepth = "Unknown value";

                    try
                    {
                        targetAdcBitDepth =
                            _camera.AdcBitDepth.GetEntryByName(adcBitDepthSymbolics[0]).Value.ToString();
                        _camera.AdcBitDepth.Value = _camera.AdcBitDepth.GetEntryByName(adcBitDepthSymbolics[0]).Value;
                    }
                    catch
                    {
                        log.Debug(string.Format(nodeChangeErrorString, "AdcBitDepth", targetAdcBitDepth));
                    }
                }
                else
                {
                    log.Debug(string.Format(nodeChangeErrorString, "AdcBitDepth", "lowest available bit depth"));
                }

                uint desiredGevSCPSPacketSize = 0;

                if (_camera.GevSCPSPacketSize != null && _camera.GevSCPSPacketSize.IsWritable)
                {
                    try
                    {

                        desiredGevSCPSPacketSize = _camera.DiscoverMaxPacketSize();
                        _camera.GevSCPSPacketSize.Value = desiredGevSCPSPacketSize;
                    }
                    catch
                    {
                        log.Debug(string.Format(nodeChangeErrorString, "GevSCPSPacketSize", desiredGevSCPSPacketSize));
                    }
                }
                else
                {
                    log.Debug(
                        string.Format(nodeChangeErrorString, "GevSCPSPacketSize", "max discoverable packet size"));
                }

                if (_camera.PixelFormat != null && _camera.PixelFormat.IsReadable && _camera.PixelFormat.IsWritable)
                {
                    EnumValue desiredPixelFormat;
                    string[] pixelFormatSymbolics = _camera.PixelFormat.Symbolics;

                    if (pixelFormatSymbolics.Contains("BayerRG8"))
                    {
                        desiredPixelFormat = _camera.PixelFormat.GetEntryByName("BayerRG8").Value;
                        desiredPixelFormat.String = "BayerRG8";
                    }
                    else if (pixelFormatSymbolics.Contains("Mono8"))
                    {
                        desiredPixelFormat = _camera.PixelFormat.GetEntryByName("Mono8").Value;
                        desiredPixelFormat.String = "Mono8";
                    }
                    else
                    {
                        desiredPixelFormat = new EnumValue("");
                        log.Debug(string.Format(
                            "{0}BayerRG8 and Mono8 are not available pixel formats", FormattedSerialNumber));
                    }

                    try
                    {
                        if (desiredPixelFormat.String != "")
                        {
                            _camera.PixelFormat.Value = desiredPixelFormat;
                        }
                    }
                    catch
                    {
                        log.Debug(string.Format(nodeChangeErrorString, "PixelFormat", desiredPixelFormat.String));
                    }
                }
                else
                {
                    log.Debug(string.Format(nodeChangeErrorString, "PixelFormat", "BayerRG8 or Mono8"));
                }

                if (_camera.GainAuto != null && _camera.GainAuto.IsWritable)
                {
                    try
                    {

                        EnumValue desiredGainAutoSetting = new EnumValue("Off");
                        _camera.GainAuto.Value = desiredGainAutoSetting;
                    }
                    catch
                    {
                        log.Debug(string.Format(nodeChangeErrorString, "GainAuto", "Off"));
                    }
                }
                else
                {
                    log.Debug(string.Format(nodeChangeErrorString, "GainAuto", "Off"));
                }

                if (_camera.BalanceWhiteAuto != null && _camera.BalanceWhiteAuto.IsWritable)
                {
                    EnumValue desiredBalanceWhiteAutoSetting = new EnumValue("Off");
                    try
                    {
                        _camera.BalanceWhiteAuto.Value = desiredBalanceWhiteAutoSetting;
                    }
                    catch
                    {
                        log.Debug(string.Format(nodeChangeErrorString, "BalanceWhiteAuto", "Off"));
                    }
                }
                else
                {
                    log.Debug(string.Format(nodeChangeErrorString, "BalanceWhiteAuto", "Off"));
                }

                if (_camera.ExposureAuto != null && _camera.ExposureAuto.IsWritable)
                {
                    EnumValue desiredExposureAutoSetting = new EnumValue("Off");

                    try
                    {
                        _camera.ExposureAuto.Value = desiredExposureAutoSetting;
                    }
                    catch
                    {
                        log.Debug(string.Format(nodeChangeErrorString, "ExposureAuto", "Off"));
                    }
                }
                else
                {
                    log.Debug(string.Format(nodeChangeErrorString, "ExposureAuto", "Off"));
                }

                if (_camera.ExposureMode != null && _camera.ExposureMode.IsWritable)
                {
                    EnumValue desiredExposureModeSetting = new EnumValue("Timed");

                    try
                    {
                        _camera.ExposureMode.Value = desiredExposureModeSetting;
                    }
                    catch
                    {
                        log.Debug(string.Format(nodeChangeErrorString, "ExposureMode", "Timed"));
                    }
                }
                else
                {
                    log.Debug(string.Format(nodeChangeErrorString, "ExposureMode", "Timed"));
                }

                // Turn AcquisitionFrameRateEnable on so that we could read the desired AcquisitionFrameRate (Required
                // for some cameras)
                if (_camera.AcquisitionFrameRateEnable != null && _camera.AcquisitionFrameRateEnable.IsWritable)
                {
                    try
                    {
                        _camera.AcquisitionFrameRateEnable.Value = true;
                    }
                    catch
                    {
                        log.Debug(string.Format(nodeChangeErrorString, "AcquisitionFrameRateEnable", "true"));
                    }
                }
                else
                {
                    log.Debug(string.Format(nodeChangeErrorString, "AcquisitionFrameRateEnable", "true"));
                }

                // Fetch desired frame rate
                double desiredFrameRate = 0.0;
                if (_camera.AcquisitionFrameRate != null && _camera.AcquisitionFrameRate.IsReadable)
                {
                    if (_camera.ExposureTime != null && _camera.ExposureTime.IsWritable)
                    {
                        _camera.ExposureTime.Value = _camera.ExposureTime.Min;
                    }

                    desiredFrameRate = _camera.AcquisitionFrameRate.Max;
                }
                else
                {
                    log.Debug(
                        "AcquisitionFrameRate is not available or not readable for determining a desired frame rate");
                }

                // Disable AcquisitionFrameRateEnable
                if (_camera.AcquisitionFrameRateEnable != null && _camera.AcquisitionFrameRateEnable.IsWritable)
                {
                    try
                    {
                        _camera.AcquisitionFrameRateEnable.Value = false;
                    }
                    catch
                    {
                        log.Debug(string.Format(nodeChangeErrorString, "AcquisitionFrameRateEnable", "false"));
                    }
                }
                else
                {
                    log.Debug(string.Format(nodeChangeErrorString, "AcquisitionFrameRateEnable", "false"));
                }

                if (_camera.ExposureTime != null && _camera.ExposureTime.IsWritable && desiredFrameRate != 0.0)
                {
                    double desiredExposureTime = 1000000.0 / desiredFrameRate;

                    try
                    {
                        _camera.ExposureTime.Value = desiredExposureTime;
                    }
                    catch
                    {
                        log.Debug(string.Format(nodeChangeErrorString, "ExposureTime", desiredExposureTime));
                    }

                    // Lower the exposure time in order to match Acquisition Resulting Frame Rate to Acquisition Frame
                    // Rate
                    int loop_count = 0;
                    try
                    {
                        while (Math.Abs(_camera.AcquisitionFrameRate - _camera.AcquisitionResultingFrameRate) >= 0.01)
                        {
                            if (loop_count > 100)
                            {
                                log.Debug(string.Format(
                                    "{0}Too many iterations to increase Acquisition Resulting Frame Rate",
                                    FormattedSerialNumber));
                                _camera.ExposureTime.Value = _camera.ExposureTime.Min;

                                break;
                            }

                            desiredExposureTime = 0.96 * _camera.ExposureTime.Value;
                            _camera.ExposureTime.Value = desiredExposureTime;

                            loop_count++;
                        }
                    }
                    catch
                    {
                        log.Debug(string.Format(
                            nodeChangeErrorString,
                            "ExposureTime",
                            "match AcquisitionFrameRate with AcquisitionResultingFrameRate"));
                    }
                }
                else
                {
                    log.Debug(string.Format(
                        nodeChangeErrorString,
                        "ExposureTime",
                        "match AcquisitionFrameRate with AcquisitionResultingFrameRate"));
                }
            }

            private void btn_Recorder_Click(object sender, RoutedEventArgs e)
            {
                if (_camera != null && !_initializing)
                {
                    _drawingControl.ToggleRecordingWindow();

                    AnalyticsEventLog(
                        analytics,
                        AnalyticsEventCategory,
                        "Recording Toggle",
                        "",
                        (_camera.DeviceModelName.IsReadable) ? _camera.DeviceModelName : "N/A");
                }
            }

            private void btn_zoomIn_Click(object sender, RoutedEventArgs e)
            {
                if (!_initializing)
                {
                    if (_DXDrawingWindow.StretchToFitEnable)
                    {
                        // Let stretch-to-fit know we're disabling it using zoom
                        _DXDrawingWindow.SetZoomStretchToFit(true);
                        // Disable stretch-to-fit if user tries to zoom manually
                        _DXDrawingWindow.m_dp_contextmenu_stretch.IsChecked = false;
                    }

                    _drawingControl.ZoomIn();

                    string cameraModel = (_camera != null) ? (_camera.DeviceModelName.IsReadable ? _camera.DeviceModelName : "N/A") : "N/A";
                    AnalyticsEventLog(
                        analytics,
                        AnalyticsEventCategory,
                        "Zoom In",
                        "",
                        cameraModel);
                }
            }

            private void btn_zoomOut_Click(object sender, RoutedEventArgs e)
            {
                if (!_initializing)
                {
                    if (_DXDrawingWindow.StretchToFitEnable)
                    {
                        // Let stretch-to-fit know we're disabling it using zoom
                        _DXDrawingWindow.SetZoomStretchToFit(false);
                        // Disable stretch-to-fit if user tries to zoom manually
                        _DXDrawingWindow.m_dp_contextmenu_stretch.IsChecked = false;
                    }

                    _drawingControl.ZoomOut();

                    string cameraModel = (_camera != null) ? (_camera.DeviceModelName.IsReadable ? _camera.DeviceModelName : "N/A") : "N/A";
                    AnalyticsEventLog(
                        analytics,
                        AnalyticsEventCategory,
                        "Zoom Out",
                        "",
                        cameraModel);
                }
            }

            private void btn_loupe_Click(object sender, RoutedEventArgs e)
            {
                if (!_initializing)
                {
                    _drawingControl.ToggleLoupeTool();

                    string cameraModel = (_camera != null) ? (_camera.DeviceModelName.IsReadable ? _camera.DeviceModelName : "N/A") : "N/A";
                    AnalyticsEventLog(
                        analytics,
                        AnalyticsEventCategory,
                        "Loupe Toggle",
                        "",
                        cameraModel);
                }
            }

            private void ToolBar_SizeChanged(object sender, SizeChangedEventArgs e)
            {
                ToolBar toolBar = sender as ToolBar;
                var overflowGrid = toolBar.Template.FindName("OverflowGrid", toolBar) as FrameworkElement;
                if (overflowGrid != null)
                {
                    overflowGrid.Visibility = toolBar.HasOverflowItems ? Visibility.Visible : Visibility.Collapsed;
                }

                var mainPanelBorder = toolBar.Template.FindName("MainPanelBorder", toolBar) as FrameworkElement;
                if (mainPanelBorder != null)
                {
                    var defaultMargin = new Thickness(0, 0, 11, 0);
                    mainPanelBorder.Margin = toolBar.HasOverflowItems ? defaultMargin : new Thickness(0);
                }
            }

#endregion

#region ICAMERACONTROL
            public override string GetNodeToControl()
            {
                return string.Empty;
            }

            public override void Connect(INodeMap nodemap, string nodename = "", string namelabel = "")
            {
                throw new NotImplementedException(
                    "See \"public bool Connect(ManagedCamera camera, IManagedInterface parentInterface, NodeMap map = null, bool BeginAcquisition = true)\"");
            }

            public override void SetNameLabelBoldness(bool status)
            {
                // Not applicable
            }

            public override void SetToolTip(string tooltip)
            {
                // Not applicable
            }

            public override void SetControlNameLabel(string nameLabel)
            {
                // Not applicable
            }

            public override void SetNameLabelVisibility(System.Windows.Visibility visibility)
            {
                // Not applicable
            }

            public override void SetRefreshTime(int seconds)
            {
                // Not applicable
            }

            public override void Refresh()
            {
                // Not applicable
            }

            public override string GetControlNameLabel()
            {
                return string.Empty;
            }

            public override System.Windows.Visibility GetNameLabelVisibility()
            {
                return this.Visibility;
            }

            public IManagedCamera GetConnectedDevice()
            {
                return _camera;
            }
#endregion

            private void btn_Save_Click(object sender, RoutedEventArgs e)
            {
                if (!_initializing)
                {
                    if (!_DXDrawingWindow.Enable3DView)
                    {
                        _drawingControl.SaveImage();
                    }
                    else
                    {
                        _drawingControl.Save3DData();
                    }

                    if (_camera != null)
                    {
                        AnalyticsEventLog(
                            analytics,
                            AnalyticsEventCategory,
                            "Save Image",
                            "",
                            (_camera.DeviceModelName.IsReadable) ? _camera.DeviceModelName : "N/A");
                    }
                    else
                    {
                        AnalyticsEventLog(
                            analytics,
                            AnalyticsEventCategory,
                            "Save Image",
                            "",
                            "N/A");
                    }
                }
            }

            private void btn_Shading_Click(object sender, RoutedEventArgs e)
            {
                if (_camera != null && !_initializing)
                {
                    _drawingControl.ToggleShadingWindow();
                    _drawingControl.ToggleHistogramWindow();

                    AnalyticsEventLog(
                        analytics,
                        AnalyticsEventCategory,
                        "Shading Toggle",
                        "",
                        (_camera.DeviceModelName.IsReadable) ? _camera.DeviceModelName : "N/A");
                }
            }

            private void btn_ColorCorrection_Click(object sender, RoutedEventArgs e)
            {
                if (!_initializing)
                {
                    _drawingControl.ToggleColorCorrectionWindow();

                    string cameraModel = (_camera != null) ? (_camera.DeviceModelName.IsReadable ? _camera.DeviceModelName : "N/A") : "N/A";
                    AnalyticsEventLog(
                        analytics,
                        AnalyticsEventCategory,
                        "Color Correction Toggle",
                        "",
                        cameraModel);
                }
            }
            private void btn_ColorProcessing_Click(object sender, RoutedEventArgs e)
            {
                if (!_initializing)
                {
                    _drawingControl.ToggleColorProcessingWindow();
                    string cameraModel = (_camera != null) ? (_camera.DeviceModelName.IsReadable ? _camera.DeviceModelName : "N/A") : "N/A";
                    AnalyticsEventLog(
                            analytics,
                            AnalyticsEventCategory,
                            "Color Processing Toggle",
                            "",
                            cameraModel);
                }
            }

            private void btn_2DView_Click(object sender, RoutedEventArgs e)
            {
                if (!_initializing)
                {
                    _drawingControl.ToggleViewDimension();

                    btn_Histogram.IsEnabled = true;
                    btn_Shading.IsEnabled = _drawingControl.GetShadingAvailability();
                    btn_2D_view.IsEnabled = false;
                    btn_3D_view.IsEnabled = true;

                    if (_camera != null)
                    {
                        if (IsStreaming())
                        {
                            btn_loupe_tool.IsEnabled = true;
                        }

                        if (ManagedImageUtilityStereo.IsStereoCamera(_camera))
                        {
                            btn_Save.ToolTip = "Save current image list to disk";
                        }
                        else
                        {
                            btn_Save.ToolTip = "Save current image to disk";
                        }

                        AnalyticsEventLog(
                            analytics,
                            AnalyticsEventCategory,
                            "2D View enable",
                            "",
                            (_camera.DeviceModelName.IsReadable) ? _camera.DeviceModelName : "N/A");
                    }
                    else
                    {
                        if (IsStereoCamera)
                        {
                            btn_Save.ToolTip = "Save current image list to disk";
                        }
                        else
                        {
                            btn_Save.ToolTip = "Save current image to disk";
                        }

                        AnalyticsEventLog(
                            analytics,
                            AnalyticsEventCategory,
                            "2D View enable",
                            "",
                            "N/A");
                    }
                }
            }

            private void btn_3DView_Click(object sender, RoutedEventArgs e)
            {
                if (!_initializing)
                {
                    _drawingControl.ToggleViewDimension();

                    btn_loupe_tool.IsEnabled = false;
                    btn_Histogram.IsEnabled = false;
                    btn_Shading.IsEnabled = false;
                    btn_Save.ToolTip = "Save current 3D data to disk";
                    btn_2D_view.IsEnabled = true;
                    btn_3D_view.IsEnabled = false;

                    if (_camera != null)
                    {
                        AnalyticsEventLog(
                            analytics,
                            AnalyticsEventCategory,
                            "3D View enable",
                            "",
                            (_camera.DeviceModelName.IsReadable) ? _camera.DeviceModelName : "N/A");
                    }
                    else
                    {
                        AnalyticsEventLog(
                            analytics,
                            AnalyticsEventCategory,
                            "3D View enable",
                            "",
                            "N/A");
                    }
                }
            }
        }


        public enum RotationAngle
        {
            [XmlEnum(Name = "0")] _0,
            [XmlEnum(Name = "90")] _90,
            [XmlEnum(Name = "180")] _180,
            [XmlEnum(Name = "270")] _270
        }
    }
}