Получение отредактированного значения DataGridTemplateColumn в DataGrid, привязанного к результатам запроса LINQ

#wpf #data-binding #linq-to-sql #wpfdatagrid

#wpf #привязка данных #linq-to-sql #wpfdatagrid

Вопрос:

У меня есть приложение WPF с datagrid, которое я привязываю к пользовательскому запросу LINQ to SQL в моей ViewModel, который объединяет столбцы из двух разных таблиц:

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

Коллекция SetsView привязана к моей datagrid, и поскольку мне нужно иметь возможность редактировать значение SetNotes для любой строки и сохранять его обратно в таблицу Sets в моей базе данных, я добавил обработчик событий для CellEditEnding (CellEditEnding=»dgST_Sets_CellEditEnding») к определению DataGrid и создал этот столбец:

 <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>
  

Проблема в том, что когда я запускаю приложение и редактирую столбец Set Notes в любой строке, я не могу понять, как получить новое значение отредактированной ячейки из аргументов события. Я думал, что смогу преобразовать экземпляр EditingElement аргументов события в текстовое поле (см. обработчик ниже), но когда я запускаю приложение, редактирую строку и изменяю значение SetNotes, тип EditingElement — ContentPresenter, а не TextBox, и, хоть убейте, я не могу понять, как получить измененное значение.

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

    //Code here to update table
}
  

Пожалуйста, помните, что я привязываюсь к пользовательскому запросу LINQ to SQL, поэтому это не проблема привязки классической модели. Также обратите внимание, что при привязке значения SetNotes в столбце моего шаблона у меня нет другого выбора, кроме как использовать Mode = OneWay, поскольку использование любого другого параметра приводит к ошибкам во время выполнения при доступе к свойству только для чтения — может ли это как-то быть проблемой?

Я потратил часы на это и бесконечно гуглил без радости — кто-нибудь может мне помочь, пожалуйста?

Ответ №1:

Это должно сработать:

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

Комментарии:

1. Большое спасибо mm8 — не могу поверить, что я не подумал о обходе визуального дерева, но это работает отлично.

2. действительно сожалею об этом, я думал, что сделал это, но, очевидно, не сейчас 🙂