Я столкнулся с вашим вопросом и столкнулся с тем же. Вот моя ситуация и решение, и я думаю, что оно должно работать и для вас (и других). У меня есть сетка данных, которая позволяет вводить новые элементы, поэтому возможные значения идут от 0 до бесконечности. Пользователи должны иметь возможность установить флажок и снять или снять флажок одним нажатием кнопки. Кроме того, есть и другие поля, которые также могут быть обновлены. Мне пришлось создать собственный элемент управления сеткой данных для автоматической фокусировки и начать редактирование флажка:
public class CheckboxDataGrid : DataGrid {
public CheckboxDataGrid() {
EventManager.RegisterClassHandler(typeof(DataGridCell),
DataGridCell.PreviewMouseLeftButtonDownEvent,
new RoutedEventHandler(this.OnPreviewMouseLeftButtonDown));
}
private void OnPreviewMouseLeftButtonDown(object sender, RoutedEventArgs e) {
DataGridCell cell = sender as DataGridCell;
if (cell != null && !cell.IsEditing && !cell.IsReadOnly) {
var parentRow = cell.Parent as DataGridRow;
if (parentRow != null) {
SelectedIndex = parentRow.GetIndex();
}
CurrentCell = new DataGridCellInfo(cell);
DependencyObject obj = FindVisualChild<CheckBox>(cell);
if (obj != null) {
BeginEdit(e);
System.Windows.Controls.CheckBox cb = (System.Windows.Controls.CheckBox)obj;
cb.Focus();
}
}
}
public static TChild FindVisualChild<TChild>(DependencyObject obj) where TChild : DependencyObject {
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) {
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child is TChild) {
return (TChild)child;
} else {
TChild childOfChild = FindVisualChild<TChild>(child);
if (childOfChild != null)
return childOfChild;
}
}
return null;
}
}
Мне также нужен был конвертер, чтобы игнорировать новое сообщение привязки элемента из-за способа, которым WPF обрабатывает новые элементы в сетке данных:
public class IgnoreNewItemPlaceHolderConverter : IValueConverter {
private const string NewItemPlaceholderName = "{NewItemPlaceholder}";
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
if (value != null && value.ToString() == NewItemPlaceholderName)
return DependencyProperty.UnsetValue;
return value;
}
}
Вот соответствующий XAML для сетки данных:
<chkDatagrid:CheckboxDataGrid AutoGenerateColumns="False"
ItemsSource="{Binding ElementName=dgPurchaseOrders, Path=SelectedItem.Releases, NotifyOnSourceUpdated=True}" AlternatingRowBackground="#1E000000"
DockPanel.Dock="Bottom" HorizontalAlignment="Left" SelectedItem="{Binding SelectedRelease, Mode=TwoWay, Converter={StaticResource ignoreNewItemPlaceHolderConverter}}"
MinHeight="100">
<b:Interaction.Triggers>
<b:EventTrigger EventName="RowEditEnding">
<b:InvokeCommandAction Command="{Binding ReleaseRowEditEndingCommand}" CommandParameter="{Binding SelectedRelease}"/>
</b:EventTrigger>
</b:Interaction.Triggers>
<DataGrid.Columns>
<DataGridCheckBoxColumn Header="Is Paid" Binding="{Binding IsPaid, UpdateSourceTrigger=PropertyChanged}" />
<DataGridTextColumn Header="Amount" Binding="{Binding Amount, UpdateSourceTrigger=PropertyChanged}" />
<DataGridTextColumn Header="Description" Binding="{Binding Description, UpdateSourceTrigger=PropertyChanged}" />
<DataGridTextColumn Header="Invoice Number" Binding="{Binding InvoiceNumber, UpdateSourceTrigger=PropertyChanged}" />
<DataGridTextColumn Header="Invoice Receive Date" Binding="{Binding InvoiceRecvDate, UpdateSourceTrigger=PropertyChanged}" />
</DataGrid.Columns>
</chkDatagrid:CheckboxDataGrid>
Вы заметите несколько вещей здесь. Я подписываюсь на событие RowEditEnding для редактирования и фиксации столбцов и применения конвертера к новой строке.
Наконец, вот код, который обновляет присоединенную сущность:
private void OnReleaseRowEditEnding(object arg) {
if (arg != null) {
EMService.EMEntities etx = GetEMEntities();
EMService.Release release = (EMService.Release)arg;
if (release.ReleaseID == 0) {
release.EncumbranceID = SelectedPurchaseOrder.EncumbranceID;
release.CreatedOn = DateTime.Now;
release.CreatedBy = CurrentUser.Username;
release.ModifiedOn = DateTime.Now;
release.ModifiedBy = CurrentUser.Username;
etx.AddObject("Releases", release);
} else {
EMService.Release existingRelease = etx.Releases.Where(e => e.ReleaseID == release.ReleaseID).First();
existingRelease.Amount = release.Amount;
existingRelease.Description = release.Description;
existingRelease.InvoiceNumber = release.InvoiceNumber;
existingRelease.InvoiceRecvDate = release.InvoiceRecvDate;
existingRelease.IsPaid = release.IsPaid;
release.ModifiedOn = DateTime.Now;
release.ModifiedBy = CurrentUser.Username;
etx.UpdateObject(existingRelease);
}
etx.SaveChanges();
}
}
Это много, чтобы переварить, но в конечном итоге это сработало. Кто знал, что датагрид в WPF будет очень неприятным.