TronListView: A ListView type library with fuller features.

The TronControlLibrary contains one main control called TronListView. This is a DLL compatible with Visual Studio 2019 and later. This control offers enhanced ListView behaviour comprised primarily of embedded objects. The usual mode is to have each cell in a column containing the same control, such as a textbox, checkbox or combobox. Data is read or written to the embedded control from the listview items and subitems in text form for simplicity. This occurs when the control is modified by the user.

So why did I write TronListView?

  • I used ObjectListView until I released that it had a viral agreement requirement to disclose source code. The other problem with it was that they don’t let you edit the model, which prevents programmatic changes to values in cells. If you change these they inexplicably change back after a few seconds. That is an obvious requirement for a programmer and not some unexpected or invalid requirement.
  • I tried some commercial alternatives to ObjectListView and I found that in addition to being very expensive, that some of these were unstable or contained bugs.

TronControlLibrary/TronListView has a suggested donation of $120NZ for developers for the first year, then $60NZ for developers for subsequent years and $5NZ per end user for distribution as part of a package on a one off basis. TLV is not guaranteed to be free of bugs, however I use software based on it all of the time e.g, Microtron Remindertron.

If you wish to contribute toward the development of this software, via a donation, that would be appreciated. Make it to the following bank account: 06-0313-0252831-00 New Zealand, Microtron NZ.

Microtron has no facilities for dealing with sales tax. If that is required the transaction cannot go ahead.

TronListView is still being improved, however it can carry out many desired tasks already.

Download Microtron TronControlLibrary with Remindertron   Contains TronListView and StickCalendar DLL (Unofficial release). TronControlLibrary.dll and ClassLibraryCalendar.dll.

Free Demo of how the TLV DLL can be used:

There is also a testing code example with more graphical controls.

This software is available in USA, Australia, Japan and in Canada BC and Q. If donations are unaffected by sales tax for you, then you may make a donation if you wish.

  • TronListView allows single cell selection and focus including navigation with mouse or keys. Built in controls have been refined to allow process control.
  • There are two sets of coordinates, one sorted and one unsorted allowing easy design of data handling structures.
  • A timer is required to allow selecting and focus to work correctly. An interval of 300ms is used for that.
  • Colours are used to indicate the type of cell that is focused or selected.
  • Double click works to enter a result and to execute a cell or row.

This DLL is still under development and it seeks to find better ways of selecting subitems in databases and better layout control. The paint method is currently inefficient and collaboration on further development could be considered. A student project could also be considered. This is an opportunity to experiment with Human Computer Interaction as the DLLs have been coded from scratch (Control).

Microtron is willing to negotiate a student project with a University of Technical Institute. Software companies would also be considered. Such a project would likely include:

  • Optimising the Paint method. Presently repainting results in the program cycling through all controls and setting the position. This includes the ones not on screen. This turned out to be slow. It may be possible to work with only making the controls that leave the screen invisible and only making the ones that come onto the screen visible. More can also be done with partial Paints where over lapping windows interact. This aspect of using minimal processing could lend itself to a solution where AI is used to help write more efficient code.
  • Investigation of Human Computer Interaction into ListView type controls. In particular colour coding cells when they are on the selected line or when they are directly clicked. Also to investigate could be colour coding of some control types.
  • Another more subtle aspect was the behaviour of double click. The design includes an attempt to allow double click row selection on a control that would respond to a click differently.

There is an opportunity to lead in terms of creating user friendliness and responsiveness as I have found these key points above to help in my interactions with databases. There are a lot of colour options currently available in the TCL-TLV DLL, I expect that these would be trimmed back a bit if useful new standards are established.

As well as controlling databases, the TCL-TLV DLL is intended to assist with computers that control machines and industrial processes.

