Hi,@ John Sparks. Welcome to Microsoft Q&A.
The following example opens another window for editing when an item in the DataGrid is selected, and then updates the DataGrid. You could try to refer to it .
MainWindow.xaml:
<StackPanel>
<DataGrid ItemsSource="{Binding Cars}" SelectedItem="{Binding SelectedCar, Mode=TwoWay}"
CanUserDeleteRows="False" SelectionMode="Single" SelectedIndex="{Binding SelectedIndex}"
AutoGenerateColumns="False" MouseDoubleClick="DataGrid_MouseDoubleClick" >
<DataGrid.Columns>
<DataGridTextColumn Header="Make" Binding="{Binding Path=Make, Mode=TwoWay}" Width="105" IsReadOnly="True" />
<DataGridTextColumn Header="Mode" Binding="{Binding Path=Model, Mode=TwoWay}" Width="75" IsReadOnly="True" />
<DataGridTextColumn Header="Year " Binding="{Binding Path=Year, StringFormat=d, Mode=TwoWay}" Width="75" IsReadOnly="True" />
</DataGrid.Columns>
</DataGrid>
</StackPanel>
MainWindow.xaml.cs:
public partial class MainWindow : Window , INotifyPropertyChanged
{
CarViewModel vm= new CarViewModel();
public MainWindow()
{
InitializeComponent();
DataContext=vm;
}
private void DataGrid_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
if (sender is DataGrid grid && grid.SelectedItems.Count == 1)
{
var selectedCar = grid.SelectedItem as Car;
if (selectedCar != null)
{
DetailWindow detailWindow = new DetailWindow(selectedCar);
detailWindow.DataContext=vm;
detailWindow.ShowDialog();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class CarViewModel : INotifyPropertyChanged
{
public ObservableCollection<Car> Cars { get; set; } = new ObservableCollection<Car>();
public CarViewModel()
{
LoadCars();
UpdateBindingGroup = new BindingGroup { Name = "Group1" };
CancelCommand = new RelayCommand(DoCancel);
SaveCommand = new RelayCommand(DoSave);
AddCommand = new RelayCommand(AddCar);
DeleteUserCommand = new RelayCommand(DeleteCar);
}
private Car _selectedCar;
public Car SelectedCar
{
get { return _selectedCar; }
set
{
_selectedCar = value;
OnPropertyChanged();
}
}
public int SelectedIndex { get; set; }
private void LoadCars()
{
Cars.Add(new Car { Make = "Toyota", Model = "Camry", Year = new DateTime(2021,7,8) });
Cars.Add(new Car { Make = "Honda", Model = "Civic", Year = new DateTime(2021, 7, 8) });
Cars.Add(new Car { Make = "Ford", Model = "Focus", Year = new DateTime (2021,7,8 ) });
}
private BindingGroup _UpdateBindingGroup;
public BindingGroup UpdateBindingGroup
{
get
{
return _UpdateBindingGroup;
}
set
{
if (_UpdateBindingGroup != value)
{
_UpdateBindingGroup = value;
OnPropertyChanged("UpdateBindingGroup");
}
}
}
public RelayCommand CancelCommand { get; set; }
public RelayCommand SaveCommand { get; set; }
public RelayCommand AddCommand { get; set; }
public RelayCommand DeleteUserCommand { get; set; }
void DoCancel(object param)
{
UpdateBindingGroup.CancelEdit();
if (SelectedIndex == -1) //This only closes if new - just to show you how CancelEdit returns old values to bindings
SelectedCar = null;
}
void DoSave(object param)
{
UpdateBindingGroup.CommitEdit();
var car = SelectedCar as Car;
if (SelectedIndex == -1)
{
Cars.Add(car);
OnPropertyChanged("Cars");
}
else
OnPropertyChanged("Cars");
SelectedCar = null;
}
void AddCar(object param)
{
SelectedCar = null;
var car = new Car();
SelectedCar = car;
}
void DeleteCar(object parameter)
{
var car = SelectedCar as Car;
if (SelectedIndex != -1)
{
Cars.Remove(car);
OnPropertyChanged("Cars");
}
else
SelectedCar = null;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class SelectedItemToItemsSource : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null) return null;
return new List<object>() { value };
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class Car : INotifyPropertyChanged
{
private string _make;
public string Make
{
get { return _make; }
set
{
if (_make != value)
{
_make = value;
OnPropertyChanged();
}
}
}
private string _model;
public string Model
{
get { return _model; }
set
{
if (_model != value)
{
_model = value;
OnPropertyChanged();
}
}
}
private DateTime _year;
public DateTime Year
{
get { return _year; }
set
{
if (_year != value)
{
_year = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
DetailWindow.xaml:
<Window.Resources>
<local:SelectedItemToItemsSource x:Key="SelectedItemToItemsSource"/>
<DataTemplate x:Key="UserGrid">
<Border Background="Chocolate" BorderBrush="Black" BorderThickness="1" CornerRadius="5" >
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text=" Make" Grid.Row="1" Grid.Column="0"/>
<TextBlock Text="Mode" Grid.Row="2" Grid.Column="0"/>
<TextBlock Text="Year" Grid.Row="3" Grid.Column="0"/>
<TextBox Text="{Binding Make, BindingGroupName=Group1, UpdateSourceTrigger=Explicit}" Grid.Column="1" Grid.Row="1"/>
<TextBox Text="{Binding Model, BindingGroupName=Group1, UpdateSourceTrigger=Explicit}" Grid.Column="1" Grid.Row="2"/>
<TextBox Text="{Binding Year, BindingGroupName=Group1, UpdateSourceTrigger=Explicit}" Grid.Column="1" Grid.Row="3"/>
<StackPanel Orientation="Horizontal" Grid.Row="10" Grid.ColumnSpan="2" HorizontalAlignment="Right" Margin="5,5,5,5">
<Button Foreground="White" Background="Green" Content="Cancel" Command="{Binding DataContext.CancelCommand, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" Margin="4,0"/>
<Button Foreground="White" Background="Green" Content="Delete" Command="{Binding DataContext.DeleteUserCommand, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" Margin="4,0"/>
<Button Foreground="White" Background="Green" Content="Save" Command="{Binding DataContext.SaveCommand, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" Margin="4,0"/>
<Button Foreground="White" Background="Green" Content="Add" Command="{Binding DataContext.AddCommand, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" Margin="4,0"/>
</StackPanel>
</Grid>
</Border>
</DataTemplate>
</Window.Resources>
<StackPanel>
<ItemsControl BindingGroup="{Binding UpdateBindingGroup, Mode=OneWay}" VerticalAlignment="Top" Margin="5,5,5,5" Grid.Column="1"
ItemTemplate="{StaticResource UserGrid}" ItemsSource="{Binding SelectedCar, Converter={StaticResource SelectedItemToItemsSource}}" />
</StackPanel>
Detail.xaml.cs:
public partial class DetailWindow : Window
{
public DetailWindow(Car car)
{
InitializeComponent();
}
}
public class RelayCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Predicate<object> _canExecute;
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
}
The result:
If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.