KiXforms Forum Index KiXforms
The Forum for the KiXforms Community
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 
 Quick Links 
Site News
Downloads
Documentation
Donations
Script Archive
Tracking Systems

ListView SelectedIndexChanged not affected by Rt Mouse Click
Goto page 1, 2  Next
 
Post new topic   Reply to topic    KiXforms Forum Index -> KiXforms.NET Discussion
View previous topic :: View next topic  
Author Message
pearly
KiXforms Aficionado
KiXforms Aficionado


Joined: 27 Jan 2004
Posts: 332

PostPosted: Thu Jun 21, 2007 6:56 pm    Post subject: ListView SelectedIndexChanged not affected by Rt Mouse Click Reply with quote

Is it by design when right-clicking on the mouse to change the index of a ListView, SelectedIndexChanged is not triggered?
Back to top
View user's profile Send private message
Shawn
KiXforms Developer
KiXforms Developer


Joined: 22 Feb 2003
Posts: 1983
Location: Canada

PostPosted: Thu Jun 21, 2007 9:38 pm    Post subject: Reply with quote

pearly - found some other odd behavior while investigating this - I am looking at and will be posting more information.
Back to top
View user's profile Send private message
pearly
KiXforms Aficionado
KiXforms Aficionado


Joined: 27 Jan 2004
Posts: 332

PostPosted: Thu Jun 21, 2007 10:11 pm    Post subject: Reply with quote

thanks Shawn!
Back to top
View user's profile Send private message
Shawn
KiXforms Developer
KiXforms Developer


Joined: 22 Feb 2003
Posts: 1983
Location: Canada

PostPosted: Fri Jun 22, 2007 2:51 am    Post subject: Reply with quote

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
View user's profile Send private message
Shawn
KiXforms Developer
KiXforms Developer


Joined: 22 Feb 2003
Posts: 1983
Location: Canada

PostPosted: Fri Jun 22, 2007 2:44 pm    Post subject: Reply with quote

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
View user's profile Send private message
pearly
KiXforms Aficionado
KiXforms Aficionado


Joined: 27 Jan 2004
Posts: 332

PostPosted: Fri Jun 22, 2007 6:36 pm    Post subject: Reply with quote

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
View user's profile Send private message
Shawn
KiXforms Developer
KiXforms Developer


Joined: 22 Feb 2003
Posts: 1983
Location: Canada

PostPosted: Fri Jun 22, 2007 7:19 pm    Post subject: Reply with quote

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
View user's profile Send private message
Shawn
KiXforms Developer
KiXforms Developer


Joined: 22 Feb 2003
Posts: 1983
Location: Canada

PostPosted: Fri Jun 22, 2007 11:09 pm    Post subject: Reply with quote

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
View user's profile Send private message
pearly
KiXforms Aficionado
KiXforms Aficionado


Joined: 27 Jan 2004
Posts: 332

PostPosted: Fri Jun 22, 2007 11:52 pm    Post subject: Reply with quote

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. Smile


Last edited by pearly on Mon Jun 25, 2007 4:39 pm; edited 1 time in total
Back to top
View user's profile Send private message
Shawn
KiXforms Developer
KiXforms Developer


Joined: 22 Feb 2003
Posts: 1983
Location: Canada

PostPosted: Sat Jun 23, 2007 1:56 pm    Post subject: Reply with quote

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
View user's profile Send private message
pearly
KiXforms Aficionado
KiXforms Aficionado


Joined: 27 Jan 2004
Posts: 332

PostPosted: Mon Jun 25, 2007 7:12 pm    Post subject: Reply with quote

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! Very Happy
Back to top
View user's profile Send private message
benny69
KiXforms Advocate
KiXforms Advocate


Joined: 30 Oct 2003
Posts: 567
Location: Lincoln, Ne

PostPosted: Mon Jun 25, 2007 7:54 pm    Post subject: Reply with quote

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
View user's profile Send private message Send e-mail
Shawn
KiXforms Developer
KiXforms Developer


Joined: 22 Feb 2003
Posts: 1983
Location: Canada

PostPosted: Mon Jun 25, 2007 8:55 pm    Post subject: Reply with quote

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
View user's profile Send private message
pearly
KiXforms Aficionado
KiXforms Aficionado


Joined: 27 Jan 2004
Posts: 332

PostPosted: Mon Jun 25, 2007 9:53 pm    Post subject: Reply with quote

Woohoo! Just in time for an update to ScriptForms Designer in the new ASE 3.x Wink
Back to top
View user's profile Send private message
masken
KiXforms Enthusiast
KiXforms Enthusiast


Joined: 14 Mar 2003
Posts: 202
Location: Gothenburg, Sweden

PostPosted: Tue Mar 18, 2008 6:13 am    Post subject: Reply with quote

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
View user's profile Send private message MSN Messenger
Display posts from previous:   
Post new topic   Reply to topic    KiXforms Forum Index -> KiXforms.NET Discussion All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group