Keys

  • Enter is to store the value.
  • Escape is to revert to the original value.
  • Space is to carry out a default behaviour.
  • For NumericUpDown derivatives
    • ‘Shift cursor up’ and ‘shift page up’ increase the value, and down is similar.
    • ‘Control number pad’ increases the value.
    • ‘Control Alt number pad’ decreases the value.
    • There are two modes: one requires entry and the other is immediate. Entry can be enter key or doubleclick.
  • Arrow keys moved the cursor from cell to cell.
  • Spacebar carries out the default behaviour.
  • Doubleclick or enter writes the value to the grid. Note that an edit followed by a click elsewhere does not confirm the edit.
  • ‘Alt click’ selects a row (and focuses a cell).
  • Escape exits or reverts the control.
  • It is intended that most activities will be possible using the mouse or keys.
  • Shift F1 brings focused cell back into view.
  • Shift F2 shows the EULA.
  • MCU units with sensors and datalogging.
  • Break out boards with user interface. Suitable for datalogging and interactive function including stepper motors.
  • Break out board customizations. Sensors, stepper motors, WiFi, SD cards and Fram.
  • Design of circuit boards, including design of circuit boards that are a customization of a break out board pilot project.
  • WiFi and server collection of data. Soon there will be cellular server collection of data.







Using TronControlLibrary
These code samples show the basic operation of TronListView.
TlvItems remain unsorted when the TronListView is sorted, likewise for columns. The native items do change their order. Where possible use Tlv objects, methods and properties as this causes extra code to be executed to manage the embedded objects. This is important for maintaining the connection between the text in the listview and the text in the embedded controls. The text in the items and subitems is the data for the embedded object regardless of what type of control it is.
The public event EventHandler Accept; and public event EventHandler Cancel; trigger the reading or writing of this information.


const int column1 = 0;
const int column2 = 1;
const int column3 = 2;

private void LoadList()
{
 tronListView1.ProcessEmbeddedObjectsInColumns += ProcessEmbeddedObjectsInColumns_Method; 

 Connection conn3 = new Connection(Globals.mqConString);
 conn3.Open();

 DataSet ds3 = new DataSet();
                
 string fieldlist = " * ";

 DataAdapter adapter3 =
        new DataAdapter("Select " + fieldlist + " from websiteaddress  order by webaddressid ", conn3);
 adapter3.Fill(ds3);

 conn3.Close();

 DataTable dtable = ds3.Tables[0];


 tronListView1.TlvColumns.Add("Column 1");
 tronListView1.TlvColumns.Add("Column 2");
 tronListView1.TlvColumns.Add("Column 3");


 tronListView1.TlvColumns[column1].LvColumn.Width = 50;
 tronListView1.TlvColumns[column2].LvColumn.Width = 250;
 tronListView1.TlvColumns[column3].LvColumn.Width = 50;

 foreach (DataRow dr in dtable.Rows)
 {
                    string str = dr["column1"].ToString();
                    ListViewItem lvi = new ListViewItem { Text = str };



                    tlvi.SubItems.Add(new ListViewItem.ListViewSubItem
                    {
                        Text = dr["webaddress"].ToString()
                    });


                    ListViewItem.ListViewSubItem lvsi = new ListViewItem.ListViewSubItem
                    {
                        Text = ""
                    };                  
                    lvi.SubItems.Add(lvsi);

                    tronListView1.TlvItems.Add(lvi);
 }
}

private ITronCustomControl ProcessEmbeddedObjectsInColumns_Method(object sender, SIEventArgs e)
{
            if (e.subItemIndex == 1)
            {
                ITronCustomControl nud = new TextBoxEmbeddedControl();
                return nud;
            }

            return null;
}



