View previous topic :: View next topic |
Author |
Message |
pearly KiXforms Aficionado


Joined: 27 Jan 2004 Posts: 332
|
Posted: Thu Jun 21, 2007 6:56 pm Post subject: ListView SelectedIndexChanged not affected by Rt Mouse Click |
|
|
Is it by design when right-clicking on the mouse to change the index of a ListView, SelectedIndexChanged is not triggered? |
|
Back to top |
|
 |
Shawn KiXforms Developer


Joined: 22 Feb 2003 Posts: 1983 Location: Canada
|
Posted: Thu Jun 21, 2007 9:38 pm Post subject: |
|
|
pearly - found some other odd behavior while investigating this - I am looking at and will be posting more information. |
|
Back to top |
|
 |
pearly KiXforms Aficionado


Joined: 27 Jan 2004 Posts: 332
|
Posted: Thu Jun 21, 2007 10:11 pm Post subject: |
|
|
thanks Shawn! |
|
Back to top |
|
 |
Shawn KiXforms Developer


Joined: 22 Feb 2003 Posts: 1983 Location: Canada
|
Posted: Fri Jun 22, 2007 2:51 am Post subject: |
|
|
Wrote this little driver to test some things ... can you verify my observations so far ...
1) Right-click seems to trigger SelectedIndexChanged.
2) The event gets triggered twice. Had me scratching my head until I researched. It is indeed by design and makes sense. We can chat further on this later.
Anyway, heres the code. Clicking on a row causes an entry to appear in "the log". You can clear the log through the menu. Each event is indexed so that one can see the deltas.
Code: |
Break On
$System = CreateObject("Kixforms.System")
$Form = $System.Form()
$Form.ClientWidth = 640
$Form.ClientHeight = 480
$Form.Closing = "Form_Closing()"
$Form.FontSize = 10
$MainMenu = $System.MainMenu()
$FileMenu = $MainMenu.MenuItems.Add($System.MenuItem("File"))
$ExitMenu = $FileMenu.MenuItems.Add($System.MenuItem("Exit"))
$ExitMenu.Click = "ExitMenu_Click()"
$EditMenu = $MainMenu.MenuItems.Add($System.MenuItem("Edit"))
$ClearLogMenu = $EditMenu.MenuItems.Add($System.MenuItem("Clear Log"))
$ClearLogMenu.Click = "ClearLogMenu_Click()"
$Form.Menu = $MainMenu
$Splitter1 = $Form.Controls.Add($System.Splitter())
$Splitter1.Dock = $System.DockStyle_Bottom
$TextBox1 = $Form.Controls.Add($System.TextBox())
$TextBox1.MultiLine = 1
$TextBox1.Height = 200
$TextBox1.Dock = $System.DockStyle_Bottom
$TextBox1.ScrollBars = $System.Scrollbars_Both
$TextBox1.Tag = 0 ; Log index number
$StatusBar1 = $Form.Controls.Add($System.StatusBar())
$ListView1 = $Form.Controls.Add($System.ListView())
$ListView1.Dock = $System.DockStyle_Fill
$ListView1.View = $System.View_Details
$ListView1.SelectedIndexChanged = "ListView1_SelectedIndexChanged()"
$ListView1.FullRowSelect = 1
$NameColumn = $ListView1.Columns.Add($System.ColumnHeader("Name"))
$AddressColumn = $ListView1.Columns.Add($System.ColumnHeader("Address"))
$PhoneColumn = $ListView1.Columns.Add($System.ColumnHeader("Phone"))
For $i = 1 To 10
$ListViewItem = $ListView1.Items.Add($System.ListViewItem())
$ListViewItem.Text = "John Doe "+$i
$AddressSubItem = $ListViewItem.SubItems.Add($System.ListViewSubItem())
$AddressSubItem.Text = ""+(RND(88)+10)+" Main Street"
$PhoneSubItem = $ListViewItem.SubItems.Add($System.ListViewSubItem())
$PhoneSubItem.Text = "("+(RND(900)+100)+") " + (RND(900)+100) + "-" + (RND(9000)+1000)
Next
For Each $ColumnHeader In $ListView1.Columns
$ColumnHeader.Width = -1
Next
$Form.Center
$Form.Show
While $Form.Visible
$=Execute($System.DoEvents)
Loop
Exit 0
Function Form_Closing()
$e = $System.EventArgs
$e.Cancel = 1
$Form.Hide
EndFunction
Function ExitMenu_Click()
$Form.Hide
EndFunction
Function ListView1_SelectedIndexChanged()
$TextBox1.Tag = $TextBox1.Tag + 1
$Id = CStr($TextBox1.Tag)
$Count = $ListView1.SelectedItems.Count
$Index = -1
If $Count
$Index = $ListView1.SelectedItems.Item(0).Index
Endif
$TextBox1.AppendText("$Id - SelectedIndexChanged. Index=$Index Count=$Count" + @CRLF)
EndFunction
Function ClearLogMenu_Click()
$TextBox1.Text = ""
$TextBox1.Tag = 0
EndFunction
|
|
|
Back to top |
|
 |
