Announcement

Collapse

Looking for a User App or Add-On built by the NinjaTrader community?

Visit NinjaTrader EcoSystem and our free User App Share!

Have a question for the NinjaScript developer community? Open a new thread in our NinjaScript File Sharing Discussion Forum!
See more
See less

Partner 728x90

Collapse

Error when trying to create a new window/tab Addon

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Error when trying to create a new window/tab Addon

    Hello friends.

    I've been following the documentation here: https://ninjatrader.com/support/help...development_ov erview.htm

    I'm at a point where I get this error when I click on my menu item in the "New" section: (see attached).

    This is the AddOn:

    Code:
    #region Using declarations
    using System;
    using NinjaTrader.Gui.Tools;
    using System.Windows;
    using NinjaTrader.Gui;
    using System.Windows.Controls;
    using System.Xml.Linq;
    using System.Windows.Media;
    #endregion
    
    //This namespace holds Add ons in this folder and is required. Do not change it.
    namespace NinjaTrader.NinjaScript.AddOns
    {
    
        public class MyCustomAddOn : AddOnBase
        {
            // menu stuff
            private NTMenuItem MenuItem;
            private NTMenuItem ControlCenterNewMenu;
            protected override void OnStateChange()
            {
                if (State == State.SetDefaults)
                {
                    Description = @"Enter the description for your new custom Add on here.";
                    Name = "CustomeAddOn";
    
                }
                else if (State == State.Configure)
                {
    
                }
                else if (State == State.DataLoaded)
                {
    
                }
                else if (State == State.Terminated)
                {  
                }
            }
    
            protected override void OnWindowCreated(Window window)
            {
                // We want to place the menu item for the AddOn in the Control Center's "New" menu
                // First obtain a reference to the Control Center window
                ControlCenter cc = window as ControlCenter;
                if (cc == null)
                    return;
    
                /* Determine we want to place the AddOn in the Control Center's "New" menu
                 Other menus can be accessed via the control's "Automation ID". For example: toolsMenuItem, workspacesMenuItem,      connectionsMenuItem, helpMenuItem. */
                ControlCenterNewMenu = cc.FindFirst("ControlCenterMenuItemNew") as NTMenuItem;
                if (ControlCenterNewMenu == null) return;
    
                // 'Header' sets the name of our AddOn seen in the menu structure
                MenuItem = new NTMenuItem { Header = "Custom Addon", Style = Application.Current.TryFindResource("MainMenuItem") as Style };
    
                // Add our AddOn into the "New" menu
                ControlCenterNewMenu.Items.Add(MenuItem);
    
                MenuItem.Click += OnMenuItemClick;
            }
    
            private void OnMenuItemClick(object sender, EventArgs e)
            {
                Core.Globals.RandomDispatcher.BeginInvoke(new Action(() => new ExporterWindow().Show()));
            }
    
            // Class for Window management
            // create a NT8 window with the name StableMetricsWindow
            // this window will be used to display the prometheus URL
            public class ExporterWindow : NTWindow
            {
                public ExporterWindow()
                {
                    Caption = "Custom Addon Window";
                    Width = 800;
                    Height = 600;
    
                    TabControl tc = new TabControl();
    
                    // Attached properties defined in TabControlManager class should be set to achieve tab moving, adding/removing tabs
                    //TabControlManager.SetIsMovable(tc, true);
                    //TabControlManager.SetCanAddTabs(tc, true);
                    //TabControlManager.SetCanRemoveTabs(tc, true);
    
                    // if ability to add new tabs is desired, TabControl has to have attached property "Factory" set.
                    TabControlManager.SetFactory(tc, new AddOnFrameworkWindowFactory());
    
                    Content = tc;
    
                    /* In order to have link buttons functionality, tab control items must be derived from Tools.NTTabPage
                    They can be added using extension method AddNTTabPage(NTTabPage page) */
                    tc.AddNTTabPage(new AddOnFrameworkTab());
                }
            }
    
            /* Class which implements Tools.INTTabFactory must be created and set as an attached property for TabControl
            in order to use tab page add/remove/move/duplicate functionality */
            public class AddOnFrameworkWindowFactory : INTTabFactory
            {
                // INTTabFactory member. Required to create parent window
                public NTWindow CreateParentWindow()
                {
                    return new ExporterWindow();
                }
    
                // INTTabFactory member. Required to create tabs
                public NTTabPage CreateTabPage(string typeName, bool isTrue)
                {
                    return new AddOnPage();
                }
            }
    
            public class AddOnFrameworkTab : NTTabPage
            {
                public AddOnFrameworkTab()
                {
    
                    AddOnFrameworkWindowFactory myAddOnFrameworkWindowFactory = new AddOnFrameworkWindowFactory();
    
    
                    Content = myAddOnFrameworkWindowFactory.CreateTabPage("AddOnPage", true);
                }
    
                // implement a basic save
                protected override void Save(XElement element)
                {
                    // Save the tab page
                    if (element == null)
                        return;
                }
    
                // implement a basic restore
                protected override void Restore(XElement element)
                {
                    // Restore the tab page
                    if (element == null)
                        return;
                }
    
                // implement a basic GetHeaderPart
                protected override string GetHeaderPart(string header)
                {
                    return "AddOnTab";
                }
            }
    
            public class AddOnPage : NTTabPage
            {
                public AddOnPage()
                {
                    // create the parent window
    
                    Grid grid = new Grid();
                    grid.Background = new SolidColorBrush(Colors.Transparent);
    
                    ColumnDefinition col1 = new ColumnDefinition();
                    // bug in the NT documentation, missing a space here
                    col1.Width = new GridLength(55);
    
                    ColumnDefinition col2 = new ColumnDefinition();
                    // bug in the NT documentation, missing a space here
                    col2.Width = new GridLength(45);
    
                    grid.ColumnDefinitions.Add(col1);
                    grid.ColumnDefinitions.Add(col2);
    
                    // Create a textblock to display the prometheus URL
                    TextBlock textBlock = new TextBlock();
                    textBlock.Text = "Some Text: ";
                }
    
                // implement a basic save
                protected override void Save(XElement element)
                {
                    // Save the tab page
                    if (element == null)
                        return;
                }
    
                // implement a basic restore
                protected override void Restore(XElement element)
                {
                    // Restore the tab page
                    if (element == null)
                        return;
                }
    
                // implement a basic GetHeaderPart
                protected override string GetHeaderPart(string header)
                {
                    return "AddOnTab";
                }
            }
    
            // Will be called as a new NTWindow is destroyed. It will be called in the thread of that window
            protected override void OnWindowDestroyed(Window window)
            {
                if (MenuItem != null && window is ControlCenter)
                {
                    if (ControlCenterNewMenu != null && ControlCenterNewMenu.Items.Contains(MenuItem))
                        ControlCenterNewMenu.Items.Remove(MenuItem);
    
                    MenuItem.Click -= OnMenuItemClick;
                    MenuItem = null;
                }
            }
        }
    }
    ​
    I've search for "name" and "+" in my code to try to float something up, but nothing relevant comes up.

    I'm not using a XAML file. I'm opting to do everting in code. I don't care about persistence in the workspace, so took that out as well. The tab would be simple, so took out the create, move, delete options from TabControl.

    Google searched point to XML errors and such. I'm VERY much not a UI / FrontEnd sort of person, so all lot of this is a bit new and overwhelming.

    Cheers!
    Last edited by scouratier; 02-27-2024, 10:33 AM.

    #2
    Hello scouratier,

    Below is a link to a simplified example you can use as a starting point.


    The ExporterWindow, NTTabpage, AddonPage classes should not be nested within another class.
    Use RandomDispatcher.InvokeAsync instead of .BeginInvoke.

    I've made those changes, and changed the initial tab to be AddOnPage(Modified) and have found the window opens as expected.
    Attached is the script exported.

    Generating the UI with code instead of a xaml file is fine to do.
    Attached Files
    Chelsea B.NinjaTrader Customer Service

    Comment


      #3
      Chealsea!

      Thanks, that worked.

      In terms of generating ui with code, I'm not finding a whole lot of documentation on NT docs. But can you confirm this is standard WPF stuff, and I can just use existing docs for WPF to do what I need?

      Cheers!

      S.

      Comment


        #4
        Hello scouratier,

        The NinjaTrader UI is WPF.

        Making a custom addon window is possible, but is largely undocumented.

        There are a few examples of modifying WPF.


        Chelsea B.NinjaTrader Customer Service

        Comment

        Latest Posts

        Collapse

        Topics Statistics Last Post
        Started by algospoke, Today, 06:40 PM
        0 responses
        2 views
        0 likes
        Last Post algospoke  
        Started by maybeimnotrader, Today, 05:46 PM
        0 responses
        6 views
        0 likes
        Last Post maybeimnotrader  
        Started by quantismo, Today, 05:13 PM
        0 responses
        6 views
        0 likes
        Last Post quantismo  
        Started by AttiM, 02-14-2024, 05:20 PM
        8 responses
        168 views
        0 likes
        Last Post jeronymite  
        Started by cre8able, Today, 04:22 PM
        0 responses
        8 views
        0 likes
        Last Post cre8able  
        Working...
        X