Discussion:
How to cancel SelectedIndexChanged event in ListView control
(too old to reply)
Keith. O
2006-04-07 01:29:02 UTC
Permalink
Hi all,

I'd like to cancel SelectedIndexChanged event in ListView control.

I tried the following code for SelectedIndexChanged handler, but it doesn't
work:

private void OnSelectedIndexChanged(object sender, EventArgs e) {

if ( <Cancel condition here> ) {

// Select back the originally selected one. here, I hard coded to zero.
ListView1.Items[0].Selected = true;

return;
}

}

It might be a FAQ, but I couldn't fint an answer on the web.

Thanks in advance,

Keith
Cerebrus
2006-04-07 03:17:08 UTC
Permalink
Hi Keith,

I tried it and it works. The only pitfall is that the event fires as
many as 4 times. (2 times for the original change, and 2 more times,
when you set the SelectedIndex to 0 manually.) So, what error do you
get when you run it ? Also, could you describe the <cancel condition>.

Regards,

Cerebrus.
Keith. O
2006-04-07 19:33:02 UTC
Permalink
Thanks for your time, Cerebrus.

I should have simplified the problem first. You're right. The behavior is
interesting.

Keith
Post by Cerebrus
Hi Keith,
I tried it and it works. The only pitfall is that the event fires as
many as 4 times. (2 times for the original change, and 2 more times,
when you set the SelectedIndex to 0 manually.) So, what error do you
get when you run it ? Also, could you describe the <cancel condition>.
Regards,
Cerebrus.
Claes Bergefall
2006-04-07 14:26:02 UTC
Permalink
http://groups.google.com/group/microsoft.public.dotnet.framework.windowsforms.controls/msg/5afb5ede99eb3ffc?hl=en

/claes
Post by Keith. O
Hi all,
I'd like to cancel SelectedIndexChanged event in ListView control.
I tried the following code for SelectedIndexChanged handler, but it doesn't
private void OnSelectedIndexChanged(object sender, EventArgs e) {
if ( <Cancel condition here> ) {
// Select back the originally selected one. here, I hard coded to zero.
ListView1.Items[0].Selected = true;
return;
}
}
It might be a FAQ, but I couldn't fint an answer on the web.
Thanks in advance,
Keith
Keith. O
2006-04-07 19:36:02 UTC
Permalink
Thanks, Claes.

Your code seems great. I'll try it.

Keith
Post by Claes Bergefall
http://groups.google.com/group/microsoft.public.dotnet.framework.windowsforms.controls/msg/5afb5ede99eb3ffc?hl=en
/claes
Post by Keith. O
Hi all,
I'd like to cancel SelectedIndexChanged event in ListView control.
I tried the following code for SelectedIndexChanged handler, but it doesn't
private void OnSelectedIndexChanged(object sender, EventArgs e) {
if ( <Cancel condition here> ) {
// Select back the originally selected one. here, I hard coded to zero.
ListView1.Items[0].Selected = true;
return;
}
}
It might be a FAQ, but I couldn't fint an answer on the web.
Thanks in advance,
Keith
Keith. O
2006-04-07 21:32:02 UTC
Permalink
I re-wrote it in C# -- I have to write codes in C# in my current project --
and tested it. I believe that it's identical to what you show me in VB.NET.

As a result, I could get a SelectedIndexChanging event (Thanks Claes :-) )

But the event occurs "twice." So I get a popup prompt twice (see my test
client code below.)

How can I prevent the event occurs twice or how can I filter unnecessary
event?


The code for ListViewEx is as follows:

