Add an expression-tree based version of RaiseAndSetIfChanged

This commit is contained in:
Paul Betts 2010-09-18 22:10:41 -07:00
Родитель f869ca4f4c
Коммит a7a04be6a4
4 изменённых файлов: 64 добавлений и 10 удалений

Просмотреть файл

@ -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 :