Skip to content

Commit 1b3c081

Browse files
committed
fix
1 parent c6e2274 commit 1b3c081

File tree

6 files changed

+113
-103
lines changed

6 files changed

+113
-103
lines changed

Eocron.Algorithms.Tests/EditSessionTests.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,6 @@ public void Setup()
160160
public class TestDocument
161161
{
162162
public string Id { get; set; }
163-
164163
public TestDocument Inner { get; set; }
165164

166165
public List<TestDocument> Chidlren { get; set; }
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace Eocron.Algorithms.UI.Editing;
2+
3+
public class EditSessionChangeContext
4+
{
5+
public object OldValue { get; set; }
6+
}
Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
using System;
22
using System.Linq.Expressions;
33

4-
namespace Eocron.Algorithms.UI.Editing
4+
namespace Eocron.Algorithms.UI.Editing;
5+
6+
public static class EditSessionExtensions
57
{
6-
public static class EditSessionExtensions
8+
public static void SetProperty<TDocument, TProperty>(this IEditSession<TDocument> editSession,
9+
Expression<Func<TDocument, TProperty>> propertySelector, TProperty newValue)
710
{
8-
public static void SetProperty<TDocument, TProperty>(this IEditSession<TDocument> editSession,
9-
Expression<Func<TDocument, TProperty>> propertySelector, TProperty newValue)
10-
{
11-
editSession.Apply(new PropertyEditSessionChange<TDocument, TProperty>(
12-
propertySelector,
13-
newValue));
14-
}
11+
editSession.Apply(new PropertyEditSessionChange<TDocument, TProperty>(
12+
propertySelector,
13+
(obj, property, ctx) =>
14+
{
15+
ctx.OldValue = property.GetValue(obj);
16+
property.SetValue(obj, newValue);
17+
},
18+
(obj, property, ctx) =>
19+
{
20+
property.SetValue(obj, ctx.OldValue);
21+
}));
1522
}
1623
}
Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,30 @@
11
using System.ComponentModel.DataAnnotations;
22

3-
namespace Eocron.Algorithms.UI.Editing
3+
namespace Eocron.Algorithms.UI.Editing;
4+
5+
public interface IEditSession<out TDocument>
46
{
5-
public interface IEditSession<out TDocument>
6-
{
7-
TDocument Source { get; }
7+
TDocument Source { get; }
88

9-
TDocument Draft { get; }
9+
TDocument Draft { get; }
1010

11-
ValidationResult[] Validation { get; }
11+
ValidationResult[] Validation { get; }
1212

13-
bool IsEditing { get; }
13+
bool IsEditing { get; }
1414

15-
bool CanRedo { get; }
15+
bool CanRedo { get; }
1616

17-
bool CanUndo { get; }
17+
bool CanUndo { get; }
1818

19-
void BeginEdit();
19+
void BeginEdit();
2020

21-
void Apply(IEditSessionChange<TDocument> change);
21+
void Apply(IEditSessionChange<TDocument> change);
2222

23-
bool TryCommit();
23+
bool TryCommit();
2424

25-
void Rollback();
25+
void Rollback();
2626

27-
void Undo();
27+
void Undo();
2828

29-
void Redo();
30-
}
29+
void Redo();
3130
}
Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
namespace Eocron.Algorithms.UI.Editing
1+
namespace Eocron.Algorithms.UI.Editing;
2+
3+
public interface IEditSessionChange<in TDocument>
24
{
3-
public interface IEditSessionChange<in TDocument>
4-
{
5-
void Redo(TDocument document);
6-
void Undo(TDocument document);
7-
}
5+
void Redo(TDocument document);
6+
void Undo(TDocument document);
87
}

Eocron.Algorithms/UI/Editing/PropertyEditSessionChange.cs

Lines changed: 71 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -3,98 +3,98 @@
33
using System.Linq.Expressions;
44
using System.Reflection;
55

6-
namespace Eocron.Algorithms.UI.Editing
6+
namespace Eocron.Algorithms.UI.Editing;
7+
8+
public class PropertyEditSessionChange<TDocument, TProperty> : IEditSessionChange<TDocument>
79
{
8-
public class PropertyEditSessionChange<TDocument, TProperty> : IEditSessionChange<TDocument>
10+
private readonly Expression<Func<TDocument, TProperty>> _propertySelector;
11+
private readonly Action<object, PropertyInfo, EditSessionChangeContext> _onRedo;
12+
private readonly Action<object, PropertyInfo, EditSessionChangeContext> _onUndo;
13+
private readonly List<(object parent, PropertyInfo property)> _createdObjects = new();
14+
private EditSessionChangeContext _context;
15+
16+
public PropertyEditSessionChange(
17+
Expression<Func<TDocument, TProperty>> propertySelector,
18+
Action<object, PropertyInfo, EditSessionChangeContext> onRedo,
19+
Action<object, PropertyInfo, EditSessionChangeContext> onUndo)
920
{
10-
private readonly Expression<Func<TDocument, TProperty>> _propertySelector;
11-
private readonly TProperty _newValue;
12-
private TProperty _oldValue;
13-
private readonly List<(object parent, PropertyInfo property)> _createdObjects = new();
14-
15-
public PropertyEditSessionChange(
16-
Expression<Func<TDocument, TProperty>> propertySelector,
17-
TProperty newValue)
18-
{
19-
_propertySelector = propertySelector ?? throw new ArgumentNullException(nameof(propertySelector));
20-
_newValue = newValue;
21-
}
22-
23-
public void Redo(TDocument document)
24-
{
25-
if (document == null) throw new ArgumentNullException(nameof(document));
21+
_propertySelector = propertySelector ?? throw new ArgumentNullException(nameof(propertySelector));
22+
_onRedo = onRedo;
23+
_onUndo = onUndo;
24+
}
2625

27-
var properties = GetPropertyChain(_propertySelector);
26+
public void Redo(TDocument document)
27+
{
28+
if (document == null) throw new ArgumentNullException(nameof(document));
2829

29-
object current = document;
30+
var properties = GetPropertyChain(_propertySelector);
3031

31-
for (var i = 0; i < properties.Count - 1; i++)
32-
{
33-
var prop = properties[i];
34-
var value = prop.GetValue(current);
32+
object current = document;
3533

36-
if (value == null)
37-
{
38-
value = Activator.CreateInstance(prop.PropertyType)
39-
?? throw new InvalidOperationException(
40-
$"Cannot create instance of {prop.PropertyType.FullName}");
34+
for (var i = 0; i < properties.Count - 1; i++)
35+
{
36+
var prop = properties[i];
37+
var value = prop.GetValue(current);
4138

42-
prop.SetValue(current, value);
43-
_createdObjects.Add((current, prop));
44-
}
39+
if (value == null)
40+
{
41+
value = Activator.CreateInstance(prop.PropertyType)
42+
?? throw new InvalidOperationException(
43+
$"Cannot create instance of {prop.PropertyType.FullName}");
4544

46-
current = value;
45+
prop.SetValue(current, value);
46+
_createdObjects.Add((current, prop));
4747
}
4848

49-
var targetProperty = properties[^1];
50-
_oldValue = (TProperty)targetProperty.GetValue(current);
51-
52-
targetProperty.SetValue(current, _newValue);
49+
current = value;
5350
}
5451

55-
public void Undo(TDocument document)
56-
{
57-
var properties = GetPropertyChain(_propertySelector);
52+
_context = new EditSessionChangeContext();
53+
_onRedo(current, properties[^1], _context);
54+
}
5855

59-
object current = document;
56+
public void Undo(TDocument document)
57+
{
58+
var properties = GetPropertyChain(_propertySelector);
6059

61-
for (int i = 0; i < properties.Count - 1; i++)
62-
{
63-
current = properties[i].GetValue(current);
64-
if (current == null)
65-
return;
66-
}
60+
object current = document;
6761

68-
properties[^1].SetValue(current, _oldValue);
69-
70-
for (var i = _createdObjects.Count - 1; i >= 0; i--)
71-
{
72-
var (parent, property) = _createdObjects[i];
73-
property.SetValue(parent, null);
74-
}
75-
_createdObjects.Clear();
62+
for (int i = 0; i < properties.Count - 1; i++)
63+
{
64+
current = properties[i].GetValue(current);
65+
if (current == null)
66+
return;
7667
}
7768

78-
private static List<PropertyInfo> GetPropertyChain(
79-
Expression<Func<TDocument, TProperty>> expression)
69+
_onUndo(current, properties[^1], _context);
70+
71+
for (var i = _createdObjects.Count - 1; i >= 0; i--)
8072
{
81-
var properties = new List<PropertyInfo>();
82-
Expression current = expression.Body;
83-
84-
while (current is MemberExpression member)
85-
{
86-
if (member.Member is PropertyInfo property)
87-
properties.Insert(0, property);
88-
else
89-
throw new InvalidOperationException("Expression contains non-property member.");
73+
var (parent, property) = _createdObjects[i];
74+
property.SetValue(parent, null);
75+
}
76+
_createdObjects.Clear();
77+
}
9078

91-
current = member.Expression;
92-
}
79+
private static List<PropertyInfo> GetPropertyChain(
80+
Expression<Func<TDocument, TProperty>> expression)
81+
{
82+
var properties = new List<PropertyInfo>();
83+
Expression current = expression.Body;
9384

94-
if (current.NodeType != ExpressionType.Parameter)
95-
throw new InvalidOperationException("Invalid property selector expression.");
85+
while (current is MemberExpression member)
86+
{
87+
if (member.Member is PropertyInfo property)
88+
properties.Insert(0, property);
89+
else
90+
throw new InvalidOperationException("Expression contains non-property member.");
9691

97-
return properties;
92+
current = member.Expression;
9893
}
94+
95+
if (current.NodeType != ExpressionType.Parameter)
96+
throw new InvalidOperationException("Invalid property selector expression.");
97+
98+
return properties;
9999
}
100100
}

0 commit comments

Comments
 (0)