Home » WPF

Listview/Gridview Question Again

This post is similar to another post listed here http://social.msdn.microsoft.com/Forums/en/wpf/thread/9ac8f20e-0494-40b9-b230-fb120fd4e9b0, but I have reposted because I'm not sure it completely answered what the post was asking.

Here is the previous post ==================================================================

I have a simple WPF ListView that is bound to a Dataset.  The ListView defines a number of columns using the following format:











There are multiple columns.  My question is simple, If I have a button or textbox in one of the columns, and I click on on the column/row, how do I get the DataRow that is selected?  The RoutedEventArgs (in the case of clicking on a button) doesn't seem to provide that information.  If I set the IsSynchronizedWithCurrentItem Property of the View.CurrentPosition doesn't seem to report the DataRow Index of the Gridvew row index.


The answers for this post showed how to get the data context from the button that was pressed, but not how to get the row index where the button resides.  I have a need to get other information from the same row based on whether or not that button was pushed.  Specifically, I have two buttons on a row - connect and disconnect.  Every time the "connect" button is pressed for a row, I need to enable/disable the "disconnect" button accordingly.

Any help would be greatly appreciated.


10 Answers Found


Answer 1

Why not just use ListView.SelectedIndex or ListView.SelectedItem?

Answer 2

Thanks, Brian.  I guess I worded my question poorly.  As you stated, I was able to get the index, but how do I get to the "disconnect" button when the "connect" button was pressed?  As stated above, these two buttons are on the same row.  I was assuming that I could access this information if I had the index of the row of the "connect" button that was pressed.

Answer 3

Well is sounds like in the particular scenario you are using the wrong control. Since your two states are Connected and Disconnected, why not use a ToggleButton.

privatevoid ToggleButton_Click(object sender, RoutedEventArgs e)
      ToggleButton button = sender as ToggleButton;
      if (button.IsChecked)

Answer 4

To answer your question, you can get the actual ListViewItem by using:

ListViewItem item = (ListViewItem)_listView.ItemContainerGenerator.ContainerFromItem(_listView.SelectedItem);


ListViewItem item = (ListViewItem)_listView.ItemContainerGenerator.ContainerFromIndex(_listView.SelectedIndex);
You could use either one of those methods in the Button_Click.

Answer 5

It's true that I will have two states, but that's not the primary purpose for the buttons.  The "Connect" button will actually connect the user to a particular database.  While in the disconnected state, the "Disconnect" button will be disabled.  Once the user presses the "Connect" button on a row that corresponds to a database in which to connect, the "Disconnect" button will then be enabled and will serve to disconnect the user from that database.

Is there a way to access the "Disconnect" button when you have the information from the "Connect" button and the selected index in the ListView?


Answer 6

How is that different from a toggle button?  When the use toggles the button into the checked state or "connects", you run code to connect the user to the corresponding database.  When the user unchecks or "disconnects" the toggle button, you run code that disconnects the user from the database.

Another question you should be asking yourself are do these buttons belong in the ListView row?  I am assuming they can only be connected to a single database at a time.  It seems as if you should move your buttons outside the ListView and place them maybe under the ListView.  Have the user select a Database from the ListView first then enable/disable the buttons based on the selection and run your code when neccessary.


Answer 7

I appreciate the suggestions on different implementations, but I just want to know if there is there a way to access the "Disconnect" button when you have the information from the "Connect" button and the selected index in the ListView?

Answer 8

Okay here is a hack you can try.  First we want to save off the GridViewRowPresenter in the tag of the button: 

<GridViewColumn><GridViewColumn.CellTemplate><DataTemplate><Buttonx:Name="_connect"Click="Button_Click"Tag="{Binding RelativeSource={RelativeSource AncestorType={x:Type GridViewRowPresenter}}}">Connect</Button></DataTemplate></GridViewColumn.CellTemplate></GridViewColumn>

Now we add some code to the Buutton click event handler and use a very common method for searching the visual tree.

privatevoid Button_Click(object sender, RoutedEventArgs e)
   Button button = sender as Button;
   GridViewRowPresenter rowPresenter = button.Tag as GridViewRowPresenter;

   if (rowPresenter != null)

    Button disconnectButton = FindVisualChildByName<Button>(rowPresenter, "_disconnect");
    if (disconnectButton != null)
     //do some code

  public T FindVisualChildByName<T>(DependencyObject parent, string name) where T : DependencyObject
   for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
    var child = VisualTreeHelper.GetChild(parent, i);

    string controlName = child.GetValue(Control.NameProperty) asstring;

    if (controlName == name)
     return child as T;
     T result = FindVisualChildByName<T>(child, name);

     if (result != null)
      return result;

It's ugly but it works.

EDIT: Be sure to name your buttons with the x:Name attribute so you can find them.


Answer 9

That works, Brian.  I do have one question though.  Why is this considered a hack?  Even though what I'm doing doesn't seem to be the ideal for this usage, it seems like the need to retrieve and manipulate peer controls in a ListView/GridView would be common.

Anyway, thanks again.


Answer 10

The ListView is not meant to be used this way.  WPF has a declarative UI that is driven by data binding.  This would be the old WinForm way of doing things, but in WPF this is not the preferred way to do it, therefore it is a hack.

For example, in this scenario lets assume that each row is bound to a Database object.  This object would probably have a Name property, a ConnectionString property, and a boolean IsConnected property that specified if it was connected or not.  You could then bind the ConnectButton.IsEnabled property to the Database.IsConnected property and the DisconnectButton.IsEnabled property to the Database.IsConnected property, using a converter to inverse the value.  Now when you click the ConnectedButton, through databinding this would fire the setter of the bound database object, which could contain code in its setter to actually connect, and then through databinding the DisconnectButton would autumatically enable and ConnectButton would disable.  All without writing a single line of code in the UI.

There are many different more elegant WPF preferred approaches, this was just one example.  Either way, I am glad it worked for you.



<< Previous      Next >>

Microsoft   |   Windows   |   Visual Studio   |   Sharepoint   |   Azure