diff --git a/CS/ViewModel/EFCore/LocalData/IDataItemCopyOperationsSupporter.cs b/CS/ViewModel/EFCore/LocalData/IDataItemCopyOperationsSupporter.cs
new file mode 100644
index 0000000..e0cbf34
--- /dev/null
+++ b/CS/ViewModel/EFCore/LocalData/IDataItemCopyOperationsSupporter.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EFCoreIssues {
+ public interface IDataItemCopyOperationsSupporter {
+ object Clone(object item);
+ void CopyTo(object source, object target);
+ }
+}
diff --git a/CS/ViewModel/EFCore/LocalData/LocalData.csproj b/CS/ViewModel/EFCore/LocalData/LocalData.csproj
index cf7b5b4..c7f6a6b 100644
--- a/CS/ViewModel/EFCore/LocalData/LocalData.csproj
+++ b/CS/ViewModel/EFCore/LocalData/LocalData.csproj
@@ -1,4 +1,4 @@
-
+
@@ -13,7 +13,7 @@
512
{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
4
- true
+ true
true
true
@@ -166,11 +166,14 @@
MSBuild:Compile
Designer
+
+
MSBuild:Compile
Designer
-
+
+
App.xaml
Code
@@ -213,4 +216,4 @@
-
+
\ No newline at end of file
diff --git a/CS/ViewModel/EFCore/LocalData/MainViewModel.cs b/CS/ViewModel/EFCore/LocalData/MainViewModel.cs
index 0844a1f..c2e7051 100644
--- a/CS/ViewModel/EFCore/LocalData/MainViewModel.cs
+++ b/CS/ViewModel/EFCore/LocalData/MainViewModel.cs
@@ -1,18 +1,29 @@
using DevExpress.Mvvm;
+using System.Collections.ObjectModel;
using System.Linq;
namespace EFCoreIssues {
public class MainViewModel : ViewModelBase {
EFCoreIssues.Issues.IssuesContext _Context;
- System.Collections.Generic.IList _ItemsSource;
+ ObservableCollection _ItemsSource;
- public System.Collections.Generic.IList ItemsSource
+ UserCopyOperationsSupporter _CopyOperationsSupporter;
+ public UserCopyOperationsSupporter CopyOperationsSupporter {
+ get {
+ if(_CopyOperationsSupporter == null) {
+ _CopyOperationsSupporter = new UserCopyOperationsSupporter();
+ }
+ return _CopyOperationsSupporter;
+ }
+ }
+
+ public ObservableCollection ItemsSource
{
get
{
if(_ItemsSource == null && !IsInDesignMode) {
_Context = new EFCoreIssues.Issues.IssuesContext();
- _ItemsSource = _Context.Users.ToList();
+ _ItemsSource = new ObservableCollection(_Context.Users);
}
return _ItemsSource;
}
diff --git a/CS/ViewModel/EFCore/LocalData/MainWindow.xaml b/CS/ViewModel/EFCore/LocalData/MainWindow.xaml
index 560de16..ef3e943 100644
--- a/CS/ViewModel/EFCore/LocalData/MainWindow.xaml
+++ b/CS/ViewModel/EFCore/LocalData/MainWindow.xaml
@@ -1,31 +1,40 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/CS/ViewModel/EFCore/LocalData/UndoBehavior.cs b/CS/ViewModel/EFCore/LocalData/UndoBehavior.cs
new file mode 100644
index 0000000..3f56d06
--- /dev/null
+++ b/CS/ViewModel/EFCore/LocalData/UndoBehavior.cs
@@ -0,0 +1,128 @@
+using DevExpress.Mvvm;
+using DevExpress.Mvvm.UI.Interactivity;
+using DevExpress.Mvvm.Xpf;
+using DevExpress.Xpf.Grid;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Input;
+
+namespace EFCoreIssues {
+ public class UndoBehavior : Behavior {
+ public static readonly DependencyProperty CopyOperationsSupporterProperty =
+ DependencyProperty.Register(nameof(CopyOperationsSupporter), typeof(IDataItemCopyOperationsSupporter), typeof(UndoBehavior), new PropertyMetadata(null));
+
+ public IDataItemCopyOperationsSupporter CopyOperationsSupporter {
+ get { return (IDataItemCopyOperationsSupporter)GetValue(CopyOperationsSupporterProperty); }
+ set { SetValue(CopyOperationsSupporterProperty, value); }
+ }
+
+ public static readonly DependencyProperty ValidateRowCommandProperty =
+ DependencyProperty.Register(nameof(ValidateRowCommand), typeof(ICommand), typeof(UndoBehavior), new PropertyMetadata(null));
+
+ public ICommand ValidateRowCommand {
+ get { return (ICommand)GetValue(ValidateRowCommandProperty); }
+ set { SetValue(ValidateRowCommandProperty, value); }
+ }
+
+ public static readonly DependencyProperty ValidateRowDeletionCommandProperty =
+ DependencyProperty.Register(nameof(ValidateRowDeletionCommand), typeof(ICommand), typeof(UndoBehavior), new PropertyMetadata(null));
+
+ public ICommand ValidateRowDeletionCommand {
+ get { return (ICommand)GetValue(ValidateRowDeletionCommandProperty); }
+ set { SetValue(ValidateRowDeletionCommandProperty, value); }
+ }
+
+ public ICommand UndoCommand { get; private set; }
+
+ public UndoBehavior() {
+ UndoCommand = new DelegateCommand(Undo, CanUndo);
+ }
+
+ IList source;
+
+ protected override void OnAttached() {
+ base.OnAttached();
+ AssociatedObject.ValidateRow += OnRowAddedOrEdited;
+ AssociatedObject.ValidateRowDeletion += OnRowDeleted;
+ AssociatedObject.RowEditStarted += OnEditingStarted;
+ AssociatedObject.DataSourceRefresh += OnRefresh;
+ AssociatedObject.InitNewRow += OnNewRowStarted;
+ source = (IList)AssociatedObject.DataControl.ItemsSource;
+ }
+
+ private void OnRefresh(object sender, DataSourceRefreshEventArgs e) {
+ undoAction = null;
+ editingCache = null;
+ }
+
+ protected override void OnDetaching() {
+ AssociatedObject.ValidateRow -= OnRowAddedOrEdited;
+ AssociatedObject.ValidateRowDeletion -= OnRowDeleted;
+ AssociatedObject.RowEditStarted -= OnEditingStarted;
+ AssociatedObject.DataSourceRefresh -= OnRefresh;
+ AssociatedObject.InitNewRow -= OnNewRowStarted;
+ source = null;
+ base.OnDetaching();
+ }
+
+ private void OnNewRowStarted(object sender, InitNewRowEventArgs e) {
+ isNewItemRowEditing = true;
+ }
+
+ bool isNewItemRowEditing;
+
+ object editingCache;
+
+ private void OnEditingStarted(object sender, RowEditStartedEventArgs e) {
+ if(e.RowHandle != DataControlBase.NewItemRowHandle) {
+ editingCache = CopyOperationsSupporter.Clone(e.Row);
+ }
+ }
+
+ private void OnRowDeleted(object sender, GridValidateRowDeletionEventArgs e) {
+ undoAction = new Action(() => {
+ InsertItem(e.RowHandles.Single(), CopyOperationsSupporter.Clone(e.Rows.Single())); //Somehow index is changing after a new adding to source
+ });
+ }
+
+ private void OnRowAddedOrEdited(object sender, GridRowValidationEventArgs e) {
+ var item = e.Row;
+ undoAction = e.IsNewItem ? new Action(() => RemoveItem(item)) : new Action(() => ApplyEditingCache(item));
+ isNewItemRowEditing = false;
+ }
+
+ void ApplyEditingCache(object item) {
+ CopyOperationsSupporter.CopyTo(editingCache, item);
+ AssociatedObject.DataControl.RefreshRow(source.IndexOf(item)); //TODO: find a way how to get row handle by element or list index
+ ValidateRowCommand.Execute(new RowValidationArgs(editingCache, source.IndexOf(item), false, new CancellationToken(), false));
+ }
+
+ Action undoAction;
+
+ void Undo() {
+ undoAction?.Invoke();
+ undoAction = null;
+ }
+
+ bool CanUndo() {
+ return undoAction != null && !AssociatedObject.IsEditing && !isNewItemRowEditing && !AssociatedObject.IsDataSourceRefreshing;
+ }
+
+ void RemoveItem(object item) {
+ source.Remove(item);
+ ValidateRowDeletionCommand.Execute(new ValidateRowDeletionArgs(new object[] { item }, new int[] { source.IndexOf(item) }));
+ }
+
+ void InsertItem(int position, object item) {
+ source.Insert(position, item);
+ ValidateRowCommand.Execute(new RowValidationArgs(item, source.IndexOf(item), true, new CancellationToken(), false));
+ }
+
+ }
+}
diff --git a/CS/ViewModel/EFCore/LocalData/UndoManager.cs b/CS/ViewModel/EFCore/LocalData/UndoManager.cs
new file mode 100644
index 0000000..ae533cb
--- /dev/null
+++ b/CS/ViewModel/EFCore/LocalData/UndoManager.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EFCoreIssues {
+ public class UndoManager {
+
+ }
+}
diff --git a/CS/ViewModel/EFCore/LocalData/UserCopyOperationsSupporter.cs b/CS/ViewModel/EFCore/LocalData/UserCopyOperationsSupporter.cs
new file mode 100644
index 0000000..289d39c
--- /dev/null
+++ b/CS/ViewModel/EFCore/LocalData/UserCopyOperationsSupporter.cs
@@ -0,0 +1,32 @@
+using EFCoreIssues.Issues;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EFCoreIssues {
+ public class UserCopyOperationsSupporter : IDataItemCopyOperationsSupporter {
+ public object Clone(object item) {
+ var userItem = GetUser(item);
+ return new User() { FirstName = userItem.FirstName, Id = userItem.Id, Issues = userItem.Issues, LastName = userItem.LastName };
+ }
+
+ public void CopyTo(object source, object target) {
+ var userSource = GetUser(source);
+ var userTarget = GetUser(target);
+ userTarget.FirstName = userSource.FirstName;
+ userTarget.Id = userSource.Id;
+ userTarget.Issues = userSource.Issues;
+ userTarget.LastName = userSource.LastName;
+ }
+
+ User GetUser(object item) {
+ var result = item as User;
+ if(result == null) {
+ throw new InvalidOperationException();
+ }
+ return result;
+ }
+ }
+}
diff --git a/README.md b/README.md
index e40afa9..9238d77 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,4 @@
-
[](https://supportcenter.devexpress.com/ticket/details/T899930)
[](https://docs.devexpress.com/GeneralInformation/403183)