public class TextBoxEmbeddedControl : TextBox, ITronCustomControl
    {
        public TextBoxEmbeddedControl()
        {
           

            
            BorderStyle = BorderStyle.None;
            

            PreviewKeyDown += TrOnKeyPreview;
            MouseDown += ActionTronMouseDown;

            if (tronListView != null)
                tronlistview = tronListView();
        }


        public void getTLVText(ListViewItem.ListViewSubItem subItem)
        {
            
            Text = subItem.Text;

        }
        public void setTLVText(ListViewItem.ListViewSubItem subItem)
        {

            
            subItem.Text = Text;

        }
        
        public event EventHandler Accept;
#pragma warning disable CS0067        
        public event TronListView.CancelEventHandler Cancel;
#pragma warning restore CS0067
        public event KeyEventHandler TronKeyDown;
        public event MouseEventHandler TronDoubleClick;
        public event EventHandler TronSpace;
        public event EventHandler TronBefore;
        public event MouseEventHandler TronMouseDown;
        public event TronListView.TronListViewEventHandler tronListView;
        TronListView tronlistview;
       


        public bool incompleteEdit
        {
            get => false;
            set { }
        }

        protected override void OnDoubleClick(EventArgs e)
        {
            MouseEventArgs mea = new MouseEventArgs(MouseButtons, 0, 0, 0, 0);
            TronDoubleClick?.Invoke(this, mea);
        }

        protected override void OnTextChanged(System.EventArgs e)
        {
            
            base.OnTextChanged(e);
          
            Accept?.Invoke(this, EventArgs.Empty);
           
        }

              

        protected void TrOnKeyPreview(Object sender, PreviewKeyDownEventArgs e)
        {            
            if ((e.Modifiers & Keys.Control) == Keys.Control || (e.Modifiers & Keys.Alt) == Keys.Alt) { return; }


            if (e.KeyCode == Keys.Tab)
            {
                KeyEventArgs kea = new KeyEventArgs(e.KeyData);
                TronKeyDown?.Invoke(this, kea);
                return;
            }
        }

        protected override void OnKeyUp(KeyEventArgs e)
        {
            if ((e.Modifiers & Keys.Control) != Keys.Control && (e.Modifiers & Keys.Alt) != Keys.Alt)
            {
                if (((e.Modifiers & Keys.Shift) == Keys.Shift && (e.KeyCode == Keys.F1 || e.KeyCode == Keys.F2))) 
                {

                    KeyEventArgs kea = new KeyEventArgs(e.KeyData);
                    TronKeyDown?.Invoke(this, kea);
                    e.Handled = true;
                    return;
                }
            }
            base.OnKeyUp(e);
        }

        protected override void OnKeyDown(KeyEventArgs e)
        {                        
            if ((e.Modifiers & Keys.Control) == Keys.Control || (e.Modifiers & Keys.Alt) == Keys.Alt) { base.OnKeyDown(e); return; }



            if ((e.Modifiers & Keys.Shift) == Keys.Shift && e.KeyCode == Keys.Left)
            {                                
            }
            else if ((e.Modifiers & Keys.Shift) == Keys.Shift && e.KeyCode == Keys.Right)
            {                
            }
            else if ((e.Modifiers & Keys.Shift) == Keys.Shift && e.KeyCode == Keys.Up)
            {                
                SelectionStart = SelectionStart + 1;
                SelectionLength = 0;
                e.Handled = true;
                return;
            }
            else if ((e.Modifiers & Keys.Shift) == Keys.Shift && e.KeyCode == Keys.Down)
            {               
                SelectionStart = SelectionStart > 0 ? SelectionStart - 1 : 0;
                SelectionLength = 0;
                e.Handled = true;
                return;
            }
            else if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down || e.KeyCode == Keys.Left || e.KeyCode == Keys.Right
                || e.KeyCode == Keys.PageUp || e.KeyCode == Keys.PageDown || e.KeyCode == Keys.Home || e.KeyCode == Keys.End)
            {
                TronKeyDown?.Invoke(this, e);
                e.Handled = true;
                return;
            }
            else if (e.KeyCode == Keys.Return)
            {
                e.SuppressKeyPress = true;
                TronKeyDown?.Invoke(this, e);
                
                e.Handled = true;
                return;
            }

            base.OnKeyDown(e);
        }

        void ActionTronMouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
        {            
            TronMouseDown?.Invoke(this, e);
        }
    }



 public class ComboBoxClickEmbeddedControl : TextBox, ITronCustomControl, ITronClickControl
    {
        public ComboBoxClickEmbeddedControl()
        {
            

            

            ReadOnly = true;

            BorderStyle = BorderStyle.None;

                   

            cc = new DescendantComboBox()
            {
                

            };

            PreviewKeyDown += TrOnKeyPreview;
            MouseDown += ActionTronMouseDown;
            cc.KeyDown += CcKeyDown;
            
            

            if (tronListView != null)
                tronlistview = tronListView();

            SetStyle(ControlStyles.StandardClick, true);
        }




        readonly Control cc;

        public event EventHandler Accept;
        
        public event TronListView.CancelEventHandler Cancel;
        public event KeyEventHandler TronKeyDown;
        public event MouseEventHandler TronDoubleClick;
        public event EventHandler TronSpace;
        public event EventHandler TronBefore;
        public event MouseEventHandler TronMouseDown;
        public event TronListView.TronListViewEventHandler tronListView;
        TronListView tronlistview;
        


        public bool incompleteEdit
        {
            get => false;
            set { }
        }

        public Control clickcontrol
        {
            get
            {
                return cc;
            }
        }



        
        bool getdoneonce = false;
        public void getTLVText(ListViewItem.ListViewSubItem subItem)
        {
            if (!getdoneonce && cc is DescendantComboBox ccdcb) { ccdcb.Accept += Accept; ccdcb.TronMouseDown += TronMouseDown; getdoneonce = true; }
            string sitxt = subItem.Text;
            Text = sitxt;
            ComboBox cbb = (ComboBox)cc;
            cbb.Text = subItem.Text;

        }
        public void setTLVText(ListViewItem.ListViewSubItem subItem)
        {
            ComboBox cbb = (ComboBox)cc;
            subItem.Text = Text = cbb.Text;
        }

        


        private void CcKeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Alt) { return; }
            if (e.KeyCode == Keys.ControlKey) { return; }
            if (e.KeyCode == Keys.ShiftKey) { return; }           
            if ((e.Modifiers & Keys.Shift) == Keys.Shift || (e.Modifiers & Keys.Control) == Keys.Control || (e.Modifiers & Keys.Alt) == Keys.Alt) { return; }

            if (e.KeyCode == Keys.Enter)
            {
                e.SuppressKeyPress = true;
                Accept?.Invoke(cc, EventArgs.Empty);

                e.Handled = true;

                return;
            }          

            if (e.KeyCode == Keys.Escape)
            {
                e.SuppressKeyPress = true;
                Cancel?.Invoke(cc, EventArgs.Empty);

                e.Handled = true;

                return;
            }

        }


        protected void TrOnKeyPreview(Object sender, PreviewKeyDownEventArgs e)
        {
            
            if ((e.Modifiers & Keys.Shift) == Keys.Shift || (e.Modifiers & Keys.Control) == Keys.Control || (e.Modifiers & Keys.Alt) == Keys.Alt) { return; }

            

            if (e.KeyCode == Keys.Tab)
            {
                KeyEventArgs kea = new KeyEventArgs(e.KeyData);
                TronKeyDown?.Invoke(this, kea);
                return;
            }
            

            if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down || e.KeyCode == Keys.Left || e.KeyCode == Keys.Right
                || e.KeyCode == Keys.PageUp || e.KeyCode == Keys.PageDown || e.KeyCode == Keys.Home || e.KeyCode == Keys.End)
            {
                KeyEventArgs kea = new KeyEventArgs(e.KeyData);
                TronKeyDown?.Invoke(this, kea);
                
                return;
            }

            if (e.KeyCode == Keys.Space)
            {
                TronSpace?.Invoke(this, EventArgs.Empty);                
                return;
            }
        }

        protected override void OnKeyUp(KeyEventArgs e)
        {
            if ((e.Modifiers & Keys.Control) != Keys.Control && (e.Modifiers & Keys.Alt) != Keys.Alt)
            {
                if (((e.Modifiers & Keys.Shift) == Keys.Shift && (e.KeyCode == Keys.F1 || e.KeyCode == Keys.F2))) 
                {

                    KeyEventArgs kea = new KeyEventArgs(e.KeyData);
                    TronKeyDown?.Invoke(this, kea);
                    e.Handled = true;
                    return;
                }
            }
            base.OnKeyUp(e);
        }

        protected override void OnKeyDown(KeyEventArgs e)
        {
            
            if ((e.Modifiers & Keys.Shift) == Keys.Shift || (e.Modifiers & Keys.Control) == Keys.Control || (e.Modifiers & Keys.Alt) == Keys.Alt) { base.OnKeyDown(e); return; }

            
            

            base.OnKeyDown(e);
        }

        void ActionTronMouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
        {           
            TronMouseDown?.Invoke(this, e);
        }

        
        public void ClickControlMouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            TronMouseDown?.Invoke(this, e);
        }
        public void ClickControlDoubleClick(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            TronMouseDown?.Invoke(this, e);
            TronDoubleClick?.Invoke(this, e);
        }
        public void clickControlMouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
        {

        }
        
        public clickControlCancelClickMode clickControlCancelClick()
        {
            return clickControlCancelClickMode.cancelNoClick;
        }

    }




    public class TextCellEditorEmbeddedControl : TextBox, ITronCustomControl
    {
        public TextCellEditorEmbeddedControl()
        {              
            click.DoubleClick += ClickDoubleClick;
            click.MouseClick += ClickMouseClick;
            click.MouseDown += ActionTronMouseDown;  

            ReadOnly = true;

            BorderStyle = BorderStyle.None;

            
            PreviewKeyDown += TrOnKeyPreview;

            if (tronListView != null)
                tronlistview = tronListView();
        }

        
        
                      
        Click click = new Click();
        
        public event EventHandler Accept;
        
        public event TronListView.CancelEventHandler Cancel;
        public event KeyEventHandler TronKeyDown;
        public event MouseEventHandler TronDoubleClick;
        public event EventHandler TronSpace;
        public event EventHandler TronBefore;
        public event MouseEventHandler TronMouseDown;
        public event TronListView.TronListViewEventHandler tronListView;
        TronListView tronlistview;
        

        public bool incompleteEdit
        {
            get => false;
            set { }
        }

        public void getTLVText(ListViewItem.ListViewSubItem subItem)
        {
            Text = subItem.Text;
            

            
        }
        public void setTLVText(ListViewItem.ListViewSubItem subItem)
        {

            subItem.Text = Text;
        }        

        protected override void OnKeyUp(KeyEventArgs e)
        {
            if ((e.Modifiers & Keys.Control) != Keys.Control && (e.Modifiers & Keys.Alt) != Keys.Alt)
            {
                if (((e.Modifiers & Keys.Shift) == Keys.Shift && (e.KeyCode == Keys.F1 || e.KeyCode == Keys.F2))) 
                {

                    KeyEventArgs kea = new KeyEventArgs(e.KeyData);
                    TronKeyDown?.Invoke(this, kea);
                    e.Handled = true;
                    return;
                }
            }
            base.OnKeyUp(e);
        }

        protected override void OnKeyDown(KeyEventArgs e)
        {
            if ((e.Modifiers & Keys.Shift) == Keys.Shift || (e.Modifiers & Keys.Control) == Keys.Control || (e.Modifiers & Keys.Alt) == Keys.Alt) { base.OnKeyDown(e); return; }

            
            if (e.KeyCode == Keys.Enter)
            {
               
                TronKeyDown?.Invoke(this, e);

                e.Handled = true;

                return;
            }

            if (e.KeyCode == Keys.Escape &&
                Cancel != null)
            {
                Cancel(this, EventArgs.Empty);

                e.Handled = true;

                return;
            }

            if (e.KeyCode == Keys.Space)
            {                
                ActivateForm();

                e.Handled = true;

                return;
            }
            

            base.OnKeyDown(e);
        }

        


        protected void TrOnKeyPreview(Object sender, PreviewKeyDownEventArgs e)
        {
            if ((e.Modifiers & Keys.Control) == Keys.Control || (e.Modifiers & Keys.Alt) == Keys.Alt) { return; }


            if (e.KeyCode == Keys.Tab)
            {
                KeyEventArgs kea = new KeyEventArgs(e.KeyData);
                TronKeyDown?.Invoke(this, kea);
                return;
            }

           
            if ((e.Modifiers & Keys.Shift) == Keys.Shift || (e.Modifiers & Keys.Control) == Keys.Control || (e.Modifiers & Keys.Alt) == Keys.Alt) { return; }


            if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down || e.KeyCode == Keys.Left || e.KeyCode == Keys.Right
                               || e.KeyCode == Keys.PageUp || e.KeyCode == Keys.PageDown || e.KeyCode == Keys.Home || e.KeyCode == Keys.End)
            {
                KeyEventArgs kea = new KeyEventArgs(e.KeyData);
                TronKeyDown?.Invoke(this, kea);               
                return;
            }
            
        }

       
        protected override void OnMouseDown(MouseEventArgs e)
        {
           
            if ((Control.ModifierKeys & Keys.Shift) == Keys.Shift || (Control.ModifierKeys & Keys.Control) == Keys.Control || (Control.ModifierKeys & Keys.Alt) == Keys.Alt) return;
            
            click.MousePress(this, e);  
        }              

        void ActivateForm()
        {

            TronBefore?.Invoke(this, EventArgs.Empty);

            FormTextEdit formte = new FormTextEdit(Text);

            if (!formte.IsDisposed)
            {

                formte.StartPosition = FormStartPosition.CenterParent;
                formte.ShowDialog(this);
                if (!formte.IsDisposed && formte.DialogResult == DialogResult.OK)
                {
                    Text = formte.EditText;
                   
                    Accept?.Invoke(this, EventArgs.Empty);                    
                }
                else
                {
                    Cancel?.Invoke(this, EventArgs.Empty);
                }
                formte.Dispose();
            }
            else return;
            Select(0,0);
        }

        void ClickMouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            ActivateForm();
        }

        void ClickDoubleClick(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            TronDoubleClick?.Invoke(this, e);
        }

        void ActionTronMouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            
            TronMouseDown?.Invoke(this, e);
        }

    }



   public class CheckBoxEmbeddedControl : CheckBox, ITronCustomControl
    {
        public CheckBoxEmbeddedControl()
        {
            

            CheckAlign = ContentAlignment.MiddleCenter;

            PreviewKeyDown += TrOnKeyPreview;

            MouseDown += ActionTronMouseDown;

            if (tronListView != null)
                tronlistview = tronListView();
        }

        public enum modeTF { LeadingUppercaseTF, LowerCaseTF, TF01 };

        public void getTLVText(ListViewItem.ListViewSubItem subItem)
        {
            if (modetf == modeTF.LeadingUppercaseTF)
                Checked = subItem.Text == "True" ? true : false;
            else if (modetf == modeTF.LowerCaseTF)
                Checked = subItem.Text == "true" ? true : false;
            else if (modetf == modeTF.TF01)
                Checked = subItem.Text == "1" ? true : false;
            else Checked = false;
        }
        public void setTLVText(ListViewItem.ListViewSubItem subItem)
        {
            if (modetf == modeTF.LeadingUppercaseTF)
                subItem.Text = Checked ? "True" : "False";
            else if (modetf == modeTF.LowerCaseTF)
                subItem.Text = Checked ? "true" : "false";
            else if (modetf == modeTF.TF01)
                subItem.Text = Checked ? "1" : "0";
            else subItem.Text = "";

        }
        
        public event EventHandler Accept;
#pragma warning disable CS0067
        
        public event TronListView.CancelEventHandler Cancel;
#pragma warning restore CS0067
        public event KeyEventHandler TronKeyDown;
        public event MouseEventHandler TronDoubleClick;
        public event EventHandler TronSpace;
        public event EventHandler TronBefore;
        public event MouseEventHandler TronMouseDown;
        public event TronListView.TronListViewEventHandler tronListView;
        TronListView tronlistview;
        

        public modeTF modetf = modeTF.LeadingUppercaseTF;


        public bool incompleteEdit
        {
            get => false;
            set { }
        }

        protected override void OnDoubleClick(EventArgs e)
        {
            MouseEventArgs mea = new MouseEventArgs(MouseButtons, 0, 0, 0, 0);
            TronDoubleClick?.Invoke(this, mea);
        }

        protected override void OnCheckedChanged(EventArgs e)
        {

            if ((Control.ModifierKeys & Keys.Shift) == Keys.Shift || (Control.ModifierKeys & Keys.Control) == Keys.Control || (Control.ModifierKeys & Keys.Alt) == Keys.Alt)
            {
                Cancel?.Invoke(this, EventArgs.Empty);
            }
            else
            {
                base.OnCheckedChanged(e);
                
                Accept?.Invoke(this, EventArgs.Empty);
               
            }
        }

        protected override void OnKeyUp(KeyEventArgs e)
        {
            if ((e.Modifiers & Keys.Control) != Keys.Control && (e.Modifiers & Keys.Alt) != Keys.Alt)
            {
                if (((e.Modifiers & Keys.Shift) == Keys.Shift && (e.KeyCode == Keys.F1 || e.KeyCode == Keys.F2))) 
                {

                    KeyEventArgs kea = new KeyEventArgs(e.KeyData);
                    TronKeyDown?.Invoke(this, kea);
                    e.Handled = true;
                    return;
                }
            }
            base.OnKeyUp(e);
        }

        protected override void OnKeyDown(KeyEventArgs e)
        {
            
            if ((e.Modifiers & Keys.Shift) == Keys.Shift || (e.Modifiers & Keys.Control) == Keys.Control || (e.Modifiers & Keys.Alt) == Keys.Alt) { base.OnKeyDown(e); return; }



            if (e.KeyCode == Keys.Return)
            {
                TronKeyDown?.Invoke(this, e);                
                e.Handled = true;
                return;
            }

            base.OnKeyDown(e);
        }

        
        protected void TrOnKeyPreview(Object sender, PreviewKeyDownEventArgs e)
        {
            
            if ((e.Modifiers & Keys.Control) == Keys.Control || (e.Modifiers & Keys.Alt) == Keys.Alt) { return; }

            if (e.KeyCode == Keys.Tab)
            {
                KeyEventArgs kea = new KeyEventArgs(e.KeyData);
                TronKeyDown?.Invoke(this, kea);
                return;
            }

            
            if ((e.Modifiers & Keys.Shift) == Keys.Shift || (e.Modifiers & Keys.Control) == Keys.Control || (e.Modifiers & Keys.Alt) == Keys.Alt) { return; }


            if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down || e.KeyCode == Keys.Left || e.KeyCode == Keys.Right
                               || e.KeyCode == Keys.PageUp || e.KeyCode == Keys.PageDown || e.KeyCode == Keys.Home || e.KeyCode == Keys.End)
            {
                KeyEventArgs kea = new KeyEventArgs(e.KeyData);
                TronKeyDown?.Invoke(this, kea);                
                
                return;
            }
            
           
        }

        void ActionTronMouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
        {
           
            TronMouseDown?.Invoke(this, e);
        }

    }


Software Updates

Introduced ClassLibraryCalendar.

1 Nov 2020

For cb.DropDownStyle = ComboBoxStyle.DropDownList;, doubleclick was added.

28 Oct 2020

Added json response for ComboIndex

22 Oct 2020

MouseMoveListView event added

Gave user control over focus and selection colours

2 Sep 2020

Removed debug line: WriteTextDTP.txt

26 Aug 2020

In conditional acceptance mode of NumericUpDown derivative, prevented doubleclick when using up and down buttons.

26 Aug 2020

In conditional acceptance mode of NumericUpDown derivative, corrected buttons and doubleclick.

22 Aug 2020
Created two modes for a NumericUpDown derivative. The second requires enter to confirm the proposed value.

22 Feb 2020
Added proper behaviour for tab, arrows, space and return. Return selects the line containing a focussed cell (light green background) and then pressed again it executes based on the selection. Space and sometimes page up & down activate (click controls or richtextboxes and toggle checkboxes etc.) or change the control state. Arrows navigate within the tronlistview control (changing the focussed cell with a light green background) and tab jumps focus out to buttons etc. and then back in again.

7 Feb 2020
Fixed starting with ctrl or shift and click.

6 Feb 2020
Upgraded selection using modifier keys for click.