Search code examples
wpfdata-bindinglinq-to-sqlwpfdatagrid

Getting edited value of DataGridTemplateColumn in DataGrid bound to LINQ query results


I have a WPF app with a datagrid that I am binding to a custom LINQ to SQL query in my ViewModel that brings together columns from two different tables:

public ICollectionView SetsView { get; set; }

public void UpdateSetsView()
{
    var sets = (from s in dbContext.Sets
                join o in dbContext.SetParts on s.ID equals o.SetID into g1
                select new
                {
                    s.ID,
                    s.SetNumber,
                    s.SetTitle,
                    s.SetType,
                    s.SetNotes,
                    s.SetUrl,
                    s.HaveAllParts,
                    s.NumberOfSets,
                    s.IsBuilt,
                    s.DateAdded,
                    s.LastModified,
                    UniqueParts = g1.Count(),
                    TotalParts = g1.Sum(o => o.Quantity)
                }
                );
    SetsView = CollectionViewSource.GetDefaultView(sets);
}

The SetsView collection is bound to my datagrid and since I need to be able to edit the value of SetNotes for any row and save it back to the Sets table in my database I added an event handler for CellEditEnding ( CellEditEnding="dgST_Sets_CellEditEnding") to the DataGrid definition and created this column:

<DataGridTemplateColumn Header="Set Notes" 
                        SortMemberPath="SetNotes" 
                        Width="*">
    <DataGridTemplateColumn.HeaderStyle>
        <Style TargetType="{x:Type DataGridColumnHeader}">
            <Setter Property="HorizontalContentAlignment" Value="Center"/>
        </Style>
    </DataGridTemplateColumn.HeaderStyle>
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding SetNotes, Mode=OneWay}" Margin="5,0,5,0"
                        HorizontalAlignment="Stretch" VerticalAlignment="Center" />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
    <DataGridTemplateColumn.CellEditingTemplate>
        <DataTemplate>
            <TextBox Text="{Binding SetNotes, Mode=OneWay}" Margin="5,0,5,0"
                        HorizontalAlignment="Stretch" VerticalAlignment="Center" 
                        />
        </DataTemplate>
    </DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>

The issue is that when I run the application and edit the Set Notes column in any row I cannot work out how to get the new value of the edited cell from the event args. I thought I could cast the event args EditingElement instance to a TextBox (see handler below) but when I run the app, edit a row and change a value of SetNotes the type of EditingElement is ContentPresenter not TextBox and for the life of me I can't work out how to get the changed value.

private void dgST_Sets_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
    string newValue = ((TextBox)e.EditingElement).Text;

    //Code here to update table
}

Please remember I am binding to a custom LINQ to SQL query so this is not a classic model binding issue. Also note, when binding the value of SetNotes in my template column I have no option but using Mode=OneWay as using any other option gives me runtime errors about accessing a read only property - could this somehow be the issue?

I've spent hours on this and googled endlessly with no joy - can anyone help me out please?


Solution

  • This should work:

    private void dgST_Sets_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
    {
        ContentPresenter cp = e.EditingElement as ContentPresenter;
        if (cp != null && VisualTreeHelper.GetChildrenCount(cp) > 0)
        {
            TextBox textBox = VisualTreeHelper.GetChild(cp, 0) as TextBox;
            if (textBox != null)
            {
                string newValue = textBox.Text;
            }
        }
    }