Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Binding SG] Dogfood binding source generator in the MAUI codebase #23393

Original file line number Diff line number Diff line change
Expand Up @@ -738,7 +738,7 @@ Cell GetNewGroupHeaderCell(ITemplatedItemsList<Cell> group)
groupHeaderCell = new TextCell();
groupHeaderCell.SetBinding(
TextCell.TextProperty,
TypedBinding.ForSingleNestingLevel(nameof(group.Name), static (ITemplatedItemsList<Cell> g) => g.Name));
static (ITemplatedItemsList<Cell> g) => g.Name);
groupHeaderCell.BindingContext = group;
}

Expand Down
10 changes: 10 additions & 0 deletions src/Compatibility/Core/src/Compatibility.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,16 @@
<ItemGroup Condition="$(TargetFramework.Contains('-windows')) == true ">
</ItemGroup>

<PropertyGroup>
<InterceptorsPreviewNamespaces>$(InterceptorsPreviewNamespaces);Microsoft.Maui.Controls.Generated</InterceptorsPreviewNamespaces>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, if an interceptor is declared outside of a namespace listed here, it will get a C# compiler error.

It sounds like they will rename this to $(InterceptorsNamespaces) one day:

No problem here, just fyi for later.

</PropertyGroup>
<ItemGroup>
<ProjectReference
Include="..\..\..\Controls\src\BindingSourceGen\Controls.BindingSourceGen.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetPlatformIdentifier)' == 'android' ">
<AndroidResource Include="$(AndroidRoot)Resources\layout\Tabbar.axml" />
<AndroidResource Include="$(AndroidRoot)Resources\layout\Toolbar.axml" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -763,9 +763,7 @@ Cell GetNewGroupHeaderCell(ITemplatedItemsList<Cell> group)
else
{
groupHeaderCell = new TextCell();
groupHeaderCell.SetBinding(
TextCell.TextProperty,
TypedBinding.ForSingleNestingLevel(nameof(group.Name), static (ITemplatedItemsList<Cell> g) => g.Name));
groupHeaderCell.SetBinding(TextCell.TextProperty, static (ITemplatedItemsList<Cell> g) => g.Name);
groupHeaderCell.BindingContext = group;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ static View CreateContent(SectionCell sectionCell)
#pragma warning restore CS0612 // Type or member is obsolete
};

text.SetBinding(Label.TextProperty, TypedBinding.ForSingleNestingLevel("Text", static (SectionCell cell) => cell.Text, source: sectionCell));
text.SetBinding(Label.TextColorProperty, TypedBinding.ForSingleNestingLevel("TextColor", static (SectionCell cell) => cell.TextColor, source: sectionCell));
text.SetBinding(Label.TextProperty, static (SectionCell cell) => cell.Text, source: sectionCell);
text.SetBinding(Label.TextColorProperty, static (SectionCell cell) => cell.TextColor, source: sectionCell);

