DataGrid column with button that opens dialog to edit cell value, how?

Mar 24, 2009 at 1:05 PM
For certain columtypes I would like the following behaviour:
 - The column will display an "Edit..." button
 - Clicking on the "Edit..." button will result in a dialog being opened
 - When closing the dialog an object is returned, and this object is returned through the column's data binding as a new property value of the bound source object property

Is this possible?  Have someone else done something similar?

I guess I should start by looking at the DataGridTemplateColumn?  But what should the DataTemplate and EditTemplate be?  At first I thought it should be a Button, but a Button has no usable dependency property to bind the source object property to.  And how should I transfer the value resulting from the popup dialog when it's closed down?

Thanx!


- Steinar
Coordinator
Mar 24, 2009 at 9:10 PM
You might consider only providing a CellTemplate with the button. After your dialog completes, you could just set the property on the data item. If you want to make this more generic, then create a property on your custom column type that is of type Binding and then use the Binding API to get and set the property.

Ben
Mar 25, 2009 at 2:25 PM

Can I use just a button?  Don't I need to wrap it in some other control that can hold the click handler, and find a reference to the row item?

On that note: does anyone have an example of a control in a cell template that finds a reference to a row item?

Mar 25, 2009 at 3:23 PM
I did something like this. I have a edit button that opens a dialog and when the user clicks on save in the dialog I commit the changes else I revered.

in the xaml I use a DataGridTemplateColumn with with the button in in. On the button I have a click event handler I create the dialog with the selected item put in the constructor.
This object I edit. because I send the SelectedItem object it is exactly the same as the one in the datagrid and I only have to use databinding and INotifyPorpertyChanged correctly

<

 

wpftk:DataGridTemplateColumn>

 

 

 

<wpftk:DataGridTemplateColumn.CellTemplate>

 

 

 

<DataTemplate>

 

 

 

<Button Content="Edit" Click="EditButton_Click"/>

 

 

 

</DataTemplate>

 

 

 

</wpftk:DataGridTemplateColumn.CellTemplate>

 

 

 

</wpftk:DataGridTemplateColumn>


 



private

 

void EditButton_Click(object sender, RoutedEventArgs e)

 

{

 

 

CustomerDetailView view = new CustomerDetailView(this.dgCustomers.SelectedItem as CustomerVM);

 

view.ShowDialog();

}

Mar 26, 2009 at 5:47 PM

Thanx for the code examples.

In the button click event handler I'm attempting to navigate my way up to the DataGrid or the item, and the property on the item.  I've finally succeeded in finding the item, only to find that it was a NewItemPlaceholder (since this was on an empty collection and what I see is the placeholder row at the bottom).

Unfortunately I don't know the actual type of the real items here.  The DataGrid is part of a control created by walking over the object being edited, using reflection.

Any ideas?

Here's the code I used to find the item:
        private static void OpenDialogForCollectionItem(object sender, RoutedEventArgs e)
        {
            Button editButton = sender as Button;
            DataGridCell editButtonCell = FindEditButtonCell(editButton);
            if (editButtonCell == null)
            {
                return;
            }

            DataGridColumn column = editButtonCell.Column;
            string propertyName = (string) column.Header;
            object item = FindCellItem(editButtonCell);
        }

        private static object FindCellItem(DataGridCell editButtonCell)
        {
            DataGridCellsPanel cellParent = (DataGridCellsPanel) VisualTreeHelper.GetParent(editButtonCell);
            ItemsPresenter itemsPresenter = (ItemsPresenter) VisualTreeHelper.GetParent(cellParent);
            DataGridCellsPresenter anotherParent = (DataGridCellsPresenter) VisualTreeHelper.GetParent(itemsPresenter);
            return anotherParent.Item;
        }

        private static DataGridCell FindEditButtonCell(Button editButton)
        {
            ContentPresenter editButtonParent = (ContentPresenter) VisualTreeHelper.GetParent(editButton);
            if (editButtonParent == null)
            {
                return null;
            }

            DataGridCell editButtonCell = (DataGridCell) editButtonParent.Parent;
            return editButtonCell;
        }

Mar 26, 2009 at 6:08 PM
Well... one possibility would be if I succeds in navigating the hierarchy to find the DataGrid (the DataGridCellPanel, which is the parent of the DataGridCell, has a property ParentDataGrid, but that property isn't public).

Then I can find the BindingExpression from the ItemsSource, and find the source of the databinding, and get the type of the property, and try to infer the type of the row item.

But this is awfully complicated, and fragile, and Can't Be Right! (tm).
Mar 30, 2009 at 10:14 AM
Does comparing to ItemCollection.NewItemPlaceholder and acting on the result help you any?