Add an expression-tree based version of RaiseAndSetIfChanged
This commit is contained in:
Родитель
f869ca4f4c
Коммит
a7a04be6a4
|
@ -1,5 +1,4 @@
|
|||
using Antireptilia;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
@ -8,7 +7,7 @@ using System.IO;
|
|||
using System.Text;
|
||||
using ReactiveXaml.Tests;
|
||||
|
||||
namespace Antireptilia.Tests
|
||||
namespace ReactiveXaml.Tests
|
||||
{
|
||||
[TestClass()]
|
||||
public class ReactiveCollectionTest : IEnableLogger
|
||||
|
@ -165,4 +164,4 @@ namespace Antireptilia.Tests
|
|||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Antireptilia.Tests;
|
||||
|
||||
namespace ReactiveXaml.Tests
|
||||
{
|
||||
|
@ -97,10 +96,25 @@ namespace ReactiveXaml.Tests
|
|||
this.Log().Debug(json);
|
||||
|
||||
// Should look something like:
|
||||
// {"IsNotNullString":"Foo","IsOnlyOneWord":"Baz"}
|
||||
Assert.IsTrue(json.Count(x => x == ',') == 1);
|
||||
Assert.IsTrue(json.Count(x => x == ':') == 2);
|
||||
Assert.IsTrue(json.Count(x => x == '"') == 8);
|
||||
// {"IsNotNullString":"Foo","IsOnlyOneWord":"Baz", "UserExprRaiseSet":null}
|
||||
Assert.IsTrue(json.Count(x => x == ',') == 2);
|
||||
Assert.IsTrue(json.Count(x => x == ':') == 3);
|
||||
Assert.IsTrue(json.Count(x => x == '"') == 10);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void RaiseAndSetUsingExpression()
|
||||
{
|
||||
var fixture = new ValidatedTestFixture() { IsNotNullString = "Foo", IsOnlyOneWord = "Baz" };
|
||||
var output = new List<string>();
|
||||
fixture.Subscribe(x => output.Add(x.PropertyName));
|
||||
|
||||
fixture.UsesExprRaiseSet = "Foo";
|
||||
fixture.UsesExprRaiseSet = "Foo"; // This one shouldn't raise a change notification
|
||||
|
||||
Assert.AreEqual("Foo", fixture.UsesExprRaiseSet);
|
||||
Assert.AreEqual(1, output.Count);
|
||||
Assert.AreEqual("UsesExprRaiseSet", output[0]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,6 +23,12 @@ namespace ReactiveXaml.Tests
|
|||
get { return _IsOnlyOneWord; }
|
||||
set { RaiseAndSetIfChanged(_IsOnlyOneWord, value, x => _IsOnlyOneWord = x, "IsOnlyOneWord"); }
|
||||
}
|
||||
|
||||
string _UsesExprRaiseSet;
|
||||
public string UsesExprRaiseSet {
|
||||
get { return _UsesExprRaiseSet; }
|
||||
set { _UsesExprRaiseSet = this.RaiseAndSetIfChanged(x => x.UsesExprRaiseSet, value); }
|
||||
}
|
||||
}
|
||||
|
||||
[TestClass()]
|
||||
|
|
|
@ -7,6 +7,7 @@ using System.Diagnostics;
|
|||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace ReactiveXaml
|
||||
{
|
||||
|
@ -36,6 +37,7 @@ namespace ReactiveXaml
|
|||
#endif
|
||||
}
|
||||
|
||||
[Obsolete("Use the RaiseAndSetIfChanged<TObj,TRet> extension method instead")]
|
||||
protected T RaiseAndSetIfChanged<T>(T oldValue, T newValue, Action<T> setter, string propertyName)
|
||||
{
|
||||
// if oldValue == newValue...
|
||||
|
@ -56,7 +58,7 @@ namespace ReactiveXaml
|
|||
.Subscribe(_ => RaisePropertyChanged(propertyName));
|
||||
}
|
||||
|
||||
protected void RaisePropertyChanged(string propertyName)
|
||||
protected internal void RaisePropertyChanged(string propertyName)
|
||||
{
|
||||
this.VerifyPropertyName(propertyName);
|
||||
|
||||
|
@ -137,4 +139,37 @@ namespace ReactiveXaml
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class ReactiveObjectExpressionMixin
|
||||
{
|
||||
public static TRet RaiseAndSetIfChanged<TObj, TRet>(this TObj This, Expression<Func<TObj, TRet>> Property, TRet Value)
|
||||
where TObj : ReactiveObject
|
||||
{
|
||||
string prop_name = null;
|
||||
FieldInfo field;
|
||||
try {
|
||||
var prop_expr = ((LambdaExpression)Property).Body as MemberExpression;
|
||||
prop_name = prop_expr.Member.Name;
|
||||
} catch (NullReferenceException) {
|
||||
throw new ArgumentException("Property expression must be of the form 'x => x.SomeProperty'");
|
||||
}
|
||||
|
||||
field = (typeof(TObj)).GetField("_" + prop_name, BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
if (field == null) {
|
||||
throw new ArgumentException("You must declare a backing field for this property named _" + prop_name);
|
||||
}
|
||||
|
||||
var field_val = field.GetValue(This);
|
||||
|
||||
if (EqualityComparer<TRet>.Default.Equals((TRet)field_val, (TRet)Value))
|
||||
return Value;
|
||||
|
||||
field.SetValue(This, Value);
|
||||
This.RaisePropertyChanged(prop_name);
|
||||
|
||||
return Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// vim: tw=120 ts=4 sw=4 et enc=utf8 :
|
Загрузка…
Ссылка в новой задаче