Skip to content

Commit

Permalink
Binding changes - to allow [] properties
Browse files Browse the repository at this point in the history
  • Loading branch information
slodge committed Jan 18, 2013
1 parent 2342433 commit 16bc44c
Show file tree
Hide file tree
Showing 25 changed files with 653 additions and 45 deletions.
Expand Up @@ -8,6 +8,7 @@
using System;
using System.Linq.Expressions;
using System.Reflection;
using Cirrious.MvvmCross.Binding.Interfaces;
using Cirrious.MvvmCross.Exceptions;
using Cirrious.MvvmCross.ExtensionMethods;
using Cirrious.MvvmCross.Interfaces.Platform.Diagnostics;
Expand All @@ -21,7 +22,7 @@ public static class ExpressionExtensions
public static string CreateBindingText<T>(this Expression<Func<T, object>> bindingExpression, string converter,
string converterParameter)
{
var binding = new Cirrious.MvvmCross.Binding.Binders.Json.MvxSerializableBindingDescription
var binding = new MvxSerializableBindingDescription
{
Path = bindingExpression.GetPropertyText(),
Converter = converter,
Expand All @@ -40,7 +41,7 @@ public static class ExpressionExtensions

public static string CreateBindingText(this string path, string converter, string converterParameter)
{
var binding = new Cirrious.MvvmCross.Binding.Binders.Json.MvxSerializableBindingDescription
var binding = new MvxSerializableBindingDescription
{
Path = path,
Converter = converter,
Expand Down
Expand Up @@ -6,6 +6,7 @@
// Project Lead - Stuart Lodge, @slodge, me@slodge.com

using System;
using Cirrious.MvvmCross.Binding.Interfaces;
using Cirrious.MvvmCross.ExtensionMethods;
using Cirrious.MvvmCross.Interfaces.Platform.Diagnostics;
using Cirrious.MvvmCross.Interfaces.ServiceProvider;
Expand Down
Expand Up @@ -6,6 +6,7 @@
// Project Lead - Stuart Lodge, @slodge, me@slodge.com

using System.Collections.Generic;
using Cirrious.MvvmCross.Binding.Interfaces;

namespace Cirrious.MvvmCross.Binding.Binders.Json
{
Expand Down
3 changes: 3 additions & 0 deletions Cirrious/Cirrious.MvvmCross.Binding/Binders/MvxFullBinding.cs
Expand Up @@ -160,6 +160,8 @@ private void CreateTargetBinding(object target)
}
}

#warning where did this method come from - R# says not used so commented it out
/*
private static void UpdateSourceFromTarget(MvxBindingRequest bindingRequest, IMvxSourceBinding sourceBinding,
object value)
{
Expand All @@ -182,6 +184,7 @@ private void CreateTargetBinding(object target)
exception.ToLongString());
}
}
*/

protected bool NeedToObserveSourceChanges
{
Expand Down
Expand Up @@ -7,31 +7,29 @@

using System;
using System.Collections.Generic;
using System.Linq;
using Cirrious.MvvmCross.Binding.Bindings.Source.Construction.PropertyTokens;
using Cirrious.MvvmCross.Binding.Interfaces.Bindings.Source;
using Cirrious.MvvmCross.Binding.Interfaces.Bindings.Source.Construction;
using Cirrious.MvvmCross.ExtensionMethods;
using Cirrious.MvvmCross.Interfaces.Platform.Diagnostics;
using Cirrious.MvvmCross.Interfaces.ServiceProvider;

namespace Cirrious.MvvmCross.Binding.Bindings.Source
namespace Cirrious.MvvmCross.Binding.Bindings.Source.Chained
{
public class MvxChainedSourceBinding
public abstract class MvxChainedSourceBinding
: MvxBasePropertyInfoSourceBinding
, IMvxServiceConsumer<IMvxSourceBindingFactory>
{
private readonly List<string> _childPropertyNames;
private readonly IList<MvxBasePropertyToken> _childTokens;
private IMvxSourceBinding _currentChildBinding;

public MvxChainedSourceBinding(
protected MvxChainedSourceBinding(
object source,
string propertyName,
IEnumerable<string> childPropertyNames)
IList<MvxBasePropertyToken> childTokens)
: base(source, propertyName)
{
_childPropertyNames = childPropertyNames.ToList();

UpdateChildBinding();
_childTokens = childTokens;
}

protected override void Dispose(bool isDisposing)
Expand All @@ -58,7 +56,7 @@ public override Type SourceType
get { throw new NotImplementedException(); }
}

private void UpdateChildBinding()
protected void UpdateChildBinding()
{
if (_currentChildBinding != null)
{
Expand All @@ -72,19 +70,21 @@ private void UpdateChildBinding()
return;
}

var currentValue = PropertyInfo.GetValue(Source, null);
var currentValue = PropertyInfo.GetValue(Source, PropertyIndexParameters());
if (currentValue == null)
{
// value will be missing... so end consumer will need to use fallback values
return;
}
else
{
_currentChildBinding = SourceBindingFactory.CreateBinding(currentValue, _childPropertyNames);
_currentChildBinding = SourceBindingFactory.CreateBinding(currentValue, _childTokens);
_currentChildBinding.Changed += ChildSourceBindingChanged;
}
}

protected abstract object[] PropertyIndexParameters();

private void ChildSourceBindingChanged(object sender, MvxSourcePropertyBindingEventArgs e)
{
FireChanged(e);
Expand Down
@@ -0,0 +1,31 @@
// MvxIndexerChainedSourceBinding.cs
// (c) Copyright Cirrious Ltd. http://www.cirrious.com
// MvvmCross is licensed using Microsoft Public License (Ms-PL)
// Contributions and inspirations noted in readme.md and license.txt
//
// Project Lead - Stuart Lodge, @slodge, me@slodge.com

using System.Collections.Generic;
using Cirrious.MvvmCross.Binding.Bindings.Source.Construction.PropertyTokens;

namespace Cirrious.MvvmCross.Binding.Bindings.Source.Chained
{
public class MvxIndexerChainedSourceBinding
: MvxChainedSourceBinding
{
private readonly MvxIndexerPropertyToken _indexerPropertyToken;

public MvxIndexerChainedSourceBinding(object source, MvxIndexerPropertyToken indexerPropertyToken,
IList<MvxBasePropertyToken> childTokens)
: base(source, "Item", childTokens)
{
_indexerPropertyToken = indexerPropertyToken;
UpdateChildBinding();
}

protected override object[] PropertyIndexParameters()
{
return new[] {_indexerPropertyToken.Key};
}
}
}
@@ -0,0 +1,32 @@
// MvxSimpleChainedSourceBinding.cs
// (c) Copyright Cirrious Ltd. http://www.cirrious.com
// MvvmCross is licensed using Microsoft Public License (Ms-PL)
// Contributions and inspirations noted in readme.md and license.txt
//
// Project Lead - Stuart Lodge, @slodge, me@slodge.com

using System.Collections.Generic;
using Cirrious.MvvmCross.Binding.Bindings.Source.Construction.PropertyTokens;

namespace Cirrious.MvvmCross.Binding.Bindings.Source.Chained
{
public class MvxSimpleChainedSourceBinding
: MvxChainedSourceBinding
{
private readonly MvxPropertyNamePropertyToken _propertyNamePropertyToken;

public MvxSimpleChainedSourceBinding(
object source,
MvxPropertyNamePropertyToken propertyNamePropertyToken,
IList<MvxBasePropertyToken> childTokens)
: base(source, propertyNamePropertyToken.PropertyName, childTokens)
{
_propertyNamePropertyToken = propertyNamePropertyToken;
}

protected override object[] PropertyIndexParameters()
{
return null;
}
}
}
Expand Up @@ -5,17 +5,38 @@
//
// Project Lead - Stuart Lodge, @slodge, me@slodge.com

using System;
using System.Collections.Generic;
using System.Linq;
using Cirrious.MvvmCross.Binding.Bindings.Source.Chained;
using Cirrious.MvvmCross.Binding.Bindings.Source.Construction.PropertyTokens;
using Cirrious.MvvmCross.Binding.Bindings.Source.Leaf;
using Cirrious.MvvmCross.Binding.Interfaces.Bindings.Source;
using Cirrious.MvvmCross.Binding.Interfaces.Bindings.Source.Construction;
using Cirrious.MvvmCross.Exceptions;
using Cirrious.MvvmCross.ExtensionMethods;
using Cirrious.MvvmCross.Interfaces.ServiceProvider;

namespace Cirrious.MvvmCross.Binding.Bindings.Source.Construction
{
public class MvxSourceBindingFactory : IMvxSourceBindingFactory
public class MvxSourceBindingFactory
: IMvxSourceBindingFactory
, IMvxServiceConsumer
{
private static readonly char[] FieldSeparator = new[] {'.'};
private static readonly char[] FieldSeparator = new[] {'.', '['};

private IMvxPropertyTokeniser _propertyTokeniser;

private IMvxPropertyTokeniser PropertyTokeniser
{
get
{
if (_propertyTokeniser == null)
{
_propertyTokeniser = this.GetService<IMvxPropertyTokeniser>();
}
return _propertyTokeniser;
}
}

#region IMvxSourceBindingFactory Members

Expand All @@ -24,26 +45,65 @@ public IMvxSourceBinding CreateBinding(object source, string combinedPropertyNam
if (combinedPropertyName == null)
combinedPropertyName = "";

return CreateBinding(source,
combinedPropertyName.Split(FieldSeparator, StringSplitOptions.RemoveEmptyEntries));
var tokens = PropertyTokeniser.Tokenise(combinedPropertyName);
var queue = new List<MvxBasePropertyToken>(tokens);
return CreateBinding(source, queue);
}

#warning CreateBinding should probably take an IList to make the code run quicker!
public IMvxSourceBinding CreateBinding(object source, IList<MvxBasePropertyToken> tokens)
{
if (tokens == null || tokens.Count == 0)
{
throw new MvxException("empty token list passed to CreateBinding");
}

var currentToken = tokens[0];
if (tokens.Count == 1)
{
return CreateLeafBinding(source, currentToken);
}
else
{
var remainingTokens = tokens.Skip(1).ToList();
return CreateChainedBinding(source, currentToken, remainingTokens);
}
}

public IMvxSourceBinding CreateBinding(object source, IEnumerable<string> childPropertyNames)
private static MvxChainedSourceBinding CreateChainedBinding(object source, MvxBasePropertyToken propertyToken,
List<MvxBasePropertyToken> remainingTokens)
{
var childPropertyNameList = childPropertyNames.ToList();
if (propertyToken is MvxIndexerPropertyToken)
{
return new MvxIndexerChainedSourceBinding(source, (MvxIndexerPropertyToken) propertyToken,
remainingTokens);
}
else if (propertyToken is MvxPropertyNamePropertyToken)
{
return new MvxSimpleChainedSourceBinding(source, (MvxPropertyNamePropertyToken) propertyToken,
remainingTokens);
}

throw new MvxException("Unexpected property chaining - seen token type {0}",
propertyToken.GetType().FullName);
}

switch (childPropertyNameList.Count)
private static IMvxSourceBinding CreateLeafBinding(object source, MvxBasePropertyToken propertyToken)
{
if (propertyToken is MvxIndexerPropertyToken)
{
return new MvxIndexerLeafPropertyInfoSourceBinding(source, (MvxIndexerPropertyToken) propertyToken);
}
else if (propertyToken is MvxPropertyNamePropertyToken)
{
case 0:
return new MvxDirectToSourceBinding(source);
case 1:
return new MvxPropertyInfoSourceBinding(source,
childPropertyNameList.DefaultIfEmpty(string.Empty)
.FirstOrDefault());
default:
return new MvxChainedSourceBinding(source, childPropertyNameList.First(),
childPropertyNameList.Skip(1));
return new MvxSimpleLeafPropertyInfoSourceBinding(source, (MvxPropertyNamePropertyToken) propertyToken);
}
else if (propertyToken is MvxEmptyPropertyToken)
{
return new MvxDirectToSourceBinding(source);
}

throw new MvxException("Unexpected property source - seen token type {0}", propertyToken.GetType().FullName);
}

#endregion
Expand Down
@@ -0,0 +1,16 @@
// IMvxPropertyTokeniser.cs
// (c) Copyright Cirrious Ltd. http://www.cirrious.com
// MvvmCross is licensed using Microsoft Public License (Ms-PL)
// Contributions and inspirations noted in readme.md and license.txt
//
// Project Lead - Stuart Lodge, @slodge, me@slodge.com

using System.Collections.Generic;

namespace Cirrious.MvvmCross.Binding.Bindings.Source.Construction.PropertyTokens
{
public interface IMvxPropertyTokeniser
{
IList<MvxBasePropertyToken> Tokenise(string toParse);
}
}
@@ -0,0 +1,13 @@
// MvxBasePropertyToken.cs
// (c) Copyright Cirrious Ltd. http://www.cirrious.com
// MvvmCross is licensed using Microsoft Public License (Ms-PL)
// Contributions and inspirations noted in readme.md and license.txt
//
// Project Lead - Stuart Lodge, @slodge, me@slodge.com

namespace Cirrious.MvvmCross.Binding.Bindings.Source.Construction.PropertyTokens
{
public class MvxBasePropertyToken
{
}
}
@@ -0,0 +1,13 @@
// MvxEmptyPropertyToken.cs
// (c) Copyright Cirrious Ltd. http://www.cirrious.com
// MvvmCross is licensed using Microsoft Public License (Ms-PL)
// Contributions and inspirations noted in readme.md and license.txt
//
// Project Lead - Stuart Lodge, @slodge, me@slodge.com

namespace Cirrious.MvvmCross.Binding.Bindings.Source.Construction.PropertyTokens
{
public class MvxEmptyPropertyToken : MvxBasePropertyToken
{
}
}

0 comments on commit 16bc44c

Please sign in to comment.