var layout = new Controls.StackLayout
{
Expand All @@ -93,15 +93,15 @@ static View CreateContent(SectionCell sectionCell)
static View CreateContent(TextCell textcell)
{
var text = new Label();
text.SetBinding(Label.TextProperty, TypedBinding.ForSingleNestingLevel("Text", static (TextCell cell) => cell.Text, source: textcell));
text.SetBinding(Label.TextColorProperty, TypedBinding.ForSingleNestingLevel("TextColor", static (TextCell cell) => cell.TextColor, source: textcell));
text.SetBinding(Label.TextProperty, static (TextCell cell) => cell.Text, source: textcell);
text.SetBinding(Label.TextColorProperty, static (TextCell cell) => cell.TextColor, source: textcell);
#pragma warning disable CS0612 // Type or member is obsolete
text.FontSize = Device.GetNamedSize(NamedSize.Default, typeof(Label));
#pragma warning restore CS0612 // Type or member is obsolete

var detail = new Label();
detail.SetBinding(Label.TextProperty, TypedBinding.ForSingleNestingLevel("Detail", static (TextCell cell) => cell.Detail, source: textcell));
detail.SetBinding(Label.TextColorProperty, TypedBinding.ForSingleNestingLevel("DetailColor", static (TextCell cell) => cell.DetailColor, source: textcell));
detail.SetBinding(Label.TextProperty, static (TextCell cell) => cell.Detail, source: textcell);
detail.SetBinding(Label.TextColorProperty, static (TextCell cell) => cell.DetailColor, source: textcell);
#pragma warning disable CS0612 // Type or member is obsolete
detail.FontSize = Device.GetNamedSize(NamedSize.Micro, typeof(Label));
#pragma warning restore CS0612 // Type or member is obsolete
Expand Down Expand Up @@ -139,7 +139,7 @@ static View CreateContent(ImageCell imageCell)
{
Aspect = Aspect.AspectFit,
};
img.SetBinding(Image.SourceProperty, TypedBinding.ForSingleNestingLevel("ImageSource", static (ImageCell cell) => cell.ImageSource, source: imageCell));
img.SetBinding(Image.SourceProperty, static (ImageCell cell) => cell.ImageSource, source: imageCell);
layout.Add(img, 0, 0);
layout.Add(textcell, 1, 0);
return layout;
Expand All @@ -148,20 +148,15 @@ static View CreateContent(ImageCell imageCell)
static View CreateContent(EntryCell entryCell)
{
var entry = new Entry();
entry.SetBinding(Entry.TextProperty,
TypedBinding.ForSingleNestingLevel("Text",
static (EntryCell cell) => cell.Text,
static (cell, value) => cell.Text = value,
mode: BindingMode.TwoWay,
source: entryCell));
entry.SetBinding(Entry.PlaceholderProperty, TypedBinding.ForSingleNestingLevel("Placeholder", static (EntryCell cell) => cell.Placeholder, source: entryCell));
entry.SetBinding(InputView.KeyboardProperty, TypedBinding.ForSingleNestingLevel("Keyboard", static (EntryCell cell) => cell.Keyboard, source: entryCell));
entry.SetBinding(Entry.HorizontalTextAlignmentProperty, TypedBinding.ForSingleNestingLevel("HorizontalTextAlignment", static (EntryCell cell) => cell.HorizontalTextAlignment, source: entryCell));
entry.SetBinding(Entry.VerticalTextAlignmentProperty, TypedBinding.ForSingleNestingLevel("VerticalTextAlignment", static (EntryCell cell) => cell.VerticalTextAlignment, source: entryCell));
entry.SetBinding(Entry.TextProperty, static (EntryCell cell) => cell.Text, mode: BindingMode.TwoWay, source: entryCell);
entry.SetBinding(Entry.PlaceholderProperty, static (EntryCell cell) => cell.Placeholder, source: entryCell);
entry.SetBinding(InputView.KeyboardProperty, static (EntryCell cell) => cell.Keyboard, source: entryCell);
entry.SetBinding(Entry.HorizontalTextAlignmentProperty, static (EntryCell cell) => cell.HorizontalTextAlignment, source: entryCell);
entry.SetBinding(Entry.VerticalTextAlignmentProperty, static (EntryCell cell) => cell.VerticalTextAlignment, source: entryCell);

var label = new Label();
label.SetBinding(Label.TextProperty, TypedBinding.ForSingleNestingLevel("Label", static (EntryCell cell) => cell.Label, source: entryCell));
label.SetBinding(Label.TextColorProperty, TypedBinding.ForSingleNestingLevel("LabelColor", static (EntryCell cell) => cell.LabelColor, source: entryCell));
label.SetBinding(Label.TextProperty, static (EntryCell cell) => cell.Label, source: entryCell);
label.SetBinding(Label.TextColorProperty, static (EntryCell cell) => cell.LabelColor, source: entryCell);
#pragma warning disable CS0612 // Type or member is obsolete
label.FontSize = Device.GetNamedSize(NamedSize.Micro, typeof(Label));
#pragma warning restore CS0612 // Type or member is obsolete
Expand All @@ -188,19 +183,14 @@ static View CreateContent(SwitchCell switchCell)
HorizontalOptions = LayoutOptions.StartAndExpand,
};
#pragma warning restore CS0618
text.SetBinding(Label.TextProperty, TypedBinding.ForSingleNestingLevel("Text", static (SwitchCell cell) => cell.Text, source: switchCell));
text.SetBinding(Label.TextProperty, static (SwitchCell cell) => cell.Text, source: switchCell);

var sw = new Switch
{
HorizontalOptions = LayoutOptions.End
};
sw.SetBinding(Switch.IsToggledProperty,
TypedBinding.ForSingleNestingLevel("On",
static (SwitchCell cell) => cell.On,
static (cell, value) => cell.On = value,
mode: BindingMode.TwoWay,
source: switchCell));
sw.SetBinding(Switch.OnColorProperty, TypedBinding.ForSingleNestingLevel("OnColor", static (SwitchCell cell) => cell.OnColor, source: switchCell));
sw.SetBinding(Switch.IsToggledProperty, static (SwitchCell cell) => cell.On, mode: BindingMode.TwoWay, source: switchCell);
sw.SetBinding(Switch.OnColorProperty, static (SwitchCell cell) => cell.OnColor, source: switchCell);

var layout = new Controls.StackLayout
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ protected void UpdateAdaptor(bool initialize)
template = new CellWrapperTemplate(new DataTemplate(() =>
{
var label = new TextCell();
label.SetBinding(TextCell.TextProperty, TypedBinding.ForSingleNestingLevel(string.Empty, static (object source) => source));
label.SetBinding(TextCell.TextProperty, static (object source) => source);
return label;
}), Element);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ DataTemplate DefaultTemplate
}
#pragma warning restore CS0618

label.SetBinding(Label.TextProperty, TypedBinding.ForSingleNestingLevel(string.Empty, static (object o) => o));
label.SetBinding(Label.TextProperty, static (object o) => o);
}

