Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I access the data object of a DataGridCell in code?

Basically I've bound the datagrid so that it resembles a timetable of subjects - each row represents a semester of subjects, and each cell within that semester represents a subject.

I'm now trying to add drag and drop functionality so that you can drag additional subjects onto the grid, and this will update the underlying datastructure.

I can use some visual tree methods to find the DataGridCell that the user is dragging the new subject to, but I don't know how to access the value (the subject) that the cell is bound to it in order to replace the blank/placeholder value with the new subject. Is there a way to access the underlying value or should I restructure my entire method of creating this program?

An example of the grid and the subjects to be dragged onto it

like image 568
Migwell Avatar asked Mar 12 '13 12:03

Migwell


1 Answers

To get the data of the DataGridCell, you can use it's DataContext and the Column property. How to do that exactly depends on what your row data is, i.e. what items you put in the ItemsSource collection of the DataGrid. Assuming your items are object[] arrays:

// Assuming this is an array of objects, object[],this gets you the 
// row data as you have them in the DataGrid's ItemsSource collection
var rowData = (object[]) DataGrid.SelectedCells[0].Item;
//  This gets you the single cell object
var celldata = rowData[DataGrid.SelectedCells[0].Column.DisplayIndex];

If your row data is more complex, you need to write an according method which translates the Column property and the row data item to the specific value on your row data item.


EDIT:

If the cell you drop your data into is not the selected cell, one option is to get the DataGridRow to which the DataGridCell belongs, using VisualTreeHelper:

var parent = VisualTreeHelper.GetParent(gridCell);
while(parent != null && parent.GetType() != typeof(DataGridRow))
{
    parent = VisualTreeHelper.GetParent(parent);
}
var dataRow = parent;

Then you have the row and can proceed as above.


Furthermore, regarding your question whether you should reconsider the method, I would suggest using custom WPF behavior s.

Behaviors provide a very straight forward way to extend the control's capabilities from C# code, rather the XAML, yet keeping your codebehind clear and simple (which is not only nice to have if you're following MVVM). Behaviors are designed in way that they are reusable and not bound to your specific control.

Here's a good introduction

For your special case, I can only give you an idea of what to do:

Write one DropBehavior for your the TextBlock control (or whatever control you want inside your DataGridCells, which handles the drop. The basic idea is to register according actions to the evnt of the cells in the OnAttached() method of your control.

public class DropBehavior : Behavior<TextBlock>
{
    protected override void OnAttached()
    {
        AssociatedObject.MouseUp += AssociatedObject_MouseUp;
    }

    private void AssociatedObject_MouseUp(object sender, MouseButtonEventArgs e)
    {
        // Handle what happens on mouse up

        // Check requirements, has data been dragged, etc.
        // Get underlying data, now simply as the DataContext of the AssociatedObject
        var cellData = AssociatedObject.DataContext;

    }
}

Note that, parsing the data of the single cell from the row data and the Column property becomes obsolete.

Then you attach this behavior to TextBlocks, which you put inside your cells, using the ContentTemplate of the CellStyle of your DataGrid:

<DataGrid>
    <DataGrid.CellStyle>
        <Style TargetType="DataGridCell">
            <Setter Property="ContentTemplate">
                <Setter.Value>
                    <DataTemplate>
                        <TextBlock Text="{Binding}">
                            <i:Interaction.Behaviors>
                                <yourns:DropBehavior/>
                            </i:Interaction.Behaviors>
                        </TextBlock>
                    </DataTemplate>
                </Setter.Value>

            </Setter>
        </Style>
    </DataGrid.CellStyle>
</DataGrid>

You can find the Behavior<T> baseclass in

System.Windows.Interactivity.dll

I haven't tested it, but I hope it works for you and you get the idea...

like image 130
Marc Avatar answered Nov 10 '22 19:11

Marc