0
votes

We're trying to add "block select" to the Silverlight DataGrid control: The user should be able to select, for example, a rectangle of cells from ( col 4, row 5 ) to ( col 6, row 8 ).

What we're doing is saving the two corners of the selection, and indicating it visually by setting the background color of the cells. We've run into trouble with scrolling, because the cell objects are recycled, along with their formatting. So you scroll up, and as the selected cells vanish off the bottom, bars of cells coming in at the top are colored! I've tried saving a List of the actual cell objects and the "new" colored cells are definitely the same DataGridCell instances, though with different content of course.

We're able to get our hands on the scrollbars via the visual tree, so we'll may end up refreshing the selection display in a ValueChanged event handler for the vertical scrollbar.

But I'd like to know if there's a better way. We're not Silverlight experts. Has anybody tried to do this? Is there anything obvious to a Silverlight whiz that we're not even thinking of?

We're not going to buy anything. For corporate bureaucracy reasons, unfortunately, that's not an option.

1

1 Answers

3
votes

Why not include that in you viewmodel. What i would do is create a nested enumerable viewmodel of the interaction, ie if the datagrid is bound to a IEnumerable of T where T is a viewmodel representing each row, id have something like IndexSelected on that viewmodel. Then id bind the back color using a valueconverter of some sort to that indexselected property,

public class RowViewModel
{
   public string Col1 { get; set; }
   public string Col2 { get; set; }
   public string Col3 { get; set; }

   public int IndexSelected { get; private set; }

   //Id also make a command here or something to set the indexselected but ill leave that for you :)

}

public class GridViewModel
{
    public ObservableCollection<RowViewModel> Rows; // Bound to Datagrid.ItemsSource.
}

Notice the converter param on the indexselected binding holds the index of the column

 <sdk:DataGrid>
        <sdk:DataGrid.Columns>
            <sdk:DataGridTemplateColumn Header="Col1">
                <sdk:DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Grid Background="{Binding IndexSelected, Converter={StaticResource IndexToColorConverter}, ConverterParameter=1}">
                            <TextBlock Text="{Binding Col1}" />
                        </Grid>
                    </DataTemplate>
                </sdk:DataGridTemplateColumn.CellTemplate>
            </sdk:DataGridTemplateColumn>
            <sdk:DataGridTemplateColumn Header="Col2">
                <sdk:DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Grid Background="{Binding IndexSelected, Converter={StaticResource IndexToColorConverter}, ConverterParameter=2}">
                            <TextBlock Text="{Binding Col2}" />
                        </Grid>
                    </DataTemplate>
                </sdk:DataGridTemplateColumn.CellTemplate>
            </sdk:DataGridTemplateColumn>

        </sdk:DataGrid.Columns>
    </sdk:DataGrid>

and all the converter will do is check if the indexselected bound property equals the parameter (which is the index of the column)

 public class IndexToColorConverter : IValueConverter
 {
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
         if (value == parameter)
        {
            return new SolidColorBrush(Colors.Red);
        }
        return new SolidColorBrush(Colors.White);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}