Skip to content

Commit

Permalink
[All] Bindable span (xamarin#1850)
Browse files Browse the repository at this point in the history
* Bindable Text Property on Span

* Style applied to Span

* Added style property

* Unit tests added

* Minor fix and cleanup

* Cleanup of code after review

* Updated docs

* Set Parent and reduce calls to Text property

* OneTime Binding

* Allow OneTime Binding as a default

* Updated docs
  • Loading branch information
adamped authored and Jason Smith committed Mar 8, 2018
1 parent c7fd234 commit e42bd62
Show file tree
Hide file tree
Showing 21 changed files with 550 additions and 293 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ protected override void Build (StackLayout stackLayout)
#pragma warning restore 618

var formattedString = new FormattedString ();
formattedString.Spans.Add (new Span { BackgroundColor = Color.Red, ForegroundColor = Color.Olive, Text = "Span 1 " });
formattedString.Spans.Add (new Span { BackgroundColor = Color.Black, ForegroundColor = Color.White, Text = "Span 2 " });
formattedString.Spans.Add (new Span { BackgroundColor = Color.Pink, ForegroundColor = Color.Purple, Text = "Span 3" });
formattedString.Spans.Add (new Span { BackgroundColor = Color.Red, TextColor = Color.Olive, Text = "Span 1 " });
formattedString.Spans.Add (new Span { BackgroundColor = Color.Black, TextColor = Color.White, Text = "Span 2 " });
formattedString.Spans.Add (new Span { BackgroundColor = Color.Pink, TextColor = Color.Purple, Text = "Span 3" });

var formattedTextContainer = new ViewContainer<Label> (Test.Label.FormattedText, new Label { FormattedText = formattedString });

Expand Down
6 changes: 3 additions & 3 deletions Xamarin.Forms.Controls/GalleryPages/LabelGallery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ public LabelGallery ()
var formatted = new Label { FormattedText = new FormattedString {
Spans = {
#pragma warning disable 618
new Span {Text="FormattedStrings ", ForegroundColor=Color.Blue, BackgroundColor = Color.Yellow, Font = Font.BoldSystemFontOfSize (NamedSize.Large)},
new Span {Text="FormattedStrings ", TextColor=Color.Blue, BackgroundColor = Color.Yellow, Font = Font.BoldSystemFontOfSize (NamedSize.Large)},
#pragma warning restore 618
new Span {Text="are ", ForegroundColor=Color.Red, BackgroundColor = Color.Gray},
new Span {Text="not pretty!", ForegroundColor = Color.Green,},
new Span {Text="are ", TextColor=Color.Red, BackgroundColor = Color.Gray},
new Span {Text="not pretty!", TextColor = Color.Green,},
}
} };
var missingfont = new Label { Text = "Missing font: use default" };
Expand Down
86 changes: 86 additions & 0 deletions Xamarin.Forms.Core.UnitTests/SpanTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using NUnit.Framework;

namespace Xamarin.Forms.Core.UnitTests
{
[TestFixture]
public class SpanTests : BaseTestFixture
{
[SetUp]
public override void Setup()
{
base.Setup();
Device.PlatformServices = new MockPlatformServices();
}

[TearDown]
public override void TearDown()
{
base.TearDown();
Device.PlatformServices = null;
}

[Test]
public void StyleApplied()
{
var pinkStyle = new Style(typeof(Span))
{
Setters = {
new Setter { Property = Span.TextColorProperty, Value = Color.Pink },
},
Class = "pink",
ApplyToDerivedTypes = true,
};

var span = new Span
{
Style = pinkStyle
};

var formattedText = new FormattedString();
formattedText.Spans.Add(span);

var label = new Label()
{
FormattedText = formattedText
};

new ContentView
{
Resources = new ResourceDictionary { pinkStyle },
Content = label
};

Assert.AreEqual(Color.Pink, span.TextColor);
}

[Test]
public void BindingApplied()
{
var vm = new ViewModel()
{
Text = "CheckBindingWorked"
};

var formattedText = new FormattedString();

var label = new Label()
{
FormattedText = formattedText
};

var span = new Span();
span.SetBinding(Span.TextProperty, "Text");

formattedText.Spans.Add(span);

label.BindingContext = vm;

Assert.AreEqual(vm.Text, span.Text);
}

class ViewModel
{
public string Text { get; set; }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
<Compile Include="FlowDirectionTests.cs" />
<Compile Include="LayoutChildIntoBoundingRegionTests.cs" />
<Compile Include="MenuUnitTests.cs" />
<Compile Include="SpanTests.cs" />
<Compile Include="TemplatedViewUnitTests.cs" />
<Compile Include="TemplatedPageUnitTests.cs" />
<Compile Include="ContentFormUnitTests.cs" />
Expand Down Expand Up @@ -226,5 +227,4 @@
<LogicalName>Images/crimson.jpg</LogicalName>
</EmbeddedResource>
</ItemGroup>
<ItemGroup />
</Project>
2 changes: 1 addition & 1 deletion Xamarin.Forms.Core/BindableProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public sealed class BindableProperty
throw new ArgumentNullException("declaringType");

// don't use Enum.IsDefined as its redonkulously expensive for what it does
if (defaultBindingMode != BindingMode.Default && defaultBindingMode != BindingMode.OneWay && defaultBindingMode != BindingMode.OneWayToSource && defaultBindingMode != BindingMode.TwoWay)
if (defaultBindingMode != BindingMode.Default && defaultBindingMode != BindingMode.OneWay && defaultBindingMode != BindingMode.OneWayToSource && defaultBindingMode != BindingMode.TwoWay && defaultBindingMode != BindingMode.OneTime)
throw new ArgumentException("Not a valid type of BindingMode", "defaultBindingMode");
if (defaultValue == null && Nullable.GetUnderlyingType(returnType) == null && returnType.GetTypeInfo().IsValueType)
throw new ArgumentException("Not a valid default value", "defaultValue");
Expand Down
19 changes: 11 additions & 8 deletions Xamarin.Forms.Core/FormattedString.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;

namespace Xamarin.Forms
{
[ContentProperty("Spans")]
public class FormattedString : INotifyPropertyChanged
public class FormattedString : Element
{
readonly SpanCollection _spans = new SpanCollection();

Expand All @@ -18,13 +17,18 @@ public FormattedString()
_spans.CollectionChanged += OnCollectionChanged;
}

protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
for (int i = 0; i < Spans.Count; i++)
SetInheritedBindingContext(Spans[i], BindingContext);
}

public IList<Span> Spans
{
get { return _spans; }
}

public event PropertyChangedEventHandler PropertyChanged;


public static explicit operator string(FormattedString formatted)
{
return formatted.ToString();
Expand All @@ -47,6 +51,7 @@ void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
foreach (object item in e.OldItems)
{
var bo = item as Span;
bo.Parent = null;
if (bo != null)
bo.PropertyChanged -= OnItemPropertyChanged;
}
Expand All @@ -57,6 +62,7 @@ void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
foreach (object item in e.NewItems)
{
var bo = item as Span;
bo.Parent = this;
if (bo != null)
bo.PropertyChanged += OnItemPropertyChanged;
}
Expand All @@ -70,9 +76,6 @@ void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
OnPropertyChanged("Spans");
}

void OnPropertyChanged([CallerMemberName] string propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

class SpanCollection : ObservableCollection<Span>
{
protected override void InsertItem(int index, Span item)
Expand Down
26 changes: 21 additions & 5 deletions Xamarin.Forms.Core/Label.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,29 +24,38 @@ public class Label : View, IFontElement, ITextElement, ITextAlignmentElement, IE

public static readonly BindableProperty FontProperty = FontElement.FontProperty;

public static readonly BindableProperty TextProperty = BindableProperty.Create("Text", typeof(string), typeof(Label), default(string), propertyChanged: OnTextPropertyChanged);
public static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(Label), default(string), propertyChanged: OnTextPropertyChanged);

public static readonly BindableProperty FontFamilyProperty = FontElement.FontFamilyProperty;

public static readonly BindableProperty FontSizeProperty = FontElement.FontSizeProperty;

public static readonly BindableProperty FontAttributesProperty = FontElement.FontAttributesProperty;

public static readonly BindableProperty FormattedTextProperty = BindableProperty.Create("FormattedText", typeof(FormattedString), typeof(Label), default(FormattedString),
public static readonly BindableProperty FormattedTextProperty = BindableProperty.Create(nameof(FormattedText), typeof(FormattedString), typeof(Label), default(FormattedString),
propertyChanging: (bindable, oldvalue, newvalue) =>
{
if (oldvalue != null)
((FormattedString)oldvalue).PropertyChanged -= ((Label)bindable).OnFormattedTextChanged;
{
var formattedString = ((FormattedString)oldvalue);
formattedString.PropertyChanged -= ((Label)bindable).OnFormattedTextChanged;
formattedString.Parent = null;
}
}, propertyChanged: (bindable, oldvalue, newvalue) =>
{
if (newvalue != null)
((FormattedString)newvalue).PropertyChanged += ((Label)bindable).OnFormattedTextChanged;
{
var formattedString = (FormattedString)newvalue;
formattedString.PropertyChanged += ((Label)bindable).OnFormattedTextChanged;
formattedString.Parent = (Label)bindable;
}

((Label)bindable).InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
if (newvalue != null)
((Label)bindable).Text = null;
});

public static readonly BindableProperty LineBreakModeProperty = BindableProperty.Create("LineBreakMode", typeof(LineBreakMode), typeof(Label), LineBreakMode.WordWrap,
public static readonly BindableProperty LineBreakModeProperty = BindableProperty.Create(nameof(LineBreakMode), typeof(LineBreakMode), typeof(Label), LineBreakMode.WordWrap,
propertyChanged: (bindable, oldvalue, newvalue) => ((Label)bindable).InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged));

readonly Lazy<PlatformConfigurationRegistry<Label>> _platformConfigurationRegistry;
Expand All @@ -56,6 +65,13 @@ public Label()
_platformConfigurationRegistry = new Lazy<PlatformConfigurationRegistry<Label>>(() => new PlatformConfigurationRegistry<Label>(this));
}

protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
if (FormattedText != null)
SetInheritedBindingContext(FormattedText, this.BindingContext);
}

[Obsolete("Font is obsolete as of version 1.3.0. Please use the Font attributes which are on the class itself.")]
public Font Font
{
Expand Down
Loading

0 comments on commit e42bd62

Please sign in to comment.