Shawn KiXforms Developer


Joined: 22 Feb 2003 Posts: 1983 Location: Canada
|
Posted: Fri Jun 22, 2007 2:44 pm Post subject: |
|
|
Ok here's the "issue" in more detail - its discussed much on the web and on MSDN, the key quote is:
Quote: |
MSDN states, and I quote, "The SelectedIndexChanged event occurs in single selection controls, whenever there is a change to the index position of the selected item. In a multiple selection control, this event occurs whenever an item is removed or added to the list of selected items."
|
Here is the link
We know the ListView is MULTISELECT by default. And that the SelectedItems collelction contains "the list of selected items". So the event fires twice as follows:
1) Once when the current item is removed from the collection
2) Once when the newly selected item is added to the collection.
If you select an item in that test script - you will see the event triggered twice BUT if after selecting an item - you click "off" the rows (somewhere in the blank white space under the rows) you will see that the event only triggers once. Thats because there is no "new item" added to the collection.
But there is still another problem that needs fixing. In the "twice triggered" scenario - after the first trigger when the current item becomes unselected - the SelectedItems.Count property should be returning a 0 (zero) - because no items are selected therefore no items in collelction. This isn't happening in kf.net - the count shows as 1 after each trigger.
There is a reason for this - it has to do with the way KF handles (serializes/presents) events. Can you guess ? (Took me some head-scratching to figure out btw). |
|
Back to top |
|
 |
pearly KiXforms Aficionado


