0

I have a ListView with a bound ItemsSource and a GridViewColumns to display a given items property. Here is a snippet of the important bits:

<ListView Name="listView1" ItemsSource="{Binding Path=listItemCollection}" DataContext="{Binding ListItem}">
    <ListView.View>
        <GridView x:Name="gridViewMain">
            <GridViewColumn x:Name="listViewItemNumberColumn" Width="50">
                <GridViewColumnHeader>#</GridViewColumnHeader>
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock x:Name="idTextBlock" KeyboardNavigation.IsTabStop="False" HorizontalAlignment="Center" Text="{Binding Path=Id}"/>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>

            <GridViewColumn x:Name="listViewItemNameColumn" Width="500">
                <GridViewColumnHeader>Name</GridViewColumnHeader>
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <TextBox x:Name="nameTextBox" TextChanged="nameTextBox_TextChanged" Text="{Binding Path=ItemName, UpdateSourceTrigger=PropertyChanged}"/>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
            ...

I want to be able to focus on a specific field/textbox within a user-selected ListViewItem. I am able to find the ListViewItem from a given index using this code:

listView1.ItemContainerGenerator.ContainerFromIndex(i);

All is well and good so far. That is until I want to actually access the content within the ListViewItem. Instead of ListViewItem.Content returning a group of controls which I am expecting, it returns my custom class ListItem. Here is a snippet of what that class looks like:

public class ListItem : INotifyPropertyChanged {
    public event PropertyChangedEventHandler PropertyChanged;

    public TextBlock idTextBlock;
    public GridView gridViewMain;

    public bool Selected { get; set; }
    public string ItemName { get; set; }

I am completely lost in how I would for example focus onto the nameTextBox text box control within a ListViewItem.

Is it possible to somehow link the controls such as the nameTextBox and idTextBlock to my custom ListItem class?

Anatoliy Nikolaev
  • 22,370
  • 15
  • 69
  • 68
AquaGeneral
  • 155
  • 1
  • 19
  • Just a suggestion. Why you are using GridView inside ListView. Why you are not using GridView only? I see no sense in using ListView here, just use GridView. – fhnaseer Mar 18 '13 at 05:25
  • I don't remember how exactly I went down the road into adding a GridView inside of ListView, but according to the [documentation](http://msdn.microsoft.com/en-us/library/ms610560.aspx) it makes sense for what I have: _Represents a view mode that displays data items in columns for a ListView control._ – AquaGeneral Mar 18 '13 at 07:41
  • GridView is a kind of list with additional options (columns). What I see in your code is that ListView has one child (GridView) and that child contains multiple rows. May be this approach will be good if you want to display multiple GridViews. – fhnaseer Mar 18 '13 at 07:46

1 Answers1

0

There is a property in ListView SelectedItem. You need to bind this to.

In your view

<ListView Name="listView1" ItemsSource="{Binding Path=listItemCollection}" SelectedItem="{Binding SelectedListItem}" DataContext="{Binding ListItem}">

And in your class where you have listItemCollection, add a SelectedListItem variable.

public ListViewItem SelectedListViewItem {get; set;}

EDIT:

Remove ListView. Use DataGridOnly.

XAML:

<DataGrid ItemsSource="{Binding MyItems}" SelectedItem="{Binding SelectedItem}">
     <DataGrid.Columns>
         <DataGridTextColumn Binding="{Binding Name}" Header="Name" Width="175" />
         <DataGridTextColumn Binding="{Binding Path}" Header="Path" Width="75" />
     </DataGrid.Columns>
</DataGrid>

ViewModel:

ObservableCollection<MyItem> MyItems {get; set;}
MyItem SelectedItem {get; set;}

public class MyItem : INotifyPropertyChanged
{
    public string Name {get; set;}
    public string Path {get; set;}
}
fhnaseer
  • 7,159
  • 16
  • 60
  • 112
  • Part of the problem is that SelectedListViewItem will actually return a ListItem of mine. Trying what you said gives me the following error when I keep use the ListViewItem type on SelectedListViewItem: `A first chance exception of type 'System.NotSupportedException' occurred in System.dll Additional information: TypeConverter cannot convert from AutoOutlook.ListItem.` – AquaGeneral Mar 18 '13 at 07:58
  • what is type of "listItemCollection"? SelectedListViewItem should have that type, – fhnaseer Mar 18 '13 at 08:35
  • It is an `ObservableCollection`. I obviously am doing something wrong, but how else could I hand out numerous properties (eg, Id and ItemName) any other way? – AquaGeneral Mar 18 '13 at 08:48
  • I am having doubt with ListView in XAML. Try to remove it and use DatGrid only. I have updated code. Try that, – fhnaseer Mar 18 '13 at 09:13
  • I have almost got a fully working test using the DataGrid only, but I really don't like the idea of being required to heavily customize the look to bring it back to what the ListView looks like. I guess it will have to do though if it's the only way to make my job easier. I'll give an update once I know more. – AquaGeneral Mar 19 '13 at 06:40
  • So, many days later and I still have gotten no where. Replacing the ListView with a DataGrid will change far too much of the applications feel, and really should be literally the only and last resort. I've tried mixing in TextBox members to the `ListItem` class, only for me to end up lost in how that would actually be implemented. – AquaGeneral Mar 30 '13 at 12:55
  • I also attempted to use the [FindVisualChild](http://stackoverflow.com/questions/980120/finding-control-within-wpf-itemscontrol) method, but I was endlessly confused in getting that to work, since I needed a specific type of control as well (the TextBox I want to focus on). – AquaGeneral Mar 30 '13 at 12:57