Commit Graph

4 Commits

Author SHA1 Message Date
Ryan Nowak 6f383a0f0f Adds support for 'Context' parameters on components (#1470)
Adds support for 'Context' parameters on components

This change allows you to set the parameter name of a parameterized child content by using the `Context` attribute on the component. The `Context` attribute will be defined (and shown by completion) when the component has one or more declared parameterized (`RenderFragment<>`) child content parameters.

This is nice for cases where you are using implicit child content:

```
<ol>
  <Repeater Items="People" Context="person">
    <li>@person.FirstName</li>
  </Repeater>
</ol>
```

 or, when you have multiple child content elements and want them all to have the same parameter name:

 ```
<MyComponent Items="People" Context="person">
    <ChildContent1><div>@person.FirstName</div></ChildContent1>
    <ChildContent2><div>@person.LastName</div></ChildContent2>
</Repeater>
```

The parameter name can be overridden by using the `Context` parameter on the child content element:

 ```
<MyComponent Items="People" Context="person">
    <ChildContent1 Context="item"><div>@item.FirstName</div></ChildContent1>
    <ChildContent2><div>@person.LastName</div></ChildContent2>
</Repeater>
```

If the component defines a `Context` parameter already then we won't synthesize one - your component's parameter will work exactly as it did before this feature.
2018-09-24 12:22:16 -07:00
Ryan Nowak 100382bf71 Add Type Inference for Generic-Typed Components
This change allows you to use generic-typed components without
explicitly specify type arguments.

**Before:**
```
<Grid Items="@MyItems" TItem="Person">
...
</Grid>
```

**After:**
```
<Grid Items="@MyItems">
...
</Grid>
```

Where possible, the type of the component will be inferred based on the
values passed to component parameters. This won't work like magic, you
have to specify parameters that provide type arguments for all of the
component's type parameters.

This is a best effort system, and it's largely based on the limitations
and behaviours of generic type inference in C#. We think it will work
well with most Blazor features and for most reasonable components. You
should not forget it's easy to specify type arguments, because you may
still have to in some cases.

In particular you may notice issues if you are trying to use a generic
typed component where all of the parameters are delegates or templates.
Type inference for delegates/lambdas in C# is based on the context. Any
time you combine generics and delegates it's easy to get into a scenario
where the compiler won't infer the correct type, or will give up.

----
The type inference feature works by generating a 'thunk' method in
*caller* that can act as a site for type inference (C# does not support
inference on constructors).

For our grid example above, the non-inferenced code will look something
like:
```
builder.OpenComponent<Grid<Person>>(0);
builder.AddAttribute(1, "Items", MyItems);
builder.CloseComponent();
```

Note that we can only write the type `Grid<Person>` because you wrote
`Person` in your code. What you type in the `TItem` attribute value gets
inserted into the generated code such that it fills in the generic type
parameter.

On the other hand, if you want is to infer the type, we have to do some
compiler magic. That looks like:
```
__Blazor.(long generated name).TypeInference.CreateGrid_0();
...

// elsewhere in the file
internal static class TypeInference
{
    public static void CreateGrid_0<TItem>(RenderTreeBuilder builder,
    int seq, int __seq0, global::System.Collections.Generic.List<TItem>
    __arg0)
        {
	        builder.OpenComponent<Grid<TItem>>(seq);
		        builder.AddAttribute(__seq0, "Items", __arg0);
			        builder.CloseComponent();
				    }
				    }
				    ```

				    This allows us to rely on the C#
				    compiler for itype inference.
2018-09-20 12:19:26 -07:00
Ryan Nowak 354752cf16 Add support for generic-typed components (#1417)
* Add the ability to discover generic types/properties

* Add @typeparam directive

Adds the ability to declare a generic-typed component using Razor.

* Add a 'type parameter' property to generic components

* Adds the ability to consume generic-typed components
2018-09-16 14:01:15 -07:00
Ryan Nowak d4cbb86f46 Add Support for Templated Components (#1404)
* Test namespace cleanup

* Add recognication for RenderFragment in tag helpers

* Remove dead code from node writers

* refactor type check

* Continue to treat child content as a delegate in codegen

* Add extension to enumerate child content

* Reorganize code generation tests

These were growing a bit disorganized, and weren't really result in good
code reuse.

* fix test base class

* Add some child-content tests

* Add an explicit node for ChildContent

Adds a strongly typed node to represent a 'ChildContent' and what it
contains. This allows us to simplify the code generation path,
detect/processes more issues in IR passes, and will be essential for
supporting multiple child content.

* Ignore ChildContent in components when it's just whitespace

* Add diagnostic for duplicate child content

* Add support for explicit child content elements

Precursor to support for multiple child content items

* Add support for multiple child-content elements

* Change delegate signature for RenderFragment<T>

* Clean up Tag Helper constants

* Allow RenderFragment<T> as a child content

* Allow renaming the template parameter

* Improve error message for invalid child content

* Add diagnostic for repeated child content parameter names
2018-09-10 18:59:51 -07:00