label.HorizontalTextAlignment = TextAlignment.Center;
Expand Down
48 changes: 31 additions & 17 deletions src/Controls/src/Core/ContentConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,31 +66,45 @@ static Label ConvertToLabel(string textContent, ContentPresenter presenter)

static void BindTextProperties(BindableObject content)
{
BindProperty(content, TextElement.TextColorProperty, static (ITextElement te) => te.TextColor);
BindProperty(content, TextElement.CharacterSpacingProperty, static (ITextElement te) => te.CharacterSpacing);
BindProperty(content, TextElement.TextTransformProperty, static (ITextElement te) => te.TextTransform);
var source = new RelativeBindingSource(RelativeBindingSourceMode.FindAncestor, typeof(ITextElement));
if (ShouldSetBinding(content, TextElement.TextColorProperty))
{
content.SetBinding(TextElement.TextColorProperty, static (ITextElement te) => te.TextColor, source: source);
}

if (ShouldSetBinding(content, TextElement.CharacterSpacingProperty))
{
content.SetBinding(TextElement.CharacterSpacingProperty, static (ITextElement te) => te.CharacterSpacing, source: source);
}

if (ShouldSetBinding(content, TextElement.TextTransformProperty))
{
content.SetBinding(TextElement.TextTransformProperty, static (ITextElement te) => te.TextTransform, source: source);
}
}

static void BindFontProperties(BindableObject content)
{
BindProperty(content, FontElement.FontAttributesProperty, static (IFontElement fe) => fe.FontAttributes);
BindProperty(content, FontElement.FontSizeProperty, static (IFontElement fe) => fe.FontSize);
BindProperty(content, FontElement.FontFamilyProperty, static (IFontElement fe) => fe.FontFamily);
}
var source = new RelativeBindingSource(RelativeBindingSourceMode.FindAncestor, typeof(IFontElement));
if (ShouldSetBinding(content, FontElement.FontAttributesProperty))
{
content.SetBinding(FontElement.FontAttributesProperty, static (IFontElement fe) => fe.FontAttributes, source: source);
}

static void BindProperty<TSource, TProperty>(
BindableObject content,
BindableProperty property,
Func<TSource, TProperty> getter)
{
if (content.IsSet(property) || content.GetIsBound(property))
if (ShouldSetBinding(content, FontElement.FontSizeProperty))
{
// Don't override the property if user has already set it
return;
content.SetBinding(FontElement.FontSizeProperty, static (IFontElement fe) => fe.FontSize, source: source);
}

content.SetBinding(property, TypedBinding.ForSingleNestingLevel(
property.PropertyName, getter, source: new RelativeBindingSource(RelativeBindingSourceMode.FindAncestor, typeof(TSource))));
if (ShouldSetBinding(content, FontElement.FontFamilyProperty))
{
content.SetBinding(FontElement.FontFamilyProperty, static (IFontElement fe) => fe.FontFamily, source: source);
}
}

static bool ShouldSetBinding(BindableObject content, BindableProperty property)
{
return !content.IsSet(property) && !content.GetIsBound(property);
}