Joined: 27 Jan 2004 Posts: 332
|
Posted: Fri Jun 22, 2007 6:36 pm Post subject: |
|
|
I'm going to take a random guess since I'm not too familar with serialization...
Is it because KF cannot handle simultaneous events and therefore the second event overrides the first? (very random guess)
I've also noticed a couple of things:
In your example program, when clicking on an item that is already selected, it still triggers SelectedIndexChanged event twice. Shouldn't it not trigger the event at all (since the name implies only if the selected index changes)?
Also, the reason for posting this issue in the first place was because I had a problem with right-clicking on a Listview with a Context menu (I forgot to add that part). SelectedIndexChanged event isn't triggered until after the Context Menu is closed. Is it possible to capture the event prior to displaying the context menu? Here's your code w/ Context Menu support.
As you'll see when running the code, you will never see the Logs when selecting Clear Log menu item in the Context Menu (except at times, for a split second). Events continue to pile up in Queue until you stop right-clicking on the items. Then it spits out the log all at once.
Code: |
Break On
$System = CreateObject("Kixforms.System")
$Form = $System.Form()
$Form.ClientWidth = 640
$Form.ClientHeight = 480
$Form.Closing = "Form_Closing()"
$Form.FontSize = 10
$MainMenu = $System.MainMenu()
$FileMenu = $MainMenu.MenuItems.Add($System.MenuItem("File"))
$ExitMenu = $FileMenu.MenuItems.Add($System.MenuItem("Exit"))
$ExitMenu.Click = "ExitMenu_Click()"
$EditMenu = $MainMenu.MenuItems.Add($System.MenuItem("Edit"))
$ClearLogMenu = $EditMenu.MenuItems.Add($System.MenuItem("Clear Log"))
$ClearLogMenu.Click = "ClearLogMenu_Click()"
$Form.Menu = $MainMenu
$Splitter1 = $Form.Controls.Add($System.Splitter())
$Splitter1.Dock = $System.DockStyle_Bottom
$TextBox1 = $Form.Controls.Add($System.TextBox())
$TextBox1.MultiLine = 1
$TextBox1.Height = 200
$TextBox1.Dock = $System.DockStyle_Bottom
$TextBox1.ScrollBars = $System.Scrollbars_Both
$TextBox1.Tag = 0 ; Log index number
$StatusBar1 = $Form.Controls.Add($System.StatusBar())
$ContextMenu = $System.ContextMenu()
$ContextMenuClearLog = $ContextMenu.MenuItems.Add($System.MenuItem("Clear Log"))
$ContextMenuClearLog.Click = "ContextMenuClearLog_Click()"
$ListView1 = $Form.Controls.Add($System.ListView())
$ListView1.Dock = $System.DockStyle_Fill
$ListView1.View = $System.View_Details
$ListView1.SelectedIndexChanged = "ListView1_SelectedIndexChanged()"
$ListView1.FullRowSelect = 1
$ListView1.ContextMenu = $ContextMenu
$NameColumn = $ListView1.Columns.Add($System.ColumnHeader("Name"))
$AddressColumn = $ListView1.Columns.Add($System.ColumnHeader("Address"))
$PhoneColumn = $ListView1.Columns.Add($System.ColumnHeader("Phone"))
For $i = 1 to 10
$ListViewItem = $ListView1.Items.Add($System.ListViewItem())
$ListViewItem.Text = "John Doe "+$i
$AddressSubItem = $ListViewItem.SubItems.Add($System.ListViewSubItem())
$AddressSubItem.Text = ""+(Rnd(88)+10)+" Main Street"
$PhoneSubItem = $ListViewItem.SubItems.Add($System.ListViewSubItem())
$PhoneSubItem.Text = "("+(Rnd(900)+100)+") " + (Rnd(900)+100) + "-" + (Rnd(9000)+1000)
Next
For Each $ColumnHeader in $ListView1.Columns
$ColumnHeader.Width = -1
Next
$Form.Center
$Form.Show
While $Form.Visible
$=Execute($System.DoEvents)
Loop
Exit 0
Function Form_Closing()
$e = $System.EventArgs
$e.Cancel = 1
$Form.Hide
EndFunction
Function ExitMenu_Click()
$Form.Hide
EndFunction
Function ContextMenuClearLog_Click()
$TextBox1.Text = ""
$TextBox1.Tag = 0
EndFunction
Function ListView1_SelectedIndexChanged()
$TextBox1.Tag = $TextBox1.Tag + 1
$Id = CStr($TextBox1.Tag)
$Count = $ListView1.SelectedItems.Count
$Index = -1
If $Count
$Index = $ListView1.SelectedItems.Item(0).Index
EndIf
$TextBox1.AppendText("$Id - SelectedIndexChanged. Index=$Index Count=$Count" + @CRLF)
EndFunction
Function ClearLogMenu_Click()
$TextBox1.Text = ""
$TextBox1.Tag = 0
EndFunction
|
|
|
Back to top |
|
 |
Shawn KiXforms Developer