----------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace SelectTest
{
public partial class ListViewEx : ListView
{
const int WM_USER = 0x0400;
const int WM_NOTIFY = 0x4e;
const int OCM_BASE = WM_USER + 0x1C00;
const int OCM_NOTIFY = OCM_BASE + WM_NOTIFY;
const int LVN_FIRST = 0 - 100;
const int LVN_ITEMCHANGING = LVN_FIRST - 0;
const int LVIF_STATE = 0x0008;
const int LVIS_SELECTED = 0x0002;


[StructLayout(LayoutKind.Sequential)]
public struct NMHDR
{
public IntPtr hwndFrom;
public int idFrom;
public int code;
}

[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int x;
public int y;
}

[StructLayout(LayoutKind.Sequential)]
public struct NMLISTVIEW
{
public NMHDR hdr;
public int iItem;
public int iSubItem;
public int uNewState;
public int uOldState;
public int uChanged;
public POINT ptAction;
public int lParam;
}

public delegate void SelectedIndexChangingEventHandler (object
sender, ItemChangingEventArgs e );
public event SelectedIndexChangingEventHandler SelectedIndexChanging;

protected virtual void OnSelectedIndexChanging(ItemChangingEventArgs
e)
{
SelectedIndexChanging(this, e);
}

protected override void WndProc(ref Message m)
{
if (m.Msg == OCM_NOTIFY)
{
NMHDR nm = (NMHDR)m.GetLParam(typeof(NMHDR));
if (nm.code == LVN_ITEMCHANGING)
{
NMLISTVIEW nmlv =
(NMLISTVIEW)m.GetLParam(typeof(NMLISTVIEW));

if ( ( nmlv.uChanged & LVIF_STATE ) == LVIF_STATE)
{
if ((nmlv.uNewState & LVIS_SELECTED) == LVIS_SELECTED)
{
ItemChangingEventArgs e = new
ItemChangingEventArgs(nmlv.iItem);

OnSelectedIndexChanging(e);

if (e.Cancel)
{
m.Result = new IntPtr(1);
return;
}
}
}
}
}

base.WndProc(ref m);

}

public ListViewEx()
{
InitializeComponent();
}
}

public class ItemChangingEventArgs : CancelEventArgs
{
int m_index;

public ItemChangingEventArgs(int index)
{
m_index = index;
}

public int Index
{
get
{
return m_index;
}
}
}
}
----------------------------------------

And here's my test client, which has ListViewEx1 on it:

----------------------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace SelectTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void OnSelectedIndexChanging(object sender,
ItemChangingEventArgs e)
{
if (DialogResult.Cancel == MessageBox.Show("Change selected
item?", "", MessageBoxButtons.OKCancel))
{
e.Cancel = true;
}
}
}
}
----------------------------------------

Thanks in advance,

Keith
Claes Bergefall
2006-04-10 15:52:36 UTC
Permalink
Interesting. This is actually the expected behaviour (I'll get back to that
further down), but apparently there is a bug in my code that causes it to
work only if you throw up something that gets focus away from the listview
(e.g. a message box)

In it's current form, my code only work properly for preventing new nodes
from being selected. I guess that is what most people want because no one
has ever said anything about it (I've posted that code to others as well)
:-)

The intended behaviour is to follow the behaviour of the
SelectedIndexChanged event, which actually fires twice when changing a
selection. It fires once when the old node is being deselected and once when
the new node is being selected. Fixing my code though was harder than I
expected. The Windows API works on an item level, it has no concept of
collections like .NET exposes. Windows provides a notification when the
state (selected, focused etc) of a particular item changes, but it doesn't
provide any information regarding related items. And notifications regarding
other items is independent of each other, so even if you prevent a change to
one item you can't tell Windows to stop fire notifications for the other
items. The collection that .NET uses to wrap this is easy to modify after
changes has occured but it's hard to prevent changes from occuring to it
(maybe that's why there isn't any changing event in the framework)

So basically it is easy to prevent an item from being selected (that is what
my code in practice does). It's much harder to prevent the selection from
*changing* (which is what my code was designed to do) simply because Windows
doesn't tell us what happens next and also doesn't provide any way for us to
stop the entire chain of notifications.

