Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DataGrid SelectionUnit=Cell disables all support for a selected row?

Tags:

wpf

datagrid

.Net 4 WPF DataGrid C# MMVM

When the DataGrid SelectionUnit is full row, wpf databinding and the collectionview take care of letting me know in the viewmodel what is the actively selected item via the view's currentitem property. This works great for readonly grids with the selection mode set to the fullrow.

Now I have an editable grid. So I set the SelectionUnit=Cell to make it easier to spot which cell one is in. Now all of a sudden the grid no longer has any ability to track the selection item. I can't even set SelectedItem when set to cell mode. So now the viewmodel always thinks it's on the first row. I can handle SelectedCellsChanged in the grid to figure out what row I'm on, I just have no way of letting the viewmodel know since the grid's SelectedItem can no longer be set!

I don't understand why the grid can't still have a SelectedItem when in cell select mode.

Short of hardcoding into my grid to cast the ItemSource to my collectionview to call MoveCurrentTo from the SelectedCellsChanged event, is there any other MVVM true way to keep the view's CurrentItem in sync with the grid?

Either that, or I change the grid style to remove or reduce the row highlight effect when I have an editable grid.

like image 754
happyfirst Avatar asked Feb 28 '12 20:02

happyfirst


2 Answers

I found a great solution for this on MSDN using attached properties:

<DataGrid ItemsSource="{Binding}" IsReadOnly="True" SelectionUnit="Cell">
  <DataGrid.CellStyle>
    <Style TargetType="{x:Type DataGridCell}">
      <Style.Triggers>
        <Trigger Property="IsSelected" Value="True">
          <Setter Property="local:DataGridAttachedProperties.IsCellSelected" Value="True"/>
        </Trigger>
        <Trigger Property="IsSelected" Value="False">
          <Setter Property="local:DataGridAttachedProperties.IsCellSelected" Value="False"/>
        </Trigger>
      </Style.Triggers>
    </Style>
  </DataGrid.CellStyle>
  <DataGrid.ItemContainerStyle>
    <Style TargetType="{x:Type DataGridRow}">
      <Style.Triggers>
        <Trigger Property="local:DataGridAttachedProperties.IsCellSelected" Value="True">
          <Setter Property="BorderThickness" Value="2"/>
          <Setter Property="BorderBrush" Value="Red"/>
          <Setter Property="Background" Value="Yellow"/>
          <Setter Property="Opacity" Value="0.7"/>
        </Trigger>
      </Style.Triggers>
    </Style>
  </DataGrid.ItemContainerStyle>
</DataGrid>

And the C#:

public class DataGridAttachedProperties
{
    public static bool GetIsCellSelected(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsCellSelectedProperty);
    }
    public static void SetIsCellSelected(DependencyObject obj, bool value)
    {
        obj.SetValue(IsCellSelectedProperty, value);
    }
    public static readonly DependencyProperty IsCellSelectedProperty =
        DependencyProperty.RegisterAttached("IsCellSelected", typeof(bool), typeof(DataGridAttachedProperties), new UIPropertyMetadata(false,
        (o, e) =>
        {
            if (o is DataGridCell)
            {
                DataGridRow row = VisualTreeHelperEx.FindVisualParent<DataGridRow>(o as DataGridCell);
                row.SetValue(DataGridAttachedProperties.IsCellSelectedProperty, e.NewValue);
            }
        }));
}
public class VisualTreeHelperEx
{
    public static T FindVisualParent<T>(DependencyObject child)
    where T : DependencyObject
    {
        DependencyObject parentObject = VisualTreeHelper.GetParent(child);
        if (parentObject == null) return null;
        T parent = parentObject as T;
        if (parent != null)
        {
            return parent;
        }
        else
        {
            return FindVisualParent<T>(parentObject);
        }
    }
}
like image 82
theartwebreathe Avatar answered Nov 15 '22 09:11

theartwebreathe


I was searching for the same problems and found a simple solution

To access to the row with SelectionUnit set to Cell you have to do:

DataGridXX.SelectedCells[0].item

It works only if you can select only one cell at time (not in Extended mode).

like image 30
Lorimier Thibaut Avatar answered Nov 15 '22 11:11

Lorimier Thibaut