views:

100

answers:

2

I have a ListView. When I select a row I want that only one cell was selected not the whole row. How can I get this? Here is my styles and templates.

 <ListView x:Name="List"                   
              ItemsSource="{Binding }"  
              ItemContainerStyle="{DynamicResource ListItemStyle}">          
        <ListView.View>
            <GridView AllowsColumnReorder="False">
                <GridViewColumn HeaderContainerStyle="{StaticResource myHeaderStyle}"                                  
                                Header="1"
                                CellTemplate="{StaticResource myCellTemplate1}">                        
                </GridViewColumn>

                <GridViewColumn Header="2"                               
                                HeaderContainerStyle="{StaticResource myHeaderStyle}"
                                HeaderTemplate="{StaticResource myHeaderTemplate}"
                                CellTemplate="{StaticResource cellTemplate2}">                       
                </GridViewColumn>

                <GridViewColumn Header="3" 
                                HeaderContainerStyle="{StaticResource myHeaderStyle}"
                                HeaderTemplate="{StaticResource myHeaderTemplate}"
                                CellTemplate="{StaticResource cellTemplate3}" />

                <GridViewColumn Header="4" 
                                HeaderContainerStyle="{StaticResource myHeaderStyle}"
                                HeaderTemplate="{StaticResource myHeaderTemplate}"
                                CellTemplate="{StaticResource cellTemplate4}"/>

            </GridView>
        </ListView.View>
    </ListView>

     <Style x:Key="ListItemStyle"   TargetType="{x:Type ListViewItem}">             
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate  TargetType="{x:Type ListViewItem}" >
                <Grid SnapsToDevicePixels="True"   Margin="0"  Width="410" x:Name="GridSmall">
                    <Border x:Name="Border"                                                      
                            Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            CornerRadius="0"    />
                    <GridViewRowPresenter x:Name="Rows" />
                </Grid>                    
            </ControlTemplate>                
        </Setter.Value>
    </Setter>
    <Style.Triggers>              
        <Trigger Property="IsSelected" Value="True">
            <Setter Property="Background" Value="Yellow"/>
            <Setter Property="Foreground" Value="Black"/>
        </Trigger>
        <Trigger Property="IsSelected" Value="False">
            <Setter Property="Background" Value="Black"/>
            <Setter Property="Foreground" Value="Green"/>
        </Trigger>
    </Style.Triggers>
</Style>

  <DataTemplate x:Key="myCellTemplate1">
    <DataTemplate.Resources>
        <local:NullIdConverter x:Key="NullIdConverterKey"/>            
    </DataTemplate.Resources>        
    <DockPanel x:Name="RR">
        <TextBlock FontSize="18" x:Name="TxtBl"                        
                   HorizontalAlignment="Center"                       
                   Text="{Binding Path = Id}"/>   
    </DockPanel>      
</DataTemplate>

Thanks.

A: 

If you're using .NET 3.5 SP1 or .NET 4, I'd suggest looking into the DataGrid rather than ListView.

I think it gives you much more flexibility over your data and has a property called SelectionUnit that you can set to "Cell" that gives you the functionality that you desire.

Unfortunately, I don't think there is an easy way to do the same with the ListView.

Scott
A: 

Hi,

Well.....it isn't easy. Like Scott says you may have a lot easier life using SelectionUnit and SelectionMode in .Net 4 and its DataGrid control. But, if you want to do it like you started to then try this:

In XAML (I didn't do the whole thing as Template or a Style, just the one column to get it working) you need code such as this:

<GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <Border Name="myOwnBorder" BorderBrush="Gray" BorderThickness="1,1,1,0" Margin="-6,0,-6,0">
                                <Grid Margin="6,0,6,0">
                                    <TextBlock Text="{Binding}"/>
                                </Grid>
                            </Border>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>

...and then in the code behing (not good design practice but for the sake of demo) create a function such as:

static bool FindBorderInListView(DependencyObject dep, ListView listView, 
            out Border border, out ListViewItem lvItem)
        {
            border = null;
            lvItem = null;

            DependencyObject depObj = dep;
            while (depObj != listView)
            {
                if (border == null && depObj is Border)
                {
                    border = depObj as Border;
                    if (border.Name != "myOwnBorder")
                    {
                        border = null;
                    }
                }
                else if (depObj is ListViewItem)
                {
                    lvItem = depObj as ListViewItem;
                }

                depObj = VisualTreeHelper.GetParent(depObj);
            }
            return border != null && lvItem != null;
        }

and then call it from the PreviewMouseDown event of your ListView:

private void MyList_PreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
        Border border;
        ListViewItem lvItem;

        if (FindBorderInListView(e.OriginalSource as DependencyObject, this.MyList,
            out border, out lvItem))
        {

            ItemContainerGenerator generator = this.MyList.ItemContainerGenerator;

            int rowIndex = generator.IndexFromContainer(lvItem);
            int columnIndex = Grid.GetColumn(border);

            MessageBox.Show("Cell #:" + rowIndex + columnIndex);


        }
    }

Credit where credit is due, Josh Smith worked out how to do this back in about 2007 I think in a reply to an MSDN community question.

Good luck with it! I had to implement something similar in a DataGrid once too.

jameschinnock
Thanks a lot for your answers but the problem is that: I use the keyboard to move through the list, but is highlighted only one cell in row. So I can't use PreviewMouseDown, because i don't use mouse at all. Is it possible? Or I have to move on .NET4????
Void