One fix is as follows. Change the if ((nmlv.uNewState... to the following
instead:

if ((nmlv.uOldState & LVIS_SELECTED) != LVIS_SELECTED)
&& ((nmlv.uNewState & LVIS_SELECTED) == LVIS_SELECTED)
{
// Item is being selected
ItemChangingEventArgs e = new ItemChangingEventArgs(nmlv.iItem);
OnSelectedIndexChanging(e);
if (e.Cancel)
{
m.Result = new IntPtr(1);
return;
}
}
elseif ((nmlv.uOldState & LVIS_SELECTED) == LVIS_SELECTED)
&& ((nmlv.uNewState & LVIS_SELECTED) != LVIS_SELECTED)
{
// Item is being deselected
ItemChangingEventArgs e = new ItemChangingEventArgs(nmlv.iItem);
OnSelectedIndexChanging(e);
if (e.Cancel)
{
m.Result = new IntPtr(1);
return;
}
}


This works better, but it still has a problem. If you prevent an item from
being deselected you must also prevent any other item from being selected.
Otherwise you'll see two selected items. And even if you do that there is
still a problem; once you allow the selection to change you might end up
with the old item still selected (Windows doesn't do anything with its state
unless you click on it). I was thinking that maybe prevent focus changes
(i.e. prevent the LVIS_FOCUSED (0x1) state change) would fix this, but I
haven't tried it.

/claes
Post by Keith. O
I re-wrote it in C# -- I have to write codes in C# in my current project --
and tested it. I believe that it's identical to what you show me in VB.NET.
As a result, I could get a SelectedIndexChanging event (Thanks Claes :-) )
But the event occurs "twice." So I get a popup prompt twice (see my test
client code below.)
How can I prevent the event occurs twice or how can I filter unnecessary
event?
----------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace SelectTest
{
public partial class ListViewEx : ListView
{
const int WM_USER = 0x0400;
const int WM_NOTIFY = 0x4e;
const int OCM_BASE = WM_USER + 0x1C00;
const int OCM_NOTIFY = OCM_BASE + WM_NOTIFY;
const int LVN_FIRST = 0 - 100;
const int LVN_ITEMCHANGING = LVN_FIRST - 0;
const int LVIF_STATE = 0x0008;
const int LVIS_SELECTED = 0x0002;
[StructLayout(LayoutKind.Sequential)]
public struct NMHDR
{
public IntPtr hwndFrom;
public int idFrom;
public int code;
}
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
public struct NMLISTVIEW
{
public NMHDR hdr;
public int iItem;
public int iSubItem;
public int uNewState;
public int uOldState;
public int uChanged;
public POINT ptAction;
public int lParam;
}
public delegate void SelectedIndexChangingEventHandler (object
sender, ItemChangingEventArgs e );
public event SelectedIndexChangingEventHandler
SelectedIndexChanging;
protected virtual void
OnSelectedIndexChanging(ItemChangingEventArgs
e)
{
SelectedIndexChanging(this, e);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == OCM_NOTIFY)
{
NMHDR nm = (NMHDR)m.GetLParam(typeof(NMHDR));
if (nm.code == LVN_ITEMCHANGING)
{
NMLISTVIEW nmlv =
(NMLISTVIEW)m.GetLParam(typeof(NMLISTVIEW));
if ( ( nmlv.uChanged & LVIF_STATE ) == LVIF_STATE)
{
if ((nmlv.uNewState & LVIS_SELECTED) ==
LVIS_SELECTED)
{
ItemChangingEventArgs e = new
ItemChangingEventArgs(nmlv.iItem);
OnSelectedIndexChanging(e);
if (e.Cancel)
{
m.Result = new IntPtr(1);
return;
}
}
}
}
}
base.WndProc(ref m);
}
public ListViewEx()
{
InitializeComponent();
}
}
public class ItemChangingEventArgs : CancelEventArgs
{
int m_index;
public ItemChangingEventArgs(int index)
{
m_index = index;
}
public int Index
{
get
{
return m_index;
}
}
}
}
----------------------------------------
----------------------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace SelectTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void OnSelectedIndexChanging(object sender,
ItemChangingEventArgs e)
{
if (DialogResult.Cancel == MessageBox.Show("Change selected
item?", "", MessageBoxButtons.OKCancel))
{
e.Cancel = true;
}
}
}
}
----------------------------------------
Thanks in advance,
Keith
Keith. O
2006-04-11 19:41:02 UTC
Permalink
Thanks for your time again, Claes. But I still have some problems... I might
be better to avoid using list view control instead of just avoiding the event
:'-(

