Repository: kswoll/ReactiveUI.Fody
Branch: rxui7beta
Commit: 6c002e709f46
Files: 58
Total size: 119.0 KB
Directory structure:
gitextract_4be4dugx/
├── .gitignore
├── .nuget/
│ └── packages.config
├── LICENSE
├── Nuget/
│ └── ReactiveUIFody.nuspec
├── ReactiveUI.Fody/
│ ├── CecilExtensions.cs
│ ├── ModuleWeaver.cs
│ ├── ObservableAsPropertyWeaver.cs
│ ├── Properties/
│ │ └── AssemblyInfo.cs
│ ├── ReactiveDependencyPropertyWeaver.cs
│ ├── ReactiveUI.Fody.csproj
│ ├── ReactiveUIPropertyWeaver.cs
│ └── packages.config
├── ReactiveUI.Fody.Helpers/
│ ├── LogPropertyOnErrorException.cs
│ ├── LogPropertyOnErrorObservable.cs
│ ├── ObservableAsPropertyAttribute.cs
│ ├── ObservableAsPropertyExtensions.cs
│ ├── ReactiveAttribute.cs
│ ├── ReactiveDependencyAttribute.cs
│ ├── ReactivePropertyExtensions.cs
│ ├── ReactiveUI.Fody.Helpers.projitems
│ ├── ReactiveUI.Fody.Helpers.shproj
│ └── Settings/
│ └── GlobalSettings.cs
├── ReactiveUI.Fody.Helpers.Android/
│ ├── Properties/
│ │ └── AssemblyInfo.cs
│ ├── ReactiveUI.Fody.Helpers.Android.csproj
│ ├── Resources/
│ │ ├── AboutResources.txt
│ │ ├── Resource.Designer.cs
│ │ └── Values/
│ │ └── Strings.xml
│ └── packages.config
├── ReactiveUI.Fody.Helpers.Ios/
│ ├── Properties/
│ │ └── AssemblyInfo.cs
│ ├── ReactiveUI.Fody.Helpers.Ios.csproj
│ └── packages.config
├── ReactiveUI.Fody.Helpers.Net45/
│ ├── Properties/
│ │ └── AssemblyInfo.cs
│ ├── ReactiveUI.Fody.Helpers.Net45.csproj
│ └── packages.config
├── ReactiveUI.Fody.Helpers.Pcl/
│ ├── Properties/
│ │ └── AssemblyInfo.cs
│ ├── ReactiveUI.Fody.Helpers.Pcl.csproj
│ └── packages.config
├── ReactiveUI.Fody.Tests/
│ ├── FodyWeavers.xml
│ ├── Issues/
│ │ ├── Issue10Tests.cs
│ │ ├── Issue11Tests.cs
│ │ ├── Issue13Tests.cs
│ │ ├── Issue31Tests.cs
│ │ ├── Issue41Tests.cs
│ │ └── Issue47Tests.cs
│ ├── ObservableAsPropertyTests.cs
│ ├── Properties/
│ │ └── AssemblyInfo.cs
│ ├── ReactiveDependencyTests.cs
│ ├── ReactiveUI.Fody.Tests.csproj
│ └── packages.config
├── ReactiveUIFody.sln
├── ReactiveUIFody.sln.DotSettings
├── ReactiveUIFodyAll.sln
├── Readme.md
├── Weavers/
│ └── bin/
│ └── _._
├── artifacts/
│ ├── MonoAndroid/
│ │ ├── ReactiveUI.Fody.Helpers.dll.mdb
│ │ └── ReactiveUI.Fody.Helpers.pdb
│ └── Xamarin.iOS10/
│ └── ReactiveUI.Fody.Helpers.pdb
└── makepackage.bat
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
packages/
*.nupkg
*.suo
*.userprefs
*.user
ReactiveUI.Fody/obj/
ReactiveUI.Fody/bin/
ReactiveUI.Fody.Helpers.Net45/obj/
ReactiveUI.Fody.Helpers.Net45/bin/
ReactiveUI.Fody.Helpers.Ios/bin/
ReactiveUI.Fody.Helpers.Ios/obj/
ReactiveUI.Fody.Helpers.Android/bin/
ReactiveUI.Fody.Helpers.Android/obj/
Nuget/ReactiveUI.Fody.1.0.26/
ReactiveUI.Fody.1.0.26/
ReactiveUI.Fody.Helpers.Pcl/obj/
ReactiveUI.Fody.Helpers.Pcl/bin/
ReactiveUI.Fody.Tests/bin/
ReactiveUI.Fody.Tests/obj/
Weavers/bin/Weavers.dll
Weavers/bin/Weavers.pdb
_ReSharper.Caches
================================================
FILE: .nuget/packages.config
================================================
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2014 Kirk Woll
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: Nuget/ReactiveUIFody.nuspec
================================================
ReactiveUI.Fody
2.0.0
kirk
kirk
https://github.com/kswoll/ReactiveUI.Fody
http://www.opensource.org/licenses/mit-license.php
Fix some other bugs around properties in generic types.
false
Fody extension to generate RaisePropertyChange notifications for properties and ObservableAsPropertyHelper properties.
Copyright 2015
reactiveui fody
================================================
FILE: ReactiveUI.Fody/CecilExtensions.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace ReactiveUI.Fody
{
public static class CecilExtensions
{
public static void Emit(this MethodBody body, Action il)
{
il(body.GetILProcessor());
}
public static GenericInstanceMethod MakeGenericMethod(this MethodReference method, params TypeReference[] genericArguments)
{
var result = new GenericInstanceMethod(method);
foreach (var argument in genericArguments)
result.GenericArguments.Add(argument);
return result;
}
public static bool IsAssignableFrom(this TypeReference baseType, TypeReference type, Action logger = null)
{
return baseType.Resolve().IsAssignableFrom(type.Resolve(), logger);
}
public static bool IsAssignableFrom(this TypeDefinition baseType, TypeDefinition type, Action logger = null)
{
logger = logger ?? (x => {});
Queue queue = new Queue();
queue.Enqueue(type);
while (queue.Any())
{
var current = queue.Dequeue();
logger(current.FullName);
if (baseType.FullName == current.FullName)
return true;
if (current.BaseType != null)
queue.Enqueue(current.BaseType.Resolve());
foreach (var @interface in current.Interfaces)
{
queue.Enqueue(@interface.InterfaceType.Resolve());
}
}
return false;
}
public static bool IsDefined(this IMemberDefinition member, TypeReference attributeType)
{
return member.HasCustomAttributes && member.CustomAttributes.Any(x => x.AttributeType.FullName == attributeType.FullName);
}
public static MethodReference Bind(this MethodReference method, GenericInstanceType genericType)
{
var reference = new MethodReference(method.Name, method.ReturnType, genericType);
reference.HasThis = method.HasThis;
reference.ExplicitThis = method.ExplicitThis;
reference.CallingConvention = method.CallingConvention;
foreach (var parameter in method.Parameters)
reference.Parameters.Add(new ParameterDefinition(parameter.ParameterType));
return reference;
}
/*
public static MethodReference BindDefinition(this MethodReference method, TypeReference genericTypeDefinition)
{
if (!genericTypeDefinition.HasGenericParameters)
return method;
var genericDeclaration = new GenericInstanceType(genericTypeDefinition);
foreach (var parameter in genericTypeDefinition.GenericParameters)
{
genericDeclaration.GenericArguments.Add(parameter);
}
var reference = new MethodReference(method.Name, method.ReturnType, genericDeclaration);
reference.HasThis = method.HasThis;
reference.ExplicitThis = method.ExplicitThis;
reference.CallingConvention = method.CallingConvention;
foreach (var parameter in method.Parameters)
reference.Parameters.Add(new ParameterDefinition(parameter.ParameterType));
return reference;
}
*/
public static FieldReference BindDefinition(this FieldReference field, TypeReference genericTypeDefinition)
{
if (!genericTypeDefinition.HasGenericParameters)
return field;
var genericDeclaration = new GenericInstanceType(genericTypeDefinition);
foreach (var parameter in genericTypeDefinition.GenericParameters)
{
genericDeclaration.GenericArguments.Add(parameter);
}
var reference = new FieldReference(field.Name, field.FieldType, genericDeclaration);
return reference;
}
public static AssemblyNameReference FindAssembly(this ModuleDefinition currentModule, string assemblyName)
{
return currentModule.AssemblyReferences.SingleOrDefault(x => x.Name == assemblyName);
}
public static TypeReference FindType(this ModuleDefinition currentModule, string @namespace, string typeName, IMetadataScope scope = null, params string[] typeParameters)
{
var result = new TypeReference(@namespace, typeName, currentModule, scope);
foreach (var typeParameter in typeParameters)
{
result.GenericParameters.Add(new GenericParameter(typeParameter, result));
}
return result;
}
public static bool CompareTo(this TypeReference type, TypeReference compareTo)
{
return type.FullName == compareTo.FullName;
}
public static IEnumerable GetMethodDependencies(this MethodDefinition method)
{
if (!method.IsGetter) return Enumerable.Empty();
return method.Body.Instructions.Where(i =>
{
var operand = i.Operand as MethodDefinition;
return i.OpCode == OpCodes.Call && (operand?.IsGetter ?? false);
})
.SelectMany(instruction =>
{
var methodDefinition = (MethodDefinition) instruction.Operand;
return methodDefinition.GetMethodDependencies().Concat(new[] { methodDefinition });
});
}
public static bool TryGetMethodDependencies(this MethodDefinition method, out MethodDefinition[] getMethods)
{
getMethods = method.GetMethodDependencies()
.Distinct()
.ToArray();
return getMethods.Any();
}
/*
public static IEnumerable GetAllTypes(this ModuleDefinition module)
{
var stack = new Stack();
foreach (var type in module.Types)
{
stack.Push(type);
}
while (stack.Any())
{
var current = stack.Pop();
yield return current;
foreach (var nestedType in current.NestedTypes)
{
stack.Push(nestedType);
}
}
}
*/
}
}
================================================
FILE: ReactiveUI.Fody/ModuleWeaver.cs
================================================
using System;
using Mono.Cecil;
namespace ReactiveUI.Fody
{
public class ModuleWeaver
{
public ModuleDefinition ModuleDefinition { get; set; }
// Will log an MessageImportance.High message to MSBuild.
public Action LogInfo { get; set; }
// Will log an error message to MSBuild. OPTIONAL
public Action LogError { get; set; }
public void Execute()
{
var propertyWeaver = new ReactiveUIPropertyWeaver
{
ModuleDefinition = ModuleDefinition,
LogInfo = LogInfo,
LogError = LogError
};
propertyWeaver.Execute();
var observableAsPropertyWeaver = new ObservableAsPropertyWeaver
{
ModuleDefinition = ModuleDefinition,
LogInfo = LogInfo
};
observableAsPropertyWeaver.Execute();
var reactiveDependencyWeaver = new ReactiveDependencyPropertyWeaver
{
ModuleDefinition = ModuleDefinition,
LogInfo = LogInfo,
LogError = LogError
};
reactiveDependencyWeaver.Execute();
}
}
}
================================================
FILE: ReactiveUI.Fody/ObservableAsPropertyWeaver.cs
================================================
using System;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Rocks;
namespace ReactiveUI.Fody
{
public class ObservableAsPropertyWeaver
{
public ModuleDefinition ModuleDefinition { get; set; }
// Will log an MessageImportance.High message to MSBuild. OPTIONAL
public Action LogInfo { get; set; }
public void Execute()
{
var reactiveUI = ModuleDefinition.AssemblyReferences.Where(x => x.Name == "ReactiveUI").OrderByDescending(x => x.Version).FirstOrDefault();
if (reactiveUI == null)
{
LogInfo("Could not find assembly: ReactiveUI (" + string.Join(", ", ModuleDefinition.AssemblyReferences.Select(x => x.Name)) + ")");
return;
}
LogInfo($"{reactiveUI.Name} {reactiveUI.Version}");
var helpers = ModuleDefinition.AssemblyReferences.Where(x => x.Name == "ReactiveUI.Fody.Helpers").OrderByDescending(x => x.Version).FirstOrDefault();
if (helpers == null)
{
LogInfo("Could not find assembly: ReactiveUI.Fody.Helpers (" + string.Join(", ", ModuleDefinition.AssemblyReferences.Select(x => x.Name)) + ")");
return;
}
LogInfo($"{helpers.Name} {helpers.Version}");
var reactiveObject = ModuleDefinition.FindType("ReactiveUI", "ReactiveObject", reactiveUI);
// The types we will scan are subclasses of ReactiveObject
var targetTypes = ModuleDefinition.GetAllTypes().Where(x => x.BaseType != null && reactiveObject.IsAssignableFrom(x.BaseType));
var observableAsPropertyHelper = ModuleDefinition.FindType("ReactiveUI", "ObservableAsPropertyHelper`1", reactiveUI, "T");
var observableAsPropertyAttribute = ModuleDefinition.FindType("ReactiveUI.Fody.Helpers", "ObservableAsPropertyAttribute", helpers);
var observableAsPropertyHelperGetValue = ModuleDefinition.ImportReference(observableAsPropertyHelper.Resolve().Properties.Single(x => x.Name == "Value").GetMethod);
var exceptionType = ModuleDefinition.ImportReference(typeof(Exception));
var exceptionConstructor = ModuleDefinition.ImportReference(exceptionType.Resolve().GetConstructors().Single(x => x.Parameters.Count == 1));
foreach (var targetType in targetTypes)
{
foreach (var property in targetType.Properties.Where(x => x.IsDefined(observableAsPropertyAttribute) || (x.GetMethod?.IsDefined(observableAsPropertyAttribute) ?? false)).ToArray())
{
var genericObservableAsPropertyHelper = observableAsPropertyHelper.MakeGenericInstanceType(property.PropertyType);
var genericObservableAsPropertyHelperGetValue = observableAsPropertyHelperGetValue.Bind(genericObservableAsPropertyHelper);
ModuleDefinition.ImportReference(genericObservableAsPropertyHelperGetValue);
// Declare a field to store the property value
var field = new FieldDefinition("$" + property.Name, FieldAttributes.Private, genericObservableAsPropertyHelper);
targetType.Fields.Add(field);
// It's an auto-property, so remove the generated field
if (property.SetMethod != null && property.SetMethod.HasBody)
{
// Remove old field (the generated backing field for the auto property)
var oldField = (FieldReference)property.GetMethod.Body.Instructions.Where(x => x.Operand is FieldReference).Single().Operand;
var oldFieldDefinition = oldField.Resolve();
targetType.Fields.Remove(oldFieldDefinition);
// Re-implement setter to throw an exception
property.SetMethod.Body = new MethodBody(property.SetMethod);
property.SetMethod.Body.Emit(il =>
{
il.Emit(OpCodes.Ldstr, "Never call the setter of an ObservabeAsPropertyHelper property.");
il.Emit(OpCodes.Newobj, exceptionConstructor);
il.Emit(OpCodes.Throw);
il.Emit(OpCodes.Ret);
});
}
property.GetMethod.Body = new MethodBody(property.GetMethod);
property.GetMethod.Body.Emit(il =>
{
var isValid = il.Create(OpCodes.Nop);
il.Emit(OpCodes.Ldarg_0); // this
il.Emit(OpCodes.Ldfld, field.BindDefinition(targetType)); // pop -> this.$PropertyName
il.Emit(OpCodes.Dup); // Put an extra copy of this.$PropertyName onto the stack
il.Emit(OpCodes.Brtrue, isValid); // If the helper is null, return the default value for the property
il.Emit(OpCodes.Pop); // Drop this.$PropertyName
EmitDefaultValue(property.GetMethod.Body, il, property.PropertyType); // Put the default value onto the stack
il.Emit(OpCodes.Ret); // Return that default value
il.Append(isValid); // Add a marker for if the helper is not null
il.Emit(OpCodes.Callvirt, genericObservableAsPropertyHelperGetValue); // pop -> this.$PropertyName.Value
il.Emit(OpCodes.Ret); // Return the value that is on the stack
});
}
}
}
public void EmitDefaultValue(MethodBody methodBody, ILProcessor il, TypeReference type)
{
if (type.CompareTo(ModuleDefinition.TypeSystem.Boolean) || type.CompareTo(ModuleDefinition.TypeSystem.Byte) ||
type.CompareTo(ModuleDefinition.TypeSystem.Int16) || type.CompareTo(ModuleDefinition.TypeSystem.Int32))
{
il.Emit(OpCodes.Ldc_I4_0);
}
else if (type.CompareTo(ModuleDefinition.TypeSystem.Single))
{
il.Emit(OpCodes.Ldc_R4, (float)0);
}
else if (type.CompareTo(ModuleDefinition.TypeSystem.Int64))
{
il.Emit(OpCodes.Ldc_I8, (long)0);
}
else if (type.CompareTo(ModuleDefinition.TypeSystem.Double))
{
il.Emit(OpCodes.Ldc_R8, (double)0);
}
else if (type.IsGenericParameter || type.IsValueType)
{
methodBody.InitLocals = true;
var local = new VariableDefinition(type);
il.Body.Variables.Add(local);
il.Emit(OpCodes.Ldloca_S, local);
il.Emit(OpCodes.Initobj, type);
il.Emit(OpCodes.Ldloc, local);
}
else
{
il.Emit(OpCodes.Ldnull);
}
}
}
}
================================================
FILE: ReactiveUI.Fody/Properties/AssemblyInfo.cs
================================================
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ReactiveUI.Fody")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ReactiveUI.Fody")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("0171c060-b220-4e4d-af25-2e2fc92e9267")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
================================================
FILE: ReactiveUI.Fody/ReactiveDependencyPropertyWeaver.cs
================================================
using System;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Rocks;
namespace ReactiveUI.Fody
{
public class ReactiveDependencyPropertyWeaver
{
public ModuleDefinition ModuleDefinition { get; set; }
// Will log an MessageImportance.High message to MSBuild. OPTIONAL
public Action LogInfo { get; set; }
// Will log an error message to MSBuild. OPTIONAL
public Action LogError { get; set; }
public void Execute()
{
var reactiveUI = ModuleDefinition.AssemblyReferences.Where(x => x.Name == "ReactiveUI").OrderByDescending(x => x.Version).FirstOrDefault();
if (reactiveUI == null)
{
LogInfo("Could not find assembly: ReactiveUI (" + string.Join(", ", ModuleDefinition.AssemblyReferences.Select(x => x.Name)) + ")");
return;
}
LogInfo($"{reactiveUI.Name} {reactiveUI.Version}");
var helpers = ModuleDefinition.AssemblyReferences.Where(x => x.Name == "ReactiveUI.Fody.Helpers").OrderByDescending(x => x.Version).FirstOrDefault();
if (helpers == null)
{
LogInfo("Could not find assembly: ReactiveUI.Fody.Helpers (" + string.Join(", ", ModuleDefinition.AssemblyReferences.Select(x => x.Name)) + ")");
return;
}
LogInfo($"{helpers.Name} {helpers.Version}");
var reactiveObject = new TypeReference("ReactiveUI", "IReactiveObject", ModuleDefinition, reactiveUI);
var targetTypes = ModuleDefinition.GetAllTypes().Where(x => x.BaseType != null && reactiveObject.IsAssignableFrom(x.BaseType)).ToArray();
var reactiveObjectExtensions = new TypeReference("ReactiveUI", "IReactiveObjectExtensions", ModuleDefinition, reactiveUI).Resolve();
if (reactiveObjectExtensions == null) throw new Exception("reactiveObjectExtensions is null");
var raisePropertyChangedMethod = ModuleDefinition.ImportReference(reactiveObjectExtensions.Methods.Single(x => x.Name == "RaisePropertyChanged"));
if (raisePropertyChangedMethod == null) throw new Exception("raisePropertyChangedMethod is null");
var reactiveDependencyAttribute = ModuleDefinition.FindType("ReactiveUI.Fody.Helpers", "ReactiveDependencyAttribute", helpers);
if (reactiveDependencyAttribute == null) throw new Exception("reactiveDecoratorAttribute is null");
foreach (var targetType in targetTypes.Where(x => x.Properties.Any(y => y.IsDefined(reactiveDependencyAttribute))).ToArray())
{
foreach (var facadeProperty in targetType.Properties.Where(x => x.IsDefined(reactiveDependencyAttribute)).ToArray())
{
// If the property already has a body then do not weave to prevent loss of instructions
if (!facadeProperty.GetMethod.Body.Instructions.Any(x => x.Operand is FieldReference) || facadeProperty.GetMethod.Body.HasVariables)
{
LogError($"Property {facadeProperty.Name} is not an auto property and therefore not suitable for ReactiveDependency weaving");
continue;
}
var attribute = facadeProperty.CustomAttributes.First(x => x.AttributeType.FullName == reactiveDependencyAttribute.FullName);
var targetNamedArgument = attribute.ConstructorArguments.FirstOrDefault();
var targetValue = targetNamedArgument.Value?.ToString();
if (string.IsNullOrEmpty(targetValue))
{
LogError("No target property defined on the object");
continue;
}
if (targetType.Properties.All(x => x.Name != targetValue) && targetType.Fields.All(x => x.Name != targetValue))
{
LogError($"dependency object property/field name '{targetValue}' not found on target type {targetType.Name}");
continue;
}
var objPropertyTarget = targetType.Properties.FirstOrDefault(x => x.Name == targetValue);
var objFieldTarget = targetType.Fields.FirstOrDefault(x => x.Name == targetValue);
var objDependencyTargetType = objPropertyTarget != null
? objPropertyTarget.PropertyType.Resolve()
: objFieldTarget?.FieldType.Resolve();
if(objDependencyTargetType == null)
{
LogError("Couldn't result the dependency type");
continue;
}
// Look for the target property on the member obj
var destinationPropertyNamedArgument = attribute.Properties.FirstOrDefault(x => x.Name == "TargetProperty");
var destinationPropertyName = destinationPropertyNamedArgument.Argument.Value?.ToString();
// If no target property was specified use this property's name as the target on the decorated object (ala a decorated property)
if (string.IsNullOrEmpty(destinationPropertyName)) destinationPropertyName = facadeProperty.Name;
if (objDependencyTargetType.Properties.All(x => x.Name != destinationPropertyName))
{
LogError($"Target property {destinationPropertyName} on dependency of type {objDependencyTargetType.DeclaringType.Name} not found");
continue;
}
var destinationProperty = objDependencyTargetType.Properties.First(x => x.Name == destinationPropertyName);
// The property on the facade/decorator should have a setter
if (facadeProperty.SetMethod == null)
{
LogError($"Property {facadeProperty.DeclaringType.FullName}.{facadeProperty.Name} has no setter, therefore it is not possible for the property to change, and thus should not be marked with [ReactiveDecorator]");
continue;
}
// The property on the dependency should have a setter e.g. Dependency.SomeProperty = value;
if (destinationProperty.SetMethod == null)
{
LogError($"Dependency object's property {destinationProperty.DeclaringType.FullName}.{destinationProperty.Name} has no setter, therefore it is not possible for the property to change, and thus should not be marked with [ReactiveDecorator]");
continue;
}
// Remove old field (the generated backing field for the auto property)
var oldField = (FieldReference)facadeProperty.GetMethod.Body.Instructions.Where(x => x.Operand is FieldReference).Single().Operand;
var oldFieldDefinition = oldField.Resolve();
targetType.Fields.Remove(oldFieldDefinition);
// See if there exists an initializer for the auto-property
var constructors = targetType.Methods.Where(x => x.IsConstructor);
foreach (var constructor in constructors)
{
var fieldAssignment = constructor.Body.Instructions.SingleOrDefault(x => Equals(x.Operand, oldFieldDefinition) || Equals(x.Operand, oldField));
if (fieldAssignment != null)
{
// Replace field assignment with a property set (the stack semantics are the same for both,
// so happily we don't have to manipulate the bytecode any further.)
var setterCall = constructor.Body.GetILProcessor().Create(facadeProperty.SetMethod.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, facadeProperty.SetMethod);
constructor.Body.GetILProcessor().Replace(fieldAssignment, setterCall);
}
}
// Build out the getter which simply returns the value of the generated field
facadeProperty.GetMethod.Body = new MethodBody(facadeProperty.GetMethod);
facadeProperty.GetMethod.Body.Emit(il =>
{
il.Emit(OpCodes.Ldarg_0); // this
if (objPropertyTarget != null)
{
il.Emit(objPropertyTarget.GetMethod.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, objPropertyTarget.GetMethod);
}
else
{
il.Emit(OpCodes.Ldfld, objFieldTarget);
}
il.Emit(destinationProperty.GetMethod.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, destinationProperty.GetMethod);
il.Emit(OpCodes.Ret);
});
TypeReference genericTargetType = targetType;
if (targetType.HasGenericParameters)
{
var genericDeclaration = new GenericInstanceType(targetType);
foreach (var parameter in targetType.GenericParameters)
{
genericDeclaration.GenericArguments.Add(parameter);
}
genericTargetType = genericDeclaration;
}
var methodReference = raisePropertyChangedMethod.MakeGenericMethod(genericTargetType);
facadeProperty.SetMethod.Body = new MethodBody(facadeProperty.SetMethod);
facadeProperty.SetMethod.Body.Emit(il =>
{
il.Emit(OpCodes.Ldarg_0);
if (objPropertyTarget != null)
{
il.Emit(objPropertyTarget.GetMethod.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, objPropertyTarget.GetMethod);
}
else
{
il.Emit(OpCodes.Ldfld, objFieldTarget);
}
il.Emit(OpCodes.Ldarg_1);
il.Emit(destinationProperty.SetMethod.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, destinationProperty.SetMethod); // Set the nested property
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldstr, facadeProperty.Name); // "PropertyName"
il.Emit(OpCodes.Call, methodReference); // this.RaisePropertyChanged("PropertyName")
il.Emit(OpCodes.Ret);
});
}
}
}
}
}
================================================
FILE: ReactiveUI.Fody/ReactiveUI.Fody.csproj
================================================
Debug
AnyCPU
{CCACB6C3-4C59-4372-85D1-CDDCE0D26989}
Library
Properties
ReactiveUI.Fody
ReactiveUI.Fody
v4.5
512
true
full
false
bin\Debug\
DEBUG;TRACE
prompt
4
6
pdbonly
true
bin\Release\
TRACE
prompt
4
..\packages\FodyCecil.2.0.9\lib\net40\Mono.Cecil.dll
..\packages\FodyCecil.2.0.9\lib\net40\Mono.Cecil.Mdb.dll
..\packages\FodyCecil.2.0.9\lib\net40\Mono.Cecil.Pdb.dll
..\packages\FodyCecil.2.0.9\lib\net40\Mono.Cecil.Rocks.dll
..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll
..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll
..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll
..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll
..\packages\Rx-XAML.2.2.5\lib\net45\System.Reactive.Windows.Threading.dll
================================================
FILE: ReactiveUI.Fody/ReactiveUIPropertyWeaver.cs
================================================
using System;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Rocks;
namespace ReactiveUI.Fody
{
///
/// Weaver that replaces properties marked with `[DataMember]` on subclasses of `ReactiveObject` with an
/// implementation that invokes `RaisePropertyChanged` as is required for reaciveui.
///
public class ReactiveUIPropertyWeaver
{
public ModuleDefinition ModuleDefinition { get; set; }
// Will log an MessageImportance.High message to MSBuild. OPTIONAL
public Action LogInfo { get; set; }
// Will log an error message to MSBuild. OPTIONAL
public Action LogError { get; set; }
public void Execute()
{
var reactiveUI = ModuleDefinition.AssemblyReferences.Where(x => x.Name == "ReactiveUI").OrderByDescending(x => x.Version).FirstOrDefault();
if (reactiveUI == null)
{
LogInfo("Could not find assembly: ReactiveUI (" + string.Join(", ", ModuleDefinition.AssemblyReferences.Select(x => x.Name)) + ")");
return;
}
LogInfo($"{reactiveUI.Name} {reactiveUI.Version}");
var helpers = ModuleDefinition.AssemblyReferences.Where(x => x.Name == "ReactiveUI.Fody.Helpers").OrderByDescending(x => x.Version).FirstOrDefault();
if (helpers == null)
{
LogInfo("Could not find assembly: ReactiveUI.Fody.Helpers (" + string.Join(", ", ModuleDefinition.AssemblyReferences.Select(x => x.Name)) + ")");
return;
}
LogInfo($"{helpers.Name} {helpers.Version}");
var reactiveObject = new TypeReference("ReactiveUI", "IReactiveObject", ModuleDefinition, reactiveUI);
var targetTypes = ModuleDefinition.GetAllTypes().Where(x => x.BaseType != null && reactiveObject.IsAssignableFrom(x.BaseType)).ToArray();
var reactivePropertyExtensions = ModuleDefinition.FindType("ReactiveUI.Fody.Helpers", "ReactivePropertyExtensions", helpers).Resolve();
if (reactivePropertyExtensions == null)
throw new Exception("reactivePropertyExtensions is null");
var raiseAndSetIfChangedMethod = ModuleDefinition.ImportReference(reactivePropertyExtensions.Methods.Single(x => x.Name == "RaiseAndSetIfChanged"));
if (raiseAndSetIfChangedMethod == null)
throw new Exception("raiseAndSetIfChangedMethod is null");
var reactiveAttribute = ModuleDefinition.FindType("ReactiveUI.Fody.Helpers", "ReactiveAttribute", helpers);
if (reactiveAttribute == null)
throw new Exception("reactiveAttribute is null");
var reactiveObjectExtensions = new TypeReference("ReactiveUI", "IReactiveObjectExtensions", ModuleDefinition, reactiveUI).Resolve();
if (reactiveObjectExtensions == null)
throw new Exception("reactiveObjectExtensions is null");
var raisePropertyChangedMethod = ModuleDefinition.ImportReference(reactiveObjectExtensions.Methods.Single(x => x.Name == "RaisePropertyChanged"));
if (raisePropertyChangedMethod == null)
throw new Exception("raisePropertyChangedMethod is null");
foreach (var targetType in targetTypes)
{
var setMethodByGetMethods = targetType.Properties
.Where(x => x.SetMethod != null && x.GetMethod != null && x.IsDefined(reactiveAttribute))
.ToDictionary(x => x.GetMethod, x => x.SetMethod);
foreach (var property in targetType.Properties.Where(x => x.IsDefined(reactiveAttribute)).ToArray())
{
TypeReference genericTargetType = targetType;
if (targetType.HasGenericParameters)
{
var genericDeclaration = new GenericInstanceType(targetType);
foreach (var parameter in targetType.GenericParameters)
{
genericDeclaration.GenericArguments.Add(parameter);
}
genericTargetType = genericDeclaration;
}
MethodDefinition[] getMethods;
if (property.SetMethod == null && property.GetMethod.TryGetMethodDependencies(out getMethods))
{
var setMethodsForGetInstructions = getMethods
.Where(x => setMethodByGetMethods.ContainsKey(x))
.Select(x => setMethodByGetMethods[x])
.ToArray();
if (!setMethodsForGetInstructions.Any())
{
LogError($"Get only Property {property.DeclaringType.FullName}.{property.Name} has no supported dependent properties. " +
$"Only dependent auto properties decorated with the [Reactive] attribute can be weaved to raise property change on {property.Name}");
}
var raisePropertyChangedMethodReference = raisePropertyChangedMethod.MakeGenericMethod(genericTargetType);
foreach (var method in setMethodsForGetInstructions)
{
method.Body.Emit(il =>
{
var last = method.Body.Instructions.Last(i => i.OpCode == OpCodes.Ret);
il.InsertBefore(last, il.Create(OpCodes.Ldarg_0));
il.InsertBefore(last, il.Create(OpCodes.Ldstr, property.Name));
il.InsertBefore(last, il.Create(OpCodes.Call, raisePropertyChangedMethodReference));
});
}
// Move on to next property for the target type
continue;
}
if (property.SetMethod == null)
{
LogError($"Property {property.DeclaringType.FullName}.{property.Name} has no setter, therefore it is not possible for the property to change, and thus should not be marked with [Reactive]");
continue;
}
// Declare a field to store the property value
var field = new FieldDefinition("$" + property.Name, FieldAttributes.Private, property.PropertyType);
targetType.Fields.Add(field);
// Remove old field (the generated backing field for the auto property)
var oldField = (FieldReference)property.GetMethod.Body.Instructions.Where(x => x.Operand is FieldReference).Single().Operand;
var oldFieldDefinition = oldField.Resolve();
targetType.Fields.Remove(oldFieldDefinition);
// See if there exists an initializer for the auto-property
var constructors = targetType.Methods.Where(x => x.IsConstructor);
foreach (var constructor in constructors)
{
var fieldAssignment = constructor.Body.Instructions.SingleOrDefault(x => Equals(x.Operand, oldFieldDefinition) || Equals(x.Operand, oldField));
if (fieldAssignment != null)
{
// Replace field assignment with a property set (the stack semantics are the same for both,
// so happily we don't have to manipulate the bytecode any further.)
var setterCall = constructor.Body.GetILProcessor().Create(property.SetMethod.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, property.SetMethod);
constructor.Body.GetILProcessor().Replace(fieldAssignment, setterCall);
}
}
// Build out the getter which simply returns the value of the generated field
property.GetMethod.Body = new MethodBody(property.GetMethod);
property.GetMethod.Body.Emit(il =>
{
il.Emit(OpCodes.Ldarg_0); // this
il.Emit(OpCodes.Ldfld, field.BindDefinition(targetType)); // pop -> this.$PropertyName
il.Emit(OpCodes.Ret); // Return the field value that is lying on the stack
});
var methodReference = raiseAndSetIfChangedMethod.MakeGenericMethod(genericTargetType, property.PropertyType);
// Build out the setter which fires the RaiseAndSetIfChanged method
if (property.SetMethod == null)
{
throw new Exception("[Reactive] is decorating " + property.DeclaringType.FullName + "." + property.Name + ", but the property has no setter so there would be nothing to react to. Consider removing the attribute.");
}
property.SetMethod.Body = new MethodBody(property.SetMethod);
property.SetMethod.Body.Emit(il =>
{
RaiseAndSetIfChanged(methodReference, targetType, field, il, property.Name);
});
}
}
}
private void RaiseAndSetIfChanged(MethodReference raiseAndSetIfChangedMethod, TypeDefinition targetType, FieldDefinition field, ILProcessor il, string propertyName)
{
il.Emit(OpCodes.Ldarg_0); // this
il.Emit(OpCodes.Ldarg_0); // this
il.Emit(OpCodes.Ldflda, field.BindDefinition(targetType)); // pop -> ref this.$PropertyName
il.Emit(OpCodes.Ldarg_1); // value
il.Emit(OpCodes.Ldstr, propertyName); // "PropertyName"
il.Emit(OpCodes.Call, raiseAndSetIfChangedMethod); // pop * 4 -> this.RaiseAndSetIfChanged(this.$PropertyName, value, "PropertyName")
il.Emit(OpCodes.Pop); // We don't care about the result of RaiseAndSetIfChanged, so pop it off the stack (stack is now empty)
il.Emit(OpCodes.Ret); // Return out of the function
}
}
}
================================================
FILE: ReactiveUI.Fody/packages.config
================================================
================================================
FILE: ReactiveUI.Fody.Helpers/LogPropertyOnErrorException.cs
================================================
using System;
namespace ReactiveUI.Fody.Helpers
{
public class LogPropertyOnErrorException : Exception
{
public new object Source { get; }
public string Property { get; }
public LogPropertyOnErrorException(object source, string property, Exception innerException) :
base($"An exception occurred when a property change notification was fired on {source.GetType().FullName}.{property} on an instance of {source.GetType().FullName}: {source}", innerException)
{
Source = source;
Property = property;
}
}
}
================================================
FILE: ReactiveUI.Fody.Helpers/LogPropertyOnErrorObservable.cs
================================================
using System;
namespace ReactiveUI.Fody.Helpers
{
internal class LogPropertyOnErrorObservable : IObservable
{
private readonly IObservable @this;
private readonly object source;
private readonly string property;
public LogPropertyOnErrorObservable(IObservable @this, object source, string property)
{
this.@this = @this;
this.source = source;
this.property = property;
}
public IDisposable Subscribe(IObserver observer)
{
return @this.Subscribe(new LogPropertyOnErrorObserver(observer, source, property));
}
private class LogPropertyOnErrorObserver : IObserver
{
private readonly IObserver @this;
private readonly object source;
private readonly string property;
public LogPropertyOnErrorObserver(IObserver @this, object source, string property)
{
this.@this = @this;
this.source = source;
this.property = property;
}
public void OnCompleted()
{
@this.OnCompleted();
}
public void OnError(Exception error)
{
@this.OnError(new LogPropertyOnErrorException(source, property, error));
}
public void OnNext(T value)
{
@this.OnNext(value);
}
}
}
}
================================================
FILE: ReactiveUI.Fody.Helpers/ObservableAsPropertyAttribute.cs
================================================
using System;
namespace ReactiveUI.Fody.Helpers
{
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)]
public class ObservableAsPropertyAttribute : Attribute
{
}
}
================================================
FILE: ReactiveUI.Fody.Helpers/ObservableAsPropertyExtensions.cs
================================================
using System;
using System.Linq.Expressions;
using System.Reactive.Concurrency;
using System.Reflection;
using ReactiveUI.Fody.Helpers.Settings;
namespace ReactiveUI.Fody.Helpers
{
public static class ObservableAsPropertyExtensions
{
public static ObservableAsPropertyHelper ToPropertyEx(this IObservable @this, TObj source, Expression> property, TRet initialValue = default(TRet), bool deferSubscription = false, IScheduler scheduler = null) where TObj : ReactiveObject
{
// Now assign the field via reflection.
var propertyInfo = property.GetPropertyInfo();
if (propertyInfo == null)
throw new Exception("Could not resolve expression " + property + " into a property.");
if (GlobalSettings.IsLogPropertyOnErrorEnabled)
@this = new LogPropertyOnErrorObservable(@this, source, propertyInfo.Name);
var result = @this.ToProperty(source, property, initialValue, deferSubscription, scheduler);
var field = propertyInfo.DeclaringType.GetTypeInfo().GetDeclaredField("$" + propertyInfo.Name);
if (field == null)
throw new Exception("Backing field not found for " + propertyInfo);
field.SetValue(source, result);
return result;
}
static PropertyInfo GetPropertyInfo(this LambdaExpression expression)
{
var current = expression.Body;
var unary = current as UnaryExpression;
if (unary != null)
current = unary.Operand;
var call = (MemberExpression)current;
return (PropertyInfo)call.Member;
}
}
}
================================================
FILE: ReactiveUI.Fody.Helpers/ReactiveAttribute.cs
================================================
using System;
namespace ReactiveUI.Fody.Helpers
{
[AttributeUsage(AttributeTargets.Property)]
public class ReactiveAttribute : Attribute
{
}
}
================================================
FILE: ReactiveUI.Fody.Helpers/ReactiveDependencyAttribute.cs
================================================
using System;
using System.Collections.Generic;
using System.Text;
namespace ReactiveUI.Fody.Helpers
{
[AttributeUsage(AttributeTargets.Property)]
public class ReactiveDependencyAttribute : Attribute
{
private readonly string _targetName;
public ReactiveDependencyAttribute(string targetName)
{
_targetName = targetName;
}
///
/// The name of the backing property
///
public string Target => _targetName;
///
/// Target property on the backing property
///
public string TargetProperty { get; set; }
}
}
================================================
FILE: ReactiveUI.Fody.Helpers/ReactivePropertyExtensions.cs
================================================
using System;
using System.Reflection;
using ReactiveUI.Fody.Helpers.Settings;
namespace ReactiveUI.Fody.Helpers
{
public static class ReactivePropertyExtensions
{
public static TRet RaiseAndSetIfChanged(this TObj @this, ref TRet backingField, TRet newValue, string propertyName = null) where TObj : IReactiveObject
{
if (GlobalSettings.IsLogPropertyOnErrorEnabled)
{
try
{
return IReactiveObjectExtensions.RaiseAndSetIfChanged(@this, ref backingField, newValue, propertyName);
}
catch (Exception ex)
{
throw new LogPropertyOnErrorException(@this, propertyName, ex);
}
}
else
{
return IReactiveObjectExtensions.RaiseAndSetIfChanged(@this, ref backingField, newValue, propertyName);
}
}
}
}
================================================
FILE: ReactiveUI.Fody.Helpers/ReactiveUI.Fody.Helpers.projitems
================================================
$(MSBuildAllProjects);$(MSBuildThisFileFullPath)
true
4433ff2e-3150-4d7f-be18-a2258799b79d
ReactiveUI.Fody.Helpers
================================================
FILE: ReactiveUI.Fody.Helpers/ReactiveUI.Fody.Helpers.shproj
================================================
4433ff2e-3150-4d7f-be18-a2258799b79d
================================================
FILE: ReactiveUI.Fody.Helpers/Settings/GlobalSettings.cs
================================================
namespace ReactiveUI.Fody.Helpers.Settings
{
public static class GlobalSettings
{
public static bool IsLogPropertyOnErrorEnabled { get; set; }
}
}
================================================
FILE: ReactiveUI.Fody.Helpers.Android/Properties/AssemblyInfo.cs
================================================
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Android.App;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ReactiveUI.Fody.Helpers")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ReactiveUI.Fody.Helpers")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
================================================
FILE: ReactiveUI.Fody.Helpers.Android/ReactiveUI.Fody.Helpers.Android.csproj
================================================
Debug
AnyCPU
8.0.30703
2.0
{6D2A6846-A8B7-4186-807D-12E335BD1C67}
{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
Library
Properties
ReactiveUI.Fody.Helpers
ReactiveUI.Fody.Helpers
512
Resources\Resource.Designer.cs
Off
True
True
v5.0
true
full
false
bin\Debug\
DEBUG;TRACE
prompt
4
pdbonly
true
bin\Release\
TRACE
prompt
4
..\packages\reactiveui-core.7.0.0\lib\portable-net45+netcore45+wpa81+win8+wp8+UAP10+MonoAndroid403+MonoTouch10+Xamarin.iOS10\ReactiveUI.dll
True
..\packages\Splat.1.6.0\lib\monoandroid\Splat.dll
..\packages\Rx-Core.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Core.dll
..\packages\Rx-Interfaces.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Interfaces.dll
..\packages\Rx-Linq.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Linq.dll
..\packages\Rx-PlatformServices.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.PlatformServices.dll
================================================
FILE: ReactiveUI.Fody.Helpers.Android/Resources/AboutResources.txt
================================================
Images, layout descriptions, binary blobs and string dictionaries can be included
in your application as resource files. Various Android APIs are designed to
operate on the resource IDs instead of dealing with images, strings or binary blobs
directly.
For example, a sample Android app that contains a user interface layout (main.xml),
an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
would keep its resources in the "Resources" directory of the application:
Resources/
drawable-hdpi/
icon.png
drawable-ldpi/
icon.png
drawable-mdpi/
icon.png
layout/
main.xml
values/
strings.xml
In order to get the build system to recognize Android resources, set the build action to
"AndroidResource". The native Android APIs do not operate directly with filenames, but
instead operate on resource IDs. When you compile an Android application that uses resources,
the build system will package the resources for distribution and generate a class called
"Resource" that contains the tokens for each one of the resources included. For example,
for the above Resources layout, this is what the Resource class would expose:
public class Resource {
public class drawable {
public const int icon = 0x123;
}
public class layout {
public const int main = 0x456;
}
public class strings {
public const int first_string = 0xabc;
public const int second_string = 0xbcd;
}
}
You would then use R.drawable.icon to reference the drawable/icon.png file, or Resource.layout.main
to reference the layout/main.xml file, or Resource.strings.first_string to reference the first
string in the dictionary file values/strings.xml.
================================================
FILE: ReactiveUI.Fody.Helpers.Android/Resources/Resource.Designer.cs
================================================
#pragma warning disable 1591
//------------------------------------------------------------------------------
//
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//
//------------------------------------------------------------------------------
[assembly: global::Android.Runtime.ResourceDesignerAttribute("ReactiveUI.Fody.Helpers.Resource", IsApplication=false)]
namespace ReactiveUI.Fody.Helpers
{
[System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")]
public partial class Resource
{
static Resource()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
public partial class Attribute
{
static Attribute()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
private Attribute()
{
}
}
public partial class String
{
// aapt resource value: 0x7f020002
public static int ApplicationName = 2130837506;
// aapt resource value: 0x7f020001
public static int Hello = 2130837505;
// aapt resource value: 0x7f020000
public static int library_name = 2130837504;
static String()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
private String()
{
}
}
}
}
#pragma warning restore 1591
================================================
FILE: ReactiveUI.Fody.Helpers.Android/Resources/Values/Strings.xml
================================================
Hello World, Click Me!
$projectname$
================================================
FILE: ReactiveUI.Fody.Helpers.Android/packages.config
================================================
================================================
FILE: ReactiveUI.Fody.Helpers.Ios/Properties/AssemblyInfo.cs
================================================
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ReactiveUI.Fody.Helpers.Ios")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ReactiveUI.Fody.Helpers.Ios")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("2986e217-fe12-4070-8926-fe6ac596094e")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
================================================
FILE: ReactiveUI.Fody.Helpers.Ios/ReactiveUI.Fody.Helpers.Ios.csproj
================================================
Debug
iPhoneSimulator
8.0.30703
2.0
{377C39ED-0F7E-4522-A41E-96C5BA0C4FCB}
{FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
Library
ReactiveUI.Fody.Helpers
Resources
ReactiveUI.Fody.Helpers
true
full
false
bin\iPhone\Debug
DEBUG
prompt
4
false
true
iPhone Developer
none
true
bin\iPhone\Release
prompt
4
false
iPhone Developer
..\packages\reactiveui-core.7.0.0\lib\portable-net45+netcore45+wpa81+win8+wp8+UAP10+MonoAndroid403+MonoTouch10+Xamarin.iOS10\ReactiveUI.dll
True
..\packages\Splat.1.6.0\lib\Xamarin.iOS10\Splat.dll
..\packages\Rx-Core.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Core.dll
..\packages\Rx-Interfaces.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Interfaces.dll
..\packages\Rx-Linq.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Linq.dll
..\packages\Rx-PlatformServices.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.PlatformServices.dll
================================================
FILE: ReactiveUI.Fody.Helpers.Ios/packages.config
================================================
================================================
FILE: ReactiveUI.Fody.Helpers.Net45/Properties/AssemblyInfo.cs
================================================
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ReactiveUI.Fody.Helpers.Net45")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ReactiveUI.Fody.Helpers.Net45")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("525a89d6-cbd1-4776-9692-952d32f01e28")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
================================================
FILE: ReactiveUI.Fody.Helpers.Net45/ReactiveUI.Fody.Helpers.Net45.csproj
================================================
Debug
AnyCPU
{1CA52110-BE45-4C45-B709-28061077E2A5}
Library
Properties
ReactiveUI.Fody.Helpers
ReactiveUI.Fody.Helpers
v4.5
512
true
full
false
bin\Debug\
DEBUG;TRACE
prompt
4
pdbonly
true
bin\Release\
TRACE
prompt
4
..\packages\reactiveui-core.7.0.0\lib\portable-net45+netcore45+wpa81+win8+wp8+UAP10+MonoAndroid403+MonoTouch10+Xamarin.iOS10\ReactiveUI.dll
True
..\packages\Splat.1.6.0\lib\Net45\Splat.dll
..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll
..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll
..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll
..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll
..\packages\Rx-XAML.2.2.5\lib\net45\System.Reactive.Windows.Threading.dll
================================================
FILE: ReactiveUI.Fody.Helpers.Net45/packages.config
================================================
================================================
FILE: ReactiveUI.Fody.Helpers.Pcl/Properties/AssemblyInfo.cs
================================================
using System.Resources;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ReactiveUI.Fody.Helpers.Pcl")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ReactiveUI.Fody.Helpers.Pcl")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: NeutralResourcesLanguage("en")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
================================================
FILE: ReactiveUI.Fody.Helpers.Pcl/ReactiveUI.Fody.Helpers.Pcl.csproj
================================================
10.0
Debug
AnyCPU
{8509509A-17C7-4CF0-84AD-5DD208446766}
Library
Properties
ReactiveUI.Fody.Helpers
ReactiveUI.Fody.Helpers
en-US
512
{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
Profile259
v4.5
true
full
false
bin\Debug\
DEBUG;TRACE
prompt
4
pdbonly
true
bin\Release\
TRACE
prompt
4
..\packages\reactiveui-core.7.0.0\lib\portable-net45+netcore45+wpa81+win8+wp8+UAP10+MonoAndroid403+MonoTouch10+Xamarin.iOS10\ReactiveUI.dll
True
..\packages\Splat.1.6.0\lib\Portable-net45+win+wpa81+wp80\Splat.dll
..\packages\Rx-Core.2.2.5\lib\portable-net45+winrt45+wp8+wpa81\System.Reactive.Core.dll
..\packages\Rx-Interfaces.2.2.5\lib\portable-net45+winrt45+wp8+wpa81\System.Reactive.Interfaces.dll
..\packages\Rx-Linq.2.2.5\lib\portable-net45+winrt45+wp8+wpa81\System.Reactive.Linq.dll
..\packages\Rx-PlatformServices.2.2.5\lib\portable-net45+winrt45+wp8+wpa81\System.Reactive.PlatformServices.dll
================================================
FILE: ReactiveUI.Fody.Helpers.Pcl/packages.config
================================================
================================================
FILE: ReactiveUI.Fody.Tests/FodyWeavers.xml
================================================
================================================
FILE: ReactiveUI.Fody.Tests/Issues/Issue10Tests.cs
================================================
using System;
using NUnit.Framework;
using ReactiveUI.Fody.Helpers;
namespace ReactiveUI.Fody.Tests.Issues
{
[TestFixture]
public class Issue10Tests
{
[Test]
public void UninitializedObservableAsPropertyHelperDoesntThrowAndReturnsDefaultValue()
{
var model = new TestModel();
Assert.AreEqual(null, model.MyProperty);
Assert.AreEqual(0, model.MyIntProperty);
Assert.AreEqual(default(DateTime), model.MyDateTimeProperty);
}
class TestModel : ReactiveObject
{
[ObservableAsProperty]
public string MyProperty { get; private set; }
[ObservableAsProperty]
public int MyIntProperty { get; private set; }
[ObservableAsProperty]
public DateTime MyDateTimeProperty { get; private set; }
public string OtherProperty { get; private set; }
public TestModel()
{
OtherProperty = MyProperty;
}
}
}
}
================================================
FILE: ReactiveUI.Fody.Tests/Issues/Issue11Tests.cs
================================================
using System.Reactive.Linq;
using NUnit.Framework;
using ReactiveUI.Fody.Helpers;
namespace ReactiveUI.Fody.Tests.Issues
{
[TestFixture]
public class Issue11Tests
{
[Test]
public void AllowObservableAsPropertyAttributeOnAccessor()
{
var model = new TestModel("foo");
Assert.AreEqual("foo", model.MyProperty);
}
public class TestModel : ReactiveObject
{
public extern string MyProperty { [ObservableAsProperty]get; }
public TestModel(string myProperty)
{
Observable.Return(myProperty).ToPropertyEx(this, x => x.MyProperty);
}
}
}
}
================================================
FILE: ReactiveUI.Fody.Tests/Issues/Issue13Tests.cs
================================================
using NUnit.Framework;
using ReactiveUI.Fody.Helpers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ReactiveUI.Fody.Tests.Issues
{
[TestFixture]
public class Issue13Tests
{
[Test]
public void AccessingAChainedObservableAsPropertyOfDoubleDoesntThrow()
{
var vm = new VM();
Assert.AreEqual(0.0, vm.P2);
}
class VM : ReactiveObject
{
[ObservableAsProperty] public double P1 { get; }
[ObservableAsProperty] public double P2 { get; }
public VM()
{
Observable.Return(0.0).ToPropertyEx(this, vm => vm.P1);
this.WhenAnyValue(vm => vm.P1).ToPropertyEx(this, vm => vm.P2);
}
}
}
}
================================================
FILE: ReactiveUI.Fody.Tests/Issues/Issue31Tests.cs
================================================
using System;
using System.Reactive.Linq;
using NUnit.Framework;
using ReactiveUI.Fody.Helpers;
using GlobalSettings = ReactiveUI.Fody.Helpers.Settings.GlobalSettings;
namespace ReactiveUI.Fody.Tests.Issues
{
[TestFixture]
public class Issue31Tests
{
[Test]
public void ExceptionPropertyInfoForReactiveProperty()
{
try
{
GlobalSettings.IsLogPropertyOnErrorEnabled = true;
try
{
var model = new ReactivePropertyModel();
model.MyProperty = "foo";
Assert.Fail();
}
catch (LogPropertyOnErrorException ex)
{
Assert.AreEqual(nameof(ObservableAsPropertyModel.MyProperty), ex.Property);
}
}
finally
{
GlobalSettings.IsLogPropertyOnErrorEnabled = false;
}
}
[Test]
public void ExceptionPropertyInfoForObservableAsProperty()
{
try
{
GlobalSettings.IsLogPropertyOnErrorEnabled = true;
try
{
new ObservableAsPropertyModel();
Assert.Fail();
}
catch (UnhandledErrorException ex)
{
var propertyException = (LogPropertyOnErrorException)ex.InnerException;
Assert.AreEqual(nameof(ObservableAsPropertyModel.MyProperty), propertyException.Property);
}
}
finally
{
GlobalSettings.IsLogPropertyOnErrorEnabled = false;
}
}
public class ObservableAsPropertyModel : ReactiveObject
{
public extern string MyProperty { [ObservableAsProperty]get; }
public ObservableAsPropertyModel()
{
Observable.Throw(new Exception("Observable error")).ToPropertyEx(this, x => x.MyProperty);
}
}
public class ReactivePropertyModel : ReactiveObject
{
[Reactive]public string MyProperty { get; set; }
public ReactivePropertyModel()
{
this.ObservableForProperty(x => x.MyProperty).Subscribe(_ =>
{
throw new Exception("Subscribe error");
});
}
}
}
}
================================================
FILE: ReactiveUI.Fody.Tests/Issues/Issue41Tests.cs
================================================
using System;
using System.Collections.Generic;
using System.ComponentModel;
using NUnit.Framework;
using ReactiveUI.Fody.Helpers;
namespace ReactiveUI.Fody.Tests.Issues
{
[TestFixture]
public class Issue41Tests
{
[Test]
public void PropertyChangedRaisedForDerivedPropertyOnIntPropertySet()
{
// Arrange
var model = new TestModel();
var expectedInpcPropertyName = nameof(TestModel.DerivedProperty);
var receivedInpcPropertyNames = new List();
var inpc = (INotifyPropertyChanged) model;
inpc.PropertyChanged += (sender, args) => receivedInpcPropertyNames.Add(args.PropertyName);
// Act
model.IntProperty = 5;
// Assert
Assert.IsTrue(receivedInpcPropertyNames.Contains(expectedInpcPropertyName));
}
[Test]
public void PropertyChangedRaisedOnStringPropertySet()
{
// Arrange
var model = new TestModel();
var expectedInpcPropertyName = nameof(TestModel.DerivedProperty);
var receivedInpcPropertyNames = new List();
var inpc = (INotifyPropertyChanged) model;
inpc.PropertyChanged += (sender, args) => receivedInpcPropertyNames.Add(args.PropertyName);
// Act
model.StringProperty = "Foo";
// Assert
Assert.IsTrue(receivedInpcPropertyNames.Contains(expectedInpcPropertyName));
}
[Test]
public void PropertyChangedRaisedForDerivedPropertyAndAnotherExpressionBodiedPropertyAndCombinedExpressionBodyPropertyWithAutoPropOnIntPropertySet()
{
// Arrange
var model = new TestModel();
var expectedInpcPropertyName1 = nameof(TestModel.AnotherExpressionBodiedProperty);
var expectedInpcPropertyName2 = nameof(TestModel.DerivedProperty);
var expectedInpcPropertyName3 = nameof(TestModel.CombinedExpressionBodyPropertyWithAutoProp);
var receivedInpcPropertyNames = new List();
var inpc = (INotifyPropertyChanged) model;
inpc.PropertyChanged += (sender, args) => receivedInpcPropertyNames.Add(args.PropertyName);
// Act
model.IntProperty = 5;
// Assert
Assert.IsTrue(receivedInpcPropertyNames.Contains(expectedInpcPropertyName1));
Assert.IsTrue(receivedInpcPropertyNames.Contains(expectedInpcPropertyName2));
Assert.IsTrue(receivedInpcPropertyNames.Contains(expectedInpcPropertyName3));
}
[Test]
public void PropertyChangedRaisedForCombinedExpressionBodyPropertyWithAutoPropOnStringPropertySet()
{
// Arrange
var model = new TestModel();
var expectedInpcPropertyName = nameof(TestModel.CombinedExpressionBodyPropertyWithAutoProp);
var receivedInpcPropertyNames = new List();
var inpc = (INotifyPropertyChanged)model;
inpc.PropertyChanged += (sender, args) => receivedInpcPropertyNames.Add(args.PropertyName);
// Act
model.StringProperty = "Foo";
// Assert
Assert.IsTrue(receivedInpcPropertyNames.Contains(expectedInpcPropertyName));
}
[Test]
public void PropertyChangedRaisedForCombinedExpressionBodyPropertyWithAutoPropNonReactivePropertyOnIntPropertySet()
{
// Arrange
var model = new TestModel();
var expectedInpcPropertyName = nameof(TestModel.CombinedExpressionBodyPropertyWithAutoPropNonReactiveProperty);
var receivedInpcPropertyNames = new List();
var inpc = (INotifyPropertyChanged)model;
inpc.PropertyChanged += (sender, args) => receivedInpcPropertyNames.Add(args.PropertyName);
// Act
model.IntProperty = 5;
// Assert
Assert.IsTrue(receivedInpcPropertyNames.Contains(expectedInpcPropertyName));
}
[Test]
// Ensure that this only works with dependent properties that have the [Reactive] attribute
public void PropertyChangedNotRaisedForCombinedExpressionBodyPropertyWithAutoPropNonReactivePropertyOnNonReactivePropertySet()
{
// Arrange
var model = new TestModel();
var expectedInpcPropertyName = nameof(TestModel.CombinedExpressionBodyPropertyWithAutoPropNonReactiveProperty);
var receivedInpcPropertyNames = new List();
var inpc = (INotifyPropertyChanged)model;
inpc.PropertyChanged += (sender, args) => receivedInpcPropertyNames.Add(args.PropertyName);
// Act
model.NonReactiveProperty = "Foo";
// Assert
Assert.IsEmpty(receivedInpcPropertyNames);
}
class TestModel : ReactiveObject
{
[Reactive]
public int IntProperty { get; set; }
[Reactive]
public string StringProperty { get; set; }
public string NonReactiveProperty { get; set; }
[Reactive]
// Raise property change when either StringProperty or IntProperty are set
public string DerivedProperty => StringProperty + IntProperty;
[Reactive]
// Raise property change when IntProperty is set
public int AnotherExpressionBodiedProperty => IntProperty;
[Reactive]
// Raise property changed when StringProperty or IntProperty is set (as AnotherExpressionBodiedProperty is dependent upon IntProperty)
public string CombinedExpressionBodyPropertyWithAutoProp => AnotherExpressionBodiedProperty + StringProperty;
[Reactive]
public string CombinedExpressionBodyPropertyWithAutoPropNonReactiveProperty => CombinedExpressionBodyPropertyWithAutoProp + NonReactiveProperty;
}
}
}
================================================
FILE: ReactiveUI.Fody.Tests/Issues/Issue47Tests.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ReactiveUI.Fody.Helpers;
namespace ReactiveUI.Fody.Tests.Issues
{
public class Issue47Tests
{
///
/// The "test" here is simply for these to compile
/// Tests ObservableAsPropertyWeaver.EmitDefaultValue
///
class TestModel : ReactiveObject
{
public extern int IntProperty { [ObservableAsProperty] get; }
public extern double DoubleProperty { [ObservableAsProperty] get; }
public extern float FloatProperty { [ObservableAsProperty] get; }
public extern long LongProperty { [ObservableAsProperty] get; }
}
}
}
================================================
FILE: ReactiveUI.Fody.Tests/ObservableAsPropertyTests.cs
================================================
using System.Reactive.Linq;
using NUnit.Framework;
using ReactiveUI.Fody.Helpers;
namespace ReactiveUI.Fody.Tests
{
public class ObservableAsPropertyTests
{
[Test]
public void TestPropertyReturnsFoo()
{
var model = new TestModel();
Assert.AreEqual("foo", model.TestProperty);
}
class TestModel : ReactiveObject
{
[ObservableAsProperty]
public string TestProperty { get; private set; }
public TestModel()
{
Observable.Return("foo").ToPropertyEx(this, x => x.TestProperty);
}
}
}
}
================================================
FILE: ReactiveUI.Fody.Tests/Properties/AssemblyInfo.cs
================================================
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ReactiveUI.Fody.Tests")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ReactiveUI.Fody.Tests")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("a735c110-6877-4c3a-8056-9abc5fb2dd91")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
================================================
FILE: ReactiveUI.Fody.Tests/ReactiveDependencyTests.cs
================================================
using System;
using System.ComponentModel;
using NUnit.Framework;
using ReactiveUI.Fody.Helpers;
namespace ReactiveUI.Fody.Tests
{
public class ReactiveDependencyTests
{
[Test]
public void IntPropertyOnWeavedFacadeReturnsBaseModelIntPropertyDefaultValueTest()
{
var model = new BaseModel();
var expectedResult = model.IntProperty;
var facade = new FacadeModel(model);
Assert.AreEqual(expectedResult, facade.IntProperty);
}
[Test]
public void AnotherStringPropertyOnFacadeReturnsBaseModelStringPropertyDefaultValueTest()
{
var model = new BaseModel();
var expectedResult = model.StringProperty;
var facade = new FacadeModel(model);
Assert.AreEqual(expectedResult, facade.AnotherStringProperty);
}
[Test]
public void SettingAnotherStringPropertyUpdatesTheDependencyStringProperty()
{
var expectedResult = "New String Value";
var facade = new FacadeModel(new BaseModel());
facade.AnotherStringProperty = expectedResult;
Assert.AreEqual(expectedResult, facade.Dependency.StringProperty);
}
[Test]
public void SettingFacadeIntPropertyUpdatesDependencyIntProperty()
{
var expectedResult = 999;
var facade = new FacadeModel(new BaseModel());
facade.IntProperty = expectedResult;
Assert.AreEqual(expectedResult, facade.Dependency.IntProperty);
}
[Test]
public void FacadeIntPropertyChangedEventFiresOnAssignementTest()
{
var expectedPropertyChanged = "IntProperty";
var resultPropertyChanged = string.Empty;
var facade = new FacadeModel(new BaseModel());
var obj = (INotifyPropertyChanged) facade;
obj.PropertyChanged += (sender, args) => resultPropertyChanged = args.PropertyName;
facade.IntProperty = 999;
Assert.AreEqual(expectedPropertyChanged, resultPropertyChanged);
}
[Test]
public void FacadeAnotherStringPropertyChangedEventFiresOnAssignementTest()
{
var expectedPropertyChanged = "AnotherStringProperty";
var resultPropertyChanged = string.Empty;
var facade = new FacadeModel(new BaseModel());
var obj = (INotifyPropertyChanged) facade;
obj.PropertyChanged += (sender, args) => resultPropertyChanged = args.PropertyName;
facade.AnotherStringProperty = "Some New Value";
Assert.AreEqual(expectedPropertyChanged, resultPropertyChanged);
}
[Test]
public void StringPropertyOnWeavedDecoratorReturnsBaseModelDefaultStringValue()
{
var model = new BaseModel();
var expectedResult = model.StringProperty;
var decorator = new DecoratorModel(model);
Assert.AreEqual(expectedResult, decorator.StringProperty);
}
[Test]
public void DecoratorStringPropertyRaisesPropertyChanged()
{
var expectedPropertyChanged = "StringProperty";
var resultPropertyChanged = string.Empty;
var decorator = new DecoratorModel(new BaseModel());
var obj = (INotifyPropertyChanged) decorator;
obj.PropertyChanged += (sender, args) => resultPropertyChanged = args.PropertyName;
decorator.StringProperty = "Some New Value";
Assert.AreEqual(expectedPropertyChanged, resultPropertyChanged);
}
}
public class BaseModel : ReactiveObject
{
public virtual int IntProperty { get; set; } = 5;
public virtual string StringProperty { get; set; } = "Initial Value";
}
public class FacadeModel : ReactiveObject
{
private BaseModel _dependency;
public FacadeModel()
{
_dependency = new BaseModel();
}
public FacadeModel(BaseModel dependency)
{
_dependency = dependency;
}
public BaseModel Dependency
{
get { return _dependency; }
private set { _dependency = value; }
}
// Property with the same name, will look for a like for like name on the named dependency
[ReactiveDependency(nameof(Dependency))]
public int IntProperty { get; set; }
// Property named differently to that on the dependency but still pass through value
[ReactiveDependency(nameof(Dependency), TargetProperty = "StringProperty")]
public string AnotherStringProperty { get; set; }
}
public class DecoratorModel : BaseModel
{
private readonly BaseModel _model;
// Testing ctor
public DecoratorModel()
{
_model = new BaseModel();
}
public DecoratorModel(BaseModel baseModel)
{
_model = baseModel;
}
[Reactive]
public string SomeCoolNewProperty { get; set; }
// Works with private fields
[ReactiveDependency(nameof(_model))]
public override string StringProperty { get; set; }
// Can't be attributed as has additional functionality in the decorated get
public override int IntProperty
{
get { return _model.IntProperty * 2; }
set
{
_model.IntProperty = value;
this.RaisePropertyChanged();
}
}
}
}
================================================
FILE: ReactiveUI.Fody.Tests/ReactiveUI.Fody.Tests.csproj
================================================
Debug
AnyCPU
{A735C110-6877-4C3A-8056-9ABC5FB2DD91}
Library
Properties
ReactiveUI.Fody.Tests
ReactiveUI.Fody.Tests
v4.5
512
true
full
false
bin\Debug\
DEBUG;TRACE
prompt
4
pdbonly
true
bin\Release\
TRACE
prompt
4
..\packages\NUnit.3.2.0\lib\net45\nunit.framework.dll
True
..\packages\reactiveui-core.7.0.0\lib\Net45\ReactiveUI.dll
True
..\packages\Splat.1.6.0\lib\Net45\Splat.dll
True
..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll
True
..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll
True
..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll
True
..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll
True
..\packages\Rx-XAML.2.2.5\lib\net45\System.Reactive.Windows.Threading.dll
True
Designer
Designer
{1ca52110-be45-4c45-b709-28061077e2a5}
ReactiveUI.Fody.Helpers.Net45
copy $(SolutionDir)ReactiveUI.Fody\bin\$(ConfigurationName)\ReactiveUI.Fody.dll $(SolutionDir)Weavers\bin\Weavers.dll
copy $(SolutionDir)ReactiveUI.Fody\bin\$(ConfigurationName)\ReactiveUI.Fody.pdb $(SolutionDir)Weavers\bin\Weavers.pdb
This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
================================================
FILE: ReactiveUI.Fody.Tests/packages.config
================================================
================================================
FILE: ReactiveUIFody.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReactiveUI.Fody", "ReactiveUI.Fody\ReactiveUI.Fody.csproj", "{CCACB6C3-4C59-4372-85D1-CDDCE0D26989}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "ReactiveUI.Fody.Helpers", "ReactiveUI.Fody.Helpers\ReactiveUI.Fody.Helpers.shproj", "{4433FF2E-3150-4D7F-BE18-A2258799B79D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReactiveUI.Fody.Helpers.Net45", "ReactiveUI.Fody.Helpers.Net45\ReactiveUI.Fody.Helpers.Net45.csproj", "{1CA52110-BE45-4C45-B709-28061077E2A5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReactiveUI.Fody.Helpers.Pcl", "ReactiveUI.Fody.Helpers.Pcl\ReactiveUI.Fody.Helpers.Pcl.csproj", "{8509509A-17C7-4CF0-84AD-5DD208446766}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{841EF03D-D23E-45CB-8BF5-362F32225C96}"
ProjectSection(SolutionItems) = preProject
.nuget\packages.config = .nuget\packages.config
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReactiveUI.Fody.Tests", "ReactiveUI.Fody.Tests\ReactiveUI.Fody.Tests.csproj", "{A735C110-6877-4C3A-8056-9ABC5FB2DD91}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
ReactiveUI.Fody.Helpers\ReactiveUI.Fody.Helpers.projitems*{1ca52110-be45-4c45-b709-28061077e2a5}*SharedItemsImports = 4
ReactiveUI.Fody.Helpers\ReactiveUI.Fody.Helpers.projitems*{4433ff2e-3150-4d7f-be18-a2258799b79d}*SharedItemsImports = 13
ReactiveUI.Fody.Helpers\ReactiveUI.Fody.Helpers.projitems*{8509509a-17c7-4cf0-84ad-5dd208446766}*SharedItemsImports = 4
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CCACB6C3-4C59-4372-85D1-CDDCE0D26989}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CCACB6C3-4C59-4372-85D1-CDDCE0D26989}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CCACB6C3-4C59-4372-85D1-CDDCE0D26989}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CCACB6C3-4C59-4372-85D1-CDDCE0D26989}.Release|Any CPU.Build.0 = Release|Any CPU
{1CA52110-BE45-4C45-B709-28061077E2A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1CA52110-BE45-4C45-B709-28061077E2A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1CA52110-BE45-4C45-B709-28061077E2A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1CA52110-BE45-4C45-B709-28061077E2A5}.Release|Any CPU.Build.0 = Release|Any CPU
{8509509A-17C7-4CF0-84AD-5DD208446766}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8509509A-17C7-4CF0-84AD-5DD208446766}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8509509A-17C7-4CF0-84AD-5DD208446766}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8509509A-17C7-4CF0-84AD-5DD208446766}.Release|Any CPU.Build.0 = Release|Any CPU
{A735C110-6877-4C3A-8056-9ABC5FB2DD91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A735C110-6877-4C3A-8056-9ABC5FB2DD91}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A735C110-6877-4C3A-8056-9ABC5FB2DD91}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A735C110-6877-4C3A-8056-9ABC5FB2DD91}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
================================================
FILE: ReactiveUIFody.sln.DotSettings
================================================
DO_NOT_SHOW
DO_NOT_SHOW
DO_NOT_SHOW
DO_NOT_SHOW
DO_NOT_SHOW
DO_NOT_SHOW
================================================
FILE: ReactiveUIFodyAll.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReactiveUI.Fody", "ReactiveUI.Fody\ReactiveUI.Fody.csproj", "{CCACB6C3-4C59-4372-85D1-CDDCE0D26989}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "ReactiveUI.Fody.Helpers", "ReactiveUI.Fody.Helpers\ReactiveUI.Fody.Helpers.shproj", "{4433FF2E-3150-4D7F-BE18-A2258799B79D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReactiveUI.Fody.Helpers.Net45", "ReactiveUI.Fody.Helpers.Net45\ReactiveUI.Fody.Helpers.Net45.csproj", "{1CA52110-BE45-4C45-B709-28061077E2A5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReactiveUI.Fody.Helpers.Android", "ReactiveUI.Fody.Helpers.Android\ReactiveUI.Fody.Helpers.Android.csproj", "{6D2A6846-A8B7-4186-807D-12E335BD1C67}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReactiveUI.Fody.Helpers.Ios", "ReactiveUI.Fody.Helpers.Ios\ReactiveUI.Fody.Helpers.Ios.csproj", "{377C39ED-0F7E-4522-A41E-96C5BA0C4FCB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReactiveUI.Fody.Helpers.Pcl", "ReactiveUI.Fody.Helpers.Pcl\ReactiveUI.Fody.Helpers.Pcl.csproj", "{8509509A-17C7-4CF0-84AD-5DD208446766}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{841EF03D-D23E-45CB-8BF5-362F32225C96}"
ProjectSection(SolutionItems) = preProject
.nuget\packages.config = .nuget\packages.config
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReactiveUI.Fody.Tests", "ReactiveUI.Fody.Tests\ReactiveUI.Fody.Tests.csproj", "{A735C110-6877-4C3A-8056-9ABC5FB2DD91}"
ProjectSection(ProjectDependencies) = postProject
{CCACB6C3-4C59-4372-85D1-CDDCE0D26989} = {CCACB6C3-4C59-4372-85D1-CDDCE0D26989}
EndProjectSection
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
ReactiveUI.Fody.Helpers\ReactiveUI.Fody.Helpers.projitems*{1ca52110-be45-4c45-b709-28061077e2a5}*SharedItemsImports = 4
ReactiveUI.Fody.Helpers\ReactiveUI.Fody.Helpers.projitems*{377c39ed-0f7e-4522-a41e-96c5ba0c4fcb}*SharedItemsImports = 4
ReactiveUI.Fody.Helpers\ReactiveUI.Fody.Helpers.projitems*{8509509a-17c7-4cf0-84ad-5dd208446766}*SharedItemsImports = 4
ReactiveUI.Fody.Helpers\ReactiveUI.Fody.Helpers.projitems*{4433ff2e-3150-4d7f-be18-a2258799b79d}*SharedItemsImports = 13
ReactiveUI.Fody.Helpers\ReactiveUI.Fody.Helpers.projitems*{6d2a6846-a8b7-4186-807d-12e335bd1c67}*SharedItemsImports = 4
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CCACB6C3-4C59-4372-85D1-CDDCE0D26989}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CCACB6C3-4C59-4372-85D1-CDDCE0D26989}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CCACB6C3-4C59-4372-85D1-CDDCE0D26989}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CCACB6C3-4C59-4372-85D1-CDDCE0D26989}.Release|Any CPU.Build.0 = Release|Any CPU
{1CA52110-BE45-4C45-B709-28061077E2A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1CA52110-BE45-4C45-B709-28061077E2A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1CA52110-BE45-4C45-B709-28061077E2A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1CA52110-BE45-4C45-B709-28061077E2A5}.Release|Any CPU.Build.0 = Release|Any CPU
{6D2A6846-A8B7-4186-807D-12E335BD1C67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6D2A6846-A8B7-4186-807D-12E335BD1C67}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6D2A6846-A8B7-4186-807D-12E335BD1C67}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6D2A6846-A8B7-4186-807D-12E335BD1C67}.Release|Any CPU.Build.0 = Release|Any CPU
{377C39ED-0F7E-4522-A41E-96C5BA0C4FCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{377C39ED-0F7E-4522-A41E-96C5BA0C4FCB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{377C39ED-0F7E-4522-A41E-96C5BA0C4FCB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{377C39ED-0F7E-4522-A41E-96C5BA0C4FCB}.Release|Any CPU.Build.0 = Release|Any CPU
{8509509A-17C7-4CF0-84AD-5DD208446766}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8509509A-17C7-4CF0-84AD-5DD208446766}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8509509A-17C7-4CF0-84AD-5DD208446766}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8509509A-17C7-4CF0-84AD-5DD208446766}.Release|Any CPU.Build.0 = Release|Any CPU
{A735C110-6877-4C3A-8056-9ABC5FB2DD91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A735C110-6877-4C3A-8056-9ABC5FB2DD91}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A735C110-6877-4C3A-8056-9ABC5FB2DD91}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A735C110-6877-4C3A-8056-9ABC5FB2DD91}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
================================================
FILE: Readme.md
================================================
# ReactiveUI.Fody
[![Windows Build Status]](https://ci.appveyor.com/project/KirkWoll/reactiveui-fody)
C# Fody extension to generate RaisePropertyChange notifications for properties and ObservableAsPropertyHelper properties.
## Install ##
Nuget package ReactiveUI.Fody:
> Install-Package ReactiveUI.Fody
Currently, you need to manually add `` to your Fody weavers configuration. If this is your first Fody plugin then `FodyWeavers.xml` should look like this after the change:
##Reactive Properties##
Eases the need for boilerplate in your view models when using [reactiveui](https://github.com/reactiveui/ReactiveUI). Typically, in your view models you must declare properties like this:
string _SearchId;
public string SearchId
{
get { return _SearchId; }
set { this.RaiseAndSetIfChanged(ref _SearchId, value); }
}
This is tedious since all you'd like to do is declare properties as normal:
[Reactive]public string SearchId { get; set; }
If a property is annotated with the `[Reactive]` attribute, the plugin will weave the boilerplate into your
output based on the simple auto-property declaration you provide.
##ObservableAsPropertyHelper Properties
Similarly, in order to handle observable property helper properties, you must declare them like this:
ObservableAsPropertyHelper _PersonInfo;
public string PersonInfo
{
get { return _PersonInfo.Value; }
}
Then elsewhere you'd set it up via:
...
.ToProperty(this, x => x.PersonInfo, out _PersonInfo);
This plugin will instead allow you to declare the property like:
public extern string PersonInfo { [ObservableAsProperty]get; }
It will generate the field and implement the property for you. Because there is no field for you to pass to
`.ToProperty`, you should use the `.ToPropertyEx` extension method provided by this library:
...
.ToPropertyEx(this, x => x.PersonInfo);
This extension will assign the auto-generated field for you rather than relying on the `out` parameter.
[Windows Build Status]: https://ci.appveyor.com/api/projects/status/github/kswoll/ReactiveUI.Fody?svg=true
================================================
FILE: Weavers/bin/_._
================================================
================================================
FILE: makepackage.bat
================================================
REM "C:\Program Files (x86)\MSBuild\14.0\Bin\msbuild.exe" ReactiveUIFody.sln
cd Nuget
..\packages\NugetUtilities.1.0.5\UpdateVersion.exe ReactiveUIFody.nuspec -Increment
mkdir build
cd build
copy ..\Nuget.exe .
copy ..\ReactiveUIFody.nuspec .
mkdir lib
mkdir lib\net45
mkdir lib\Xamarin.iOS10
mkdir lib\MonoAndroid
mkdir "lib\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10"
copy ..\..\ReactiveUI.Fody\bin\Debug\ReactiveUI.Fody.* .
REM copy ..\..\ReactiveUI.Fody.Helpers.Ios\bin\iPhone\Debug\ReactiveUI.Fody.Helpers.* lib\Xamarin.iOS10
copy ..\..\ReactiveUI.Fody.1.0.26\lib\Xamarin.iOS10\ReactiveUI.Fody.Helpers.* lib\Xamarin.iOS10
copy ..\..\ReactiveUI.Fody.Helpers.Net45\bin\Debug\ReactiveUI.Fody.Helpers.* lib\net45
copy ..\..\ReactiveUI.Fody.Helpers.Pcl\bin\Debug\ReactiveUI.Fody.Helpers.* "lib\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10"
REM copy ..\..\ReactiveUI.Fody.Helpers.Android\bin\Debug\ReactiveUI.Fody.Helpers.* lib\MonoAndroid
copy ..\..\ReactiveUI.Fody.1.0.26\lib\MonoAndroid\ReactiveUI.Fody.Helpers.* lib\MonoAndroid
nuget pack ReactiveUIFody.nuspec
copy *.nupkg ..
cd ..
rmdir build /S /Q
cd ..