static bool HasTemplateAncestor(ContentPresenter presenter, Type type)
Expand Down
12 changes: 5 additions & 7 deletions src/Controls/src/Core/ContentPresenter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,12 @@ public class ContentPresenter : Compatibility.Layout, IContentView
/// <include file="../../docs/Microsoft.Maui.Controls/ContentPresenter.xml" path="//Member[@MemberName='.ctor']/Docs/*" />
public ContentPresenter()
{
SetBinding(
this.SetBinding(
ContentProperty,
TypedBinding.ForSingleNestingLevel(
nameof(IContentView.Content),
static (IContentView view) => view.Content,
source: RelativeBindingSource.TemplatedParent,
converter: new ContentConverter(),
converterParameter: this));
static (IContentView view) => view.Content,
source: RelativeBindingSource.TemplatedParent,
converter: new ContentConverter(),
converterParameter: this);
}

/// <include file="../../docs/Microsoft.Maui.Controls/ContentPresenter.xml" path="//Member[@MemberName='Content']/Docs/*" />
Expand Down
10 changes: 10 additions & 0 deletions src/Controls/src/Core/Controls.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@
<ProjectReference Include="..\..\..\Controls\src\Core.Design\Controls.Core.Design.csproj" ReferenceOutputAssembly="false" />
</ItemGroup>

<PropertyGroup>
<InterceptorsPreviewNamespaces>$(InterceptorsPreviewNamespaces);Microsoft.Maui.Controls.Generated</InterceptorsPreviewNamespaces>
</PropertyGroup>
<ItemGroup>
<ProjectReference
Include="..\..\..\Controls\src\BindingSourceGen\Controls.BindingSourceGen.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ static View CreateView()
{
TextColor = Colors.Black,
};
label.SetBinding(XLabel.TextProperty, TypedBinding.ForSingleNestingLevel(string.Empty, static (object source) => source, converter: new ToTextConverter()));
label.SetBinding(XLabel.TextProperty, static (object source) => source, converter: new ToTextConverter());

return new Controls.StackLayout
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ public override NView CreateNativeView(int index)
var nativeView = base.CreateNativeView(index);

var view = GetTemplatedView(nativeView);
view?.SetBinding(ShellContentItemView.SelectedTextColorProperty, TypedBinding.ForSingleNestingLevel("TitleColor", static (ItemAppearance appearance) => appearance.TitleColor, source: _itemAppearance));
view?.SetBinding(ShellContentItemView.SelectedBarColorProperty, TypedBinding.ForSingleNestingLevel("ForegroundColor", static (ItemAppearance appearance) => appearance.ForegroundColor, source: _itemAppearance));
view?.SetBinding(ShellContentItemView.UnselectedColorProperty, TypedBinding.ForSingleNestingLevel("UnselectedColor", static (ItemAppearance appearance) => appearance.UnselectedColor, source: _itemAppearance));
view?.SetBinding(ShellContentItemView.SelectedTextColorProperty, static (ItemAppearance appearance) => appearance.TitleColor, source: _itemAppearance);
view?.SetBinding(ShellContentItemView.SelectedBarColorProperty, static (ItemAppearance appearance) => appearance.ForegroundColor, source: _itemAppearance);
view?.SetBinding(ShellContentItemView.UnselectedColorProperty, static (ItemAppearance appearance) => appearance.UnselectedColor, source: _itemAppearance);

return nativeView;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ void InitializeComponent()
HorizontalTextAlignment = TextAlignment.Center,
VerticalTextAlignment = TextAlignment.Center,
};
_label.SetBinding(Label.TextProperty, TypedBinding.ForSingleNestingLevel("Title", static (BaseShellItem item) => item.Title));
_label.SetBinding(Label.TextProperty, static (BaseShellItem item) => item.Title);

_bar = new BoxView
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,15 @@ void InitializeComponent()
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center,
};
icon.SetBinding(Image.SourceProperty, TypedBinding.ForSingleNestingLevel("Icon", static (BaseShellItem item) => item.Icon));
icon.SetBinding(Image.SourceProperty, static (BaseShellItem item) => item.Icon);