Joined: 22 Feb 2003 Posts: 1983 Location: Canada
|
Posted: Fri Jun 22, 2007 7:19 pm Post subject: |
|
|
Yea your right. The two events happen in quick succession. By the time one gets (processes) the first de-select event, the second select event has already happened. I'm going to "fix" this by creating a new EventArgs object called SelectedIndexChangedEventArgs - this object will have state information taken from when the event occured - not afterwards. Stay tuned.
In terms of your observations - I am checking them out now. I have an equivalent application done in Visiual Studio 2003 for comparison purposes. |
|
Back to top |
|
 |
Shawn KiXforms Developer


Joined: 22 Feb 2003 Posts: 1983 Location: Canada
|
Posted: Fri Jun 22, 2007 11:09 pm Post subject: |
|
|
pearly. I see what your seeing (the ContextMenu events I mean). Whats going on is that when the ContextMenu is displayed, the entire app (kix, kixforms and .net) enter a "Modal" state - where basically nothing happens until one does something with the Menu. If Kix supported "real" events then this wouldn't be a problem - they get called during this modal state. But since Kix doesn't, Kixforms batches the events up and presents them after the modal state.
Thinking about a solution ... |
|
Back to top |
|
 |
pearly KiXforms Aficionado


Joined: 27 Jan 2004 Posts: 332
|
Posted: Fri Jun 22, 2007 11:52 pm Post subject: |
|
|
Shawn, you described it perfectly. It's unfortunate KiX does not support "real" events. I wonder if Ruud has this as a near future enhancement?
Anyway, I hope you find a workaround solution. 
Last edited by pearly on Mon Jun 25, 2007 4:39 pm; edited 1 time in total |
|
Back to top |
|
 |
Shawn KiXforms Developer


