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?
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;
}
}
}