Skip to content

Commit

Permalink
feat(xbind): Add pathless casting support
Browse files Browse the repository at this point in the history
  • Loading branch information
jeromelaban committed Sep 28, 2022
1 parent 2b2736d commit 21f12bc
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 5 deletions.
22 changes: 22 additions & 0 deletions doc/articles/features/windows-ui-xaml-xbind.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,28 @@ Uno supports the [`x:Bind`](https://docs.microsoft.com/en-us/windows/uwp/xaml-pl
<TextBox FontFamily="{x:Bind (FontFamily)MyComboBox.SelectedValue}" />
```

- [Pathless casting](https://learn.microsoft.com/en-us/windows/uwp/xaml-platform/x-bind-markup-extension#pathless-casting)
```xml
<Page
x:Class="AppSample.MainPage"
...
xmlns:local="using:AppSample">

<Grid>
<ListView ItemsSource="{x:Bind Songs}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:SongItem">
<TextBlock
Margin="12"
FontSize="40"
Text="{x:Bind local:MainPage.GenerateSongTitle((local:SongItem))}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Page>
```

- `x:Load` binding
```xml
<TextBox x:Load="{x:Bind IsMyControlVisible}" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ public class Given_XBindRewriter
[DataRow("ctx", "(FontFamily)a.Value", "(FontFamily)ctx.a.Value")]
[DataRow("ctx", "(global::System.Int32)a.Value", "(global::System.Int32)ctx.a.Value")]

// Pathless casting https://learn.microsoft.com/en-us/windows/uwp/xaml-platform/x-bind-markup-extension#pathless-casting
[DataRow("ctx", "MyFunction((global::System.String))", "ctx.MyFunction(((global::System.String)ctx))")]
[DataRow("ctx", "MyFunction2((global::System.String),(global::System.String))", "ctx.MyFunction2(((global::System.String)ctx),((global::System.String)ctx))")]
[DataRow("ctx", "(global::System.String)", "((global::System.String)ctx)")]

// Not supported https://github.com/unoplatform/uno/issues/5061
// [DataRow("ctx", "MyFunction((global::System.Int32)MyProperty)", "ctx.MyFunction((global::System.Int32)ctx.MyProperty)")]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,15 +104,27 @@ private string ContextBuilder
var e = base.VisitMemberAccessExpression(node);
var isValidParent = !Helpers.IsInsideMethod(node).result && !Helpers.IsInsideMemberAccessExpression(node).result;
var isParentMemberStatic = node.Expression is MemberAccessExpressionSyntax m && _isStaticMember(m.ToFullString());
var isPathLessCast = Helpers.IsPathLessCast(node);

if (e!= null && isValidParent && !_isStaticMember(node.Expression.ToFullString()) && !isParentMemberStatic)
{
var expression = e.ToFullString();
var contextBuilder = _isStaticMember(expression) ? "" : ContextBuilder;
var output = ParseCompilationUnit($"class __Temp {{ private Func<object> __prop => {contextBuilder}{expression}; }}");
if (isPathLessCast.result)
{
var expression = e.ToFullString();
var output = ParseCompilationUnit($"class __Temp {{ private Func<object> __prop => ({isPathLessCast.expression?.Expression}){_contextName}; }}");

var o2 = output.DescendantNodes().OfType<ArrowExpressionClauseSyntax>().First().Expression;
return o2;
var newSyntax = output.DescendantNodes().OfType<ArrowExpressionClauseSyntax>().First().Expression;
return newSyntax;
}
else
{
var expression = e.ToFullString();
var contextBuilder = _isStaticMember(expression) ? "" : ContextBuilder;
var output = ParseCompilationUnit($"class __Temp {{ private Func<object> __prop => {contextBuilder}{expression}; }}");

var newSyntax = output.DescendantNodes().OfType<ArrowExpressionClauseSyntax>().First().Expression;
return newSyntax;
}
}
else
{
Expand Down Expand Up @@ -259,6 +271,31 @@ internal static (bool result, CastExpressionSyntax? expression) IsInsideCast(Syn

return (false, null);
}

internal static (bool result, ParenthesizedExpressionSyntax? expression) IsPathLessCast(SyntaxNode node)
{
var currentNode = node.Parent;

do
{
if (currentNode is ArgumentSyntax arg
&& arg.Expression is ParenthesizedExpressionSyntax expressionSyntax)
{
return (true, expressionSyntax);
}

if (currentNode is ArrowExpressionClauseSyntax arrow
&& arrow.Expression is ParenthesizedExpressionSyntax expressionSyntax2)
{
return (true, expressionSyntax2);
}

currentNode = currentNode?.Parent;
}
while (currentNode != null);

return (false, null);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<UserControl x:Class="Uno.UI.Tests.Windows_UI_Xaml_Data.xBindTests.Controls.xBind_PathLessCasting"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Uno.UI.Tests.Windows_UI_Xaml_Data.xBindTests.Controls"
xmlns:xc="using:Windows.UI.Xaml.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">

<Grid>
<TextBlock x:Name="tb1"
x:FieldModifier="public"
Tag="{x:Bind (xc:UserControl)}" />
</Grid>
</UserControl>
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236

namespace Uno.UI.Tests.Windows_UI_Xaml_Data.xBindTests.Controls
{
public sealed partial class xBind_PathLessCasting : UserControl
{
public xBind_PathLessCasting()
{
this.InitializeComponent();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<UserControl x:Class="Uno.UI.Tests.Windows_UI_Xaml_Data.xBindTests.Controls.xBind_PathLessCasting_Template"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Uno.UI.Tests.Windows_UI_Xaml_Data.xBindTests.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">


<Grid>
<ContentControl x:Name="root"
x:FieldModifier="public">
<ContentControl.ContentTemplate>
<DataTemplate x:DataType="local:xBind_PathLessCasting_Template_Model">
<Grid>
<TextBlock x:Name="tb1"
x:FieldModifier="public"
Tag="{x:Bind (local:xBind_PathLessCasting_Template_Model)}" />
</Grid>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</Grid>
</UserControl>
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236

namespace Uno.UI.Tests.Windows_UI_Xaml_Data.xBindTests.Controls
{
public sealed partial class xBind_PathLessCasting_Template : UserControl
{
public xBind_PathLessCasting_Template()
{
this.InitializeComponent();
}
}

public class xBind_PathLessCasting_Template_Model
{

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1264,6 +1264,31 @@ public async Task When_NullableRecordStruct()
Assert.AreEqual("42", SUT.tb1.Text);
}

[TestMethod]
public async Task When_PathLessCasting()
{
var SUT = new xBind_PathLessCasting();

SUT.ForceLoaded();

Assert.AreEqual(SUT, SUT.tb1.Tag);
}

[TestMethod]
public async Task When_PathLessCasting_Template()
{
var SUT = new xBind_PathLessCasting_Template();

SUT.ForceLoaded();

var rootData = new xBind_PathLessCasting_Template_Model();
SUT.root.Content = rootData;

var myObject = SUT.FindName("tb1") as TextBlock;

Assert.AreEqual(rootData, myObject.Tag);
}

private async Task AssertIsNullAsync<T>(Func<T> getter, TimeSpan? timeout = null) where T:class
{
timeout ??= TimeSpan.FromSeconds(1);
Expand Down

0 comments on commit 21f12bc

Please sign in to comment.