Joined: 22 Feb 2003 Posts: 1983 Location: Canada
|
Posted: Sat Jun 23, 2007 1:56 pm Post subject: |
|
|
I just posted a new build (3.2.3) with a fix that should give us a better behavior.
1) I "deferered" the ContextMenu.Popup event and placed it on the event stack. This has the effect of letting the script process the events ahead of it - and the popup occurs in due sequence.
2) One fall-out of this is an added feature - I exposed the ContextMenu.Popup event to script. This occurs before the ContextMenu is displayed - allowing one to change the menu dynamically based on context.
Here is a modified test script - things to notice:
1) Click on an item then right-click. You should see the changed bahvior in the event log.
2) Notice the first item of the ContextMenu is dynamically built - based on the number of selected items (do a multi-select). It asks if you want to delete n many rows.
3) Right-click somewhere to the right - away from the rows - the Delete menuitem is hidden automatically. The Edit Menu->Delete feature is also dynamically enabled/disabled.
I change the script a little bit - added some generated names - I am using this script to build./test ListView sorting - which is coming soon.
Code: |
Break On
$System = CreateObject("Kixforms.System")
$Form = $System.Form()
$Form.ClientWidth = 640
$Form.ClientHeight = 480
$Form.Closing = "Form_Closing()"
$Form.FontSize = 10
$MainMenu = $System.MainMenu()
$FileMenu = $MainMenu.MenuItems.Add($System.MenuItem("File"))
$ExitMenu = $FileMenu.MenuItems.Add($System.MenuItem("Exit"))
$ExitMenu.Click = "ExitMenu_Click()"
$EditMenu = $MainMenu.MenuItems.Add($System.MenuItem("Edit"))
$DeleteMenu = $EditMenu.MenuItems.Add($System.MenuItem("Delete"))
$DeleteMenu.Enabled = 0
$DeleteMenu.Click = "DeleteMenu_Click()"
$ClearLogMenu = $EditMenu.MenuItems.Add($System.MenuItem("Clear Events"))
$ClearLogMenu.Click = "ClearLogMenu_Click()"
$Form.Menu = $MainMenu
$ContextMenu = $System.ContextMenu()
$ContextMenu.Popup = "ContextMenu_Popup()"
$DeleteContextMenu = $ContextMenu.MenuItems.Add($System.MenuItem("Delete Item"))
$DeleteContextMenu.Click = "DeleteMenu_Click()"
$ContextMenuClearLog = $ContextMenu.MenuItems.Add($System.MenuItem("Clear Events"))
$ContextMenuClearLog.Click = "ContextMenuClearLog_Click()"
$ListView1 = $Form.Controls.Add($System.ListView())
$ListView1.Dock = $System.DockStyle_Fill
$ListView1.View = $System.View_Details
$ListView1.SelectedIndexChanged = "ListView1_SelectedIndexChanged()"
$ListView1.FullRowSelect = 1
$ListView1.ContextMenu = $ContextMenu
$NameColumn = $ListView1.Columns.Add($System.ColumnHeader("Name"))
$AddressColumn = $ListView1.Columns.Add($System.ColumnHeader("Address"))
$PhoneColumn = $ListView1.Columns.Add($System.ColumnHeader("Phone"))
$Splitter1 = $Form.Controls.Add($System.Splitter())
$Splitter1.Dock = $System.DockStyle_Bottom
$TextBox1 = $Form.Controls.Add($System.TextBox())
$TextBox1.MultiLine = 1
$TextBox1.Height = 200
$TextBox1.Dock = $System.DockStyle_Bottom
$TextBox1.ScrollBars = $System.Scrollbars_Both
$TextBox1.Tag = 0 ; Log index number
$StatusBar1 = $Form.Controls.Add($System.StatusBar())
For $i = 1 to 100
$ListViewItem = $ListView1.Items.Add($System.ListViewItem())
$ListViewItem.Text = GetName()
$AddressSubItem = $ListViewItem.SubItems.Add($System.ListViewSubItem())
$AddressSubItem.Text = GetAddress()
$PhoneSubItem = $ListViewItem.SubItems.Add($System.ListViewSubItem())
$PhoneSubItem.Text = GetPhone()
Next
For Each $ColumnHeader in $ListView1.Columns
$ColumnHeader.Width = -1
Next
$Form.Center
$Form.Show
While $Form.Visible
$=Execute($System.DoEvents)
Loop
Exit 0
Function Form_Closing()
$e = $System.EventArgs
$e.Cancel = 1
$Form.Hide
EndFunction
Function ExitMenu_Click()
$Form.Hide
EndFunction
Function ContextMenuClearLog_Click()
ClearEvents()
EndFunction
Function ListView1_SelectedIndexChanged()
$Count = $ListView1.SelectedItems.Count
$Index = -1
If $Count
$Index = $ListView1.SelectedItems.Item(0).Index
$DeleteMenu.Enabled = 1
Else
$DeleteMenu.Enabled = 0
Endif
TraceEvent("SelectedIndexChanged Index=$Index Count=$Count" + @CRLF)
EndFunction
Function DeleteMenu_Click()
If $ListView1.SelectedItems.Count
For Each $ListViewItem In $ListView1.SelectedItems
$ListViewItem.Remove
Next
Else
$= $System.MessageBox.Show("Select a row")
Endif
EndFunction
Function ClearLogMenu_Click()
ClearEvents()
EndFunction
Function ContextMenu_Popup()
TraceEvent("Popup" + @CRLF)
If $ListView1.SelectedItems.Count
$DeleteContextMenu.Visible = 1
$DeleteContextMenu.Text = "Delete " + $ListView1.SelectedItems.Count + " row(s)"
Else
$DeleteContextMenu.Visible = 0
Endif
EndFunction
Function ContextMenuDeleteItem_Click()
For Each $ListViewItem In $ListView1.SelectedItems
$ListViewItem.Remove
Next
EndFunction
Function TraceEvent($Message)
$TextBox1.Tag = $TextBox1.Tag + 1
$Id = CStr($TextBox1.Tag)
$TextBox1.AppendText("$Id - " + $Message)
EndFunction
Function ClearEvents()
$TextBox1.Text = ""
$TextBox1.Tag = 0
EndFunction
Function GetName()
Dim $FirstNames, $LastNames
$FirstNames = Split(
"Alfred Alvin Audrey Chad Cuthbert Dunstan Edgar Edith Edmund Edward Edwin Egbert Esmond "+
"Ethel Etheldreda Everard Godwin Harold Kenelm Mildred Osbert Oswald Wilfred Ainsley Bruce "+
"Cameron Courtney Darcy Darrell Granville Greville Lacey Melville Montague Montgomery "+
"Mortimer Neville Percy Quincy Sacheverell Seymour Sidney Sinclair Tracy Vere Vernon")
$LastNames = Split(
"Smith Johnson Williams Jones Brown Davis Miller Wilson Moore Taylor Baldwin Mitchell Wyndham")
$GetName = $FirstNames[RND(UBound($FirstNames))]
$GetName = $GetName + " " + $FirstNames[RND(UBound($FirstNames))]
$GetName = $GetName + " " + $LastNames[RND(UBound($LastNames))]
EndFunction
Function GetAddress()
Dim $Names, $Types
$Names = Split(
"Central College Lakeview Broadway Sycamore Hillcrest Madison Meadow River Hickory Forest")
$Types = Split(
"Street Drive Avenue Cresent Lane")
$GetAddress = CStr(Rnd(99)) + " "
$GetAddress = $GetAddress + $Names[RND(UBound($Names))] + " "
$GetAddress = $GetAddress + $Types[RND(UBound($Types))]
EndFunction
Function GetPhone()
$GetPhone = "("+(Rnd(900)+99)+") " + (Rnd(900)+99) + "-" + (Rnd(9000)+999)
EndFunction
|
|
|
Back to top |
|
 |