var label = new Label
{
Margin = new Thickness(15, 15),
FontSize = 16,
VerticalTextAlignment = TextAlignment.Center,
};
label.SetBinding(Label.TextProperty, TypedBinding.ForSingleNestingLevel("Title", static (BaseShellItem item) => item.Title));
label.SetBinding(Label.TextProperty, static (BaseShellItem item) => item.Title);

_grid = new Grid
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ static View CreateView()
{
TextColor = GColors.Black,
};
label.SetBinding(Label.TextProperty, TypedBinding.ForSingleNestingLevel(string.Empty, static (object source) => source));
label.SetBinding(Label.TextProperty, static (object source) => source);

return new Controls.StackLayout
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ public override NView CreateNativeView(int index)
var nativeView = base.CreateNativeView(index);

var view = GetTemplatedView(nativeView);
view?.SetBinding(ShellSectionItemView.SelectedColorProperty, TypedBinding.ForSingleNestingLevel("TitleColor", static (ItemAppearance appearance) => appearance.TitleColor, source: _itemAppearance));
view?.SetBinding(ShellSectionItemView.UnselectedColorProperty, TypedBinding.ForSingleNestingLevel("UnselectedColor", static (ItemAppearance appearance) => appearance.UnselectedColor, source: _itemAppearance));
view?.SetBinding(ShellSectionItemView.SelectedColorProperty, static (ItemAppearance appearance) => appearance.TitleColor, source: _itemAppearance);
view?.SetBinding(ShellSectionItemView.UnselectedColorProperty, static (ItemAppearance appearance) => appearance.UnselectedColor, source: _itemAppearance);

return nativeView;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ View CreateIconView()
VerticalOptions = LayoutOptions.Center,
};

_icon.SetBinding(Path.DataProperty, TypedBinding.ForSingleNestingLevel("IconPath", static (ShellItemView.MoreItem item) => item.IconPath, converter: new IconConverter()));
_icon.SetBinding(Path.DataProperty, static (ShellItemView.MoreItem item) => item.IconPath, converter: new IconConverter());
return _icon;
}
else
Expand All @@ -133,7 +133,7 @@ View CreateIconView()
VerticalOptions = LayoutOptions.Center,
};

_icon.SetBinding(Image.SourceProperty, TypedBinding.ForSingleNestingLevel("Icon", static (BaseShellItem item) => item.Icon));
_icon.SetBinding(Image.SourceProperty, static (BaseShellItem item) => item.Icon);
return _icon;
}
}
Expand All @@ -150,11 +150,11 @@ View CreateTextView()

if (_isMoreItem)
{
_label.SetBinding(Label.TextProperty, TypedBinding.ForSingleNestingLevel("Title", static (ShellItemView.MoreItem item) => item.Title));
_label.SetBinding(Label.TextProperty, static (ShellItemView.MoreItem item) => item.Title);
}
else
{
_label.SetBinding(Label.TextProperty, TypedBinding.ForSingleNestingLevel("Title", static (BaseShellItem item) => item.Title));
_label.SetBinding(Label.TextProperty, static (BaseShellItem item) => item.Title);
}

return _label;
Expand Down
13 changes: 2 additions & 11 deletions src/Controls/src/Core/Items/CarouselView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,17 +209,8 @@ static void LinkToIndicatorView(CarouselView carouselView, IndicatorView indicat
if (indicatorView == null)
return;

indicatorView.SetBinding(IndicatorView.PositionProperty, TypedBinding.ForSingleNestingLevel(
nameof(CarouselView.Position),
getter: static (CarouselView carousel) => carousel.Position,
setter: static (carousel, val) => carousel.Position = val,
source: carouselView));

indicatorView.SetBinding(IndicatorView.ItemsSourceProperty, TypedBinding.ForSingleNestingLevel(
nameof(CarouselView.ItemsSource),
getter: static (CarouselView carousel) => carousel.ItemsSource,
setter: static (carousel, val) => carousel.ItemsSource = val,
source: carouselView));
indicatorView.SetBinding(IndicatorView.PositionProperty, static (CarouselView carousel) => carousel.Position, source: carouselView);
indicatorView.SetBinding(IndicatorView.ItemsSourceProperty, static (CarouselView carousel) => carousel.ItemsSource, source: carouselView);
}

/// <include file="../../../docs/Microsoft.Maui.Controls/CarouselView.xml" path="//Member[@MemberName='IsScrolling']/Docs/*" />
Expand Down
Loading
Loading