Anyway, thank you. I leant a lot from your code and insight :-)

Keith
Post by Claes Bergefall
Interesting. This is actually the expected behaviour (I'll get back to that
further down), but apparently there is a bug in my code that causes it to
work only if you throw up something that gets focus away from the listview
(e.g. a message box)
In it's current form, my code only work properly for preventing new nodes
from being selected. I guess that is what most people want because no one
has ever said anything about it (I've posted that code to others as well)
:-)
The intended behaviour is to follow the behaviour of the
SelectedIndexChanged event, which actually fires twice when changing a
selection. It fires once when the old node is being deselected and once when
the new node is being selected. Fixing my code though was harder than I
expected. The Windows API works on an item level, it has no concept of
collections like .NET exposes. Windows provides a notification when the
state (selected, focused etc) of a particular item changes, but it doesn't
provide any information regarding related items. And notifications regarding
other items is independent of each other, so even if you prevent a change to
one item you can't tell Windows to stop fire notifications for the other
items. The collection that .NET uses to wrap this is easy to modify after
changes has occured but it's hard to prevent changes from occuring to it
(maybe that's why there isn't any changing event in the framework)
So basically it is easy to prevent an item from being selected (that is what
my code in practice does). It's much harder to prevent the selection from
*changing* (which is what my code was designed to do) simply because Windows
doesn't tell us what happens next and also doesn't provide any way for us to
stop the entire chain of notifications.
One fix is as follows. Change the if ((nmlv.uNewState... to the following
if ((nmlv.uOldState & LVIS_SELECTED) != LVIS_SELECTED)
&& ((nmlv.uNewState & LVIS_SELECTED) == LVIS_SELECTED)
{
// Item is being selected
ItemChangingEventArgs e = new ItemChangingEventArgs(nmlv.iItem);
OnSelectedIndexChanging(e);
if (e.Cancel)
{
m.Result = new IntPtr(1);
return;
}
}
elseif ((nmlv.uOldState & LVIS_SELECTED) == LVIS_SELECTED)
&& ((nmlv.uNewState & LVIS_SELECTED) != LVIS_SELECTED)
{
// Item is being deselected
ItemChangingEventArgs e = new ItemChangingEventArgs(nmlv.iItem);
OnSelectedIndexChanging(e);
if (e.Cancel)
{
m.Result = new IntPtr(1);
return;
}
}
This works better, but it still has a problem. If you prevent an item from
being deselected you must also prevent any other item from being selected.
Otherwise you'll see two selected items. And even if you do that there is
still a problem; once you allow the selection to change you might end up
with the old item still selected (Windows doesn't do anything with its state
unless you click on it). I was thinking that maybe prevent focus changes
(i.e. prevent the LVIS_FOCUSED (0x1) state change) would fix this, but I
haven't tried it.
/claes
Post by Keith. O
I re-wrote it in C# -- I have to write codes in C# in my current project --
and tested it. I believe that it's identical to what you show me in VB.NET.
As a result, I could get a SelectedIndexChanging event (Thanks Claes :-) )
But the event occurs "twice." So I get a popup prompt twice (see my test
client code below.)
How can I prevent the event occurs twice or how can I filter unnecessary
event?
----------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace SelectTest
{
public partial class ListViewEx : ListView
{
const int WM_USER = 0x0400;
const int WM_NOTIFY = 0x4e;
const int OCM_BASE = WM_USER + 0x1C00;
const int OCM_NOTIFY = OCM_BASE + WM_NOTIFY;
const int LVN_FIRST = 0 - 100;
const int LVN_ITEMCHANGING = LVN_FIRST - 0;
const int LVIF_STATE = 0x0008;
const int LVIS_SELECTED = 0x0002;
[StructLayout(LayoutKind.Sequential)]
public struct NMHDR
{
public IntPtr hwndFrom;
public int idFrom;
public int code;
}
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
public struct NMLISTVIEW
{
public NMHDR hdr;
public int iItem;
public int iSubItem;
public int uNewState;
public int uOldState;
public int uChanged;
public POINT ptAction;
public int lParam;
}
public delegate void SelectedIndexChangingEventHandler (object
sender, ItemChangingEventArgs e );
public event SelectedIndexChangingEventHandler
SelectedIndexChanging;
protected virtual void
OnSelectedIndexChanging(ItemChangingEventArgs
e)
{
SelectedIndexChanging(this, e);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == OCM_NOTIFY)
{
NMHDR nm = (NMHDR)m.GetLParam(typeof(NMHDR));
if (nm.code == LVN_ITEMCHANGING)
{
NMLISTVIEW nmlv =
(NMLISTVIEW)m.GetLParam(typeof(NMLISTVIEW));
if ( ( nmlv.uChanged & LVIF_STATE ) == LVIF_STATE)
{
if ((nmlv.uNewState & LVIS_SELECTED) == LVIS_SELECTED)
{
ItemChangingEventArgs e = new
ItemChangingEventArgs(nmlv.iItem);
OnSelectedIndexChanging(e);
if (e.Cancel)
{
m.Result = new IntPtr(1);
return;
}
}
}
}
}
base.WndProc(ref m);
}
public ListViewEx()
{
InitializeComponent();
}
}
public class ItemChangingEventArgs : CancelEventArgs
{
int m_index;
public ItemChangingEventArgs(int index)
{
m_index = index;
}
public int Index
{
get
{
return m_index;
}
}
}
}
----------------------------------------
----------------------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace SelectTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void OnSelectedIndexChanging(object sender,
ItemChangingEventArgs e)
{
if (DialogResult.Cancel == MessageBox.Show("Change selected
item?", "", MessageBoxButtons.OKCancel))
{
e.Cancel = true;
}
}
}
}
----------------------------------------
Thanks in advance,
Keith
Cerebrus
2006-04-07 20:24:44 UTC
Permalink
Hi Claes,