pearly KiXforms Aficionado


Joined: 27 Jan 2004 Posts: 332
|
Posted: Mon Jun 25, 2007 7:12 pm Post subject: |
|
|
Quote: | 2) One fall-out of this is an added feature - I exposed the ContextMenu.Popup event to script. This occurs before the ContextMenu is displayed - allowing one to change the menu dynamically based on context. |
Oh man Shawn! I've been wanting this feature for a long time - dynamic context menus. Thanks so much for adding this! Now I can perform operations prior to the pop-up such as dynamic menu items.
You are the man!  |
|
Back to top |
|
 |
benny69 KiXforms Advocate


Joined: 30 Oct 2003 Posts: 567 Location: Lincoln, Ne
|
Posted: Mon Jun 25, 2007 7:54 pm Post subject: |
|
|
Yeah, Shawn is the Man! _________________ Wait don't order yet,... get KiXforms Designer .NET 2.0 (Beta)
KiXforms Designer .NET 2.0 (Beta) |
|
Back to top |
|
 |
Shawn KiXforms Developer


Joined: 22 Feb 2003 Posts: 1983 Location: Canada
|
Posted: Mon Jun 25, 2007 8:55 pm Post subject: |
|
|
Well kudos to you for suggesting. Without the code to fix deferring the popup, the Popup event would never have been possible.
Btw - I will be posting a new Dev Build soon. Compiled under pure .Net 2.0 - this means we can start to open-up all the new fancy controls in 2.0 (like DataGridView and MaskedTextBox and SplitContainer etc etc) ... |
|
Back to top |
|
 |
pearly KiXforms Aficionado


Joined: 27 Jan 2004 Posts: 332
|
Posted: Mon Jun 25, 2007 9:53 pm Post subject: |
|
|
Woohoo! Just in time for an update to ScriptForms Designer in the new ASE 3.x  |
|
Back to top |
|
 |
masken KiXforms Enthusiast

Joined: 14 Mar 2003 Posts: 202 Location: Gothenburg, Sweden
|
Posted: Tue Mar 18, 2008 6:13 am Post subject: |
|
|
Sorry for rooting up an old thread, but how would one go about enumerating the SelectedItems ?
Code: |
FOR EACH $SelectedItem IN $ListView1.SelectedItems
? "now what? How do I get the address column data for example?"
NEXT
|
? |
|
Back to top |
|
 |
|