You might not believe this, but I was about to post this very link as a
solution to this problem (I have it saved it my favourites for some
time now !), but later thought that the problem Kieth was facing might
not be directly concerned with your solution. ;-))

Regards,

Cerebrus.
Claes Bergefall
2006-04-10 15:54:44 UTC
Permalink
I'm flattered :-)
Apparently though it doesn't work as expected. It can only be used to
prevent items from being selected (see my reply to the OP)

/claes
Post by Cerebrus
Hi Claes,
You might not believe this, but I was about to post this very link as a
solution to this problem (I have it saved it my favourites for some
time now !), but later thought that the problem Kieth was facing might
not be directly concerned with your solution. ;-))
Regards,
Cerebrus.
Abhishek Chandra
2010-08-08 10:16:00 UTC
Permalink
Hi,
I have modified the above code and make it perform two things on cancel

1. Stop the unselection of current item.
1. Stop the selection of next item.

Also the user will get the event only once so client need not handle two messages.

-------------------------------------------------------LISTVIEWEX---------------------------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace SelectTest
{
public partial class ListViewEx : ListView
{
const int WM_USER = 0x0400;
const int WM_NOTIFY = 0x4e;
const int OCM_BASE = WM_USER + 0x1C00;
const int OCM_NOTIFY = OCM_BASE + WM_NOTIFY;
const int LVN_FIRST = 0 - 100;
const int LVN_ITEMCHANGING = LVN_FIRST - 0;
const int LVIF_STATE = 0x0008;
const int LVIS_UNSELECTED = 0x0000;
const int LVIS_FOCUSED = 0x0001;
const int LVIS_SELECTED = 0x0002;
const int LVIS_SELECTED_FOCUSED = 0x0003;

[StructLayout(LayoutKind.Sequential)]
public struct NMHDR
{
public IntPtr hwndFrom;
public int idFrom;
public int code;
}
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
public struct NMLISTVIEW
{
public NMHDR hdr;
public int iItem;
public int iSubItem;
public int uNewState;
public int uOldState;
public int uChanged;
public POINT ptAction;
public int lParam;
}
public delegate void ItemDeselectingEventHandler(object sender, ItemChangingEventArgs e);
public event ItemDeselectingEventHandler ItemDeselecting;
private bool m_cancel;

protected virtual void OnItemDeselecting(ItemChangingEventArgs e)
{
ItemDeselecting(this, e);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == OCM_NOTIFY)
{
NMHDR nm = (NMHDR)m.GetLParam(typeof(NMHDR));
if (nm.code == LVN_ITEMCHANGING)
{
NMLISTVIEW nmlv = (NMLISTVIEW)m.GetLParam(typeof(NMLISTVIEW));
ItemStateChanging(ref m, ref nmlv);
}
}
base.WndProc(ref m);
}
private void ItemStateChanging(ref Message m, ref NMLISTVIEW nmlv)
{
if ((nmlv.uChanged & LVIF_STATE) == LVIF_STATE)
{
if ((nmlv.uOldState == LVIS_SELECTED) || //FROM ITEM
(nmlv.uNewState == LVIS_UNSELECTED))
{
if (m_cancel)
{
m.Result = new IntPtr(1);
m_cancel = false;
}
else
{
ItemChangingEventArgs e = new ItemChangingEventArgs(nmlv.iItem,this.Items[nmlv.iItem]);
OnItemDeselecting(e);
if (e.Cancel)
{
m.Result = new IntPtr(1);
m_cancel = true;
}
}
}
else if ((nmlv.uOldState == LVIS_UNSELECTED) || //TO ITEM
(nmlv.uNewState == LVIS_SELECTED) ||
(nmlv.uNewState == LVIS_SELECTED_FOCUSED))
{
if (m_cancel)
{
m.Result = new IntPtr(1);
m_cancel = false;
}
}
}
}

}
public class ItemChangingEventArgs : CancelEventArgs
{
int m_index;
ListViewItem m_item;
public ItemChangingEventArgs(int index, ListViewItem item)
{
m_index = index;
m_item=item;
}
public int Index
{
get
{
return m_index;
}
}
public ListViewItem Item
{
get
{
return m_item;
}
}

}
}

---------------------------------------Relevant CLIENT CODE(partial)-------------------------------------


const string CLEAN = "CLEAN";
private void listView1_ItemDeselecting(object sender, SelectTest.ItemChangingEventArgs e)
{
if (IsDirty())/// Any condition which make data related to current row dirty
{
DialogResult result = MessageBox.Show("Do you want to save", this.Text, MessageBoxButtons.YesNoCancel);
if (result == DialogResult.Cancel)//Prevent going to next row
{
e.Cancel = true;
}
else if (result == DialogResult.Yes)
{
//This text box contains hard-coded string
//Any change in the name makes it dirty
txtbx1.Text = CLEAN;//Save the data and move to next row
}
else// move to next row without saving
{ }

}

}

private bool IsDirty()
{
return (txtbx1.Text != CLEAN);
}


Hope this helps.

-Abhishek Chandra
Pune, India.


From http://www.developmentnow.com/g/30_2006_4_0_0_732210/How-to-cancel-SelectedIndexChanged-event-in-ListView-control.htm

Posted via DevelopmentNow.com Groups
http://www.developmentnow.com/g/

Loading...