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

[Blazor] Markup Extensions #7897

Closed
legistek opened this issue Feb 23, 2019 · 1 comment
Closed

[Blazor] Markup Extensions #7897

legistek opened this issue Feb 23, 2019 · 1 comment
Labels
area-blazor Includes: Blazor, Razor Components

Comments

@legistek
Copy link

Is your feature request related to a problem? Please describe.

Building a robust and reusable UI framework on top of Razor Components requires a more extensible system for processing CSHTML markup.

For example, I would like to build a component framework that utilizes the equivalent of UWP DependencyProperty's and data binding to support an MVVM pattern. I can get quite far (and already have) without modifying the core code and I'm NOT asking the team to implement this as part of Components.

However, I am stuck at a point where to support an elegant syntax, I would need to change the way parameter attributes are assigned to actual component instances.

For example, in CSHTML I would like to say something like:

<MyComponent MyProperty=@Binding.Create("MyViewModelProperty")/>

This really cannot be done with the current framework without sacrificing the type safety of MyProperty as discussed below.

Describe the solution you'd like

I propose a new interface that would let us create custom mechanisms for assigning parameter values to component instances. You basically already have this with the IPropertySetter interface. I would expose this idea and make it more extensible, as such:

public interface IComponentMarkupExtension
{
     void AssignValue(object target, string parameterName);
}

In the foreach loop in ParameterCollectionExtensions.SetParameterProperties, what I would do is:

if (parameter.Value is IComponentMarkupExtension markupExt)
     markupExt.AssignValue(target, parameterName);
else 
     writerWithIndex.SetValue(target, parameter.Value);

Unless I'm missing something that would be the extent of the changes necessary to the core code. The rest would be handled at the application or component library level. For example, I would define my own Binding class as something like this (most implementation omitted):

public class Binding : IComponentMarkupExtension
{
     public static Binding Create(string path, object source = null)
     {
          return new Binding(path: path, source: source);
     }
     
     public void AssignValue(object target, string parameterName)
     {
          BindingOperations.Bind(target, parameterName, this);
     }
}

Accordingly, when I write
<MyComponent MyProperty=@Binding.Create("MyViewModelProperty")/>
in markup, rather than try to assign a Binding instance to MyProperty, which would cause a type violation, my custom IMarkupExtension will invoke my own BindingOperations.Bind method instead.

I'm sure there are other potential uses for this that I haven't thought of, though robust data binding with an elegant syntax and without sacrificing type safety is really my most important objective here.

Describe alternatives you've considered

Until now I've been declaring property parameter types as dynamic. In each setter, a SetValue method is called that checks for whether the value is a markup extension. I do not like this approach however because it sacrifices type safety and can easily lead to runtime errors. This also doesn't work when the property type needs to be a RenderFragment because dynamic cannot be used for delegate types.

@Eilon Eilon added the area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates label Feb 25, 2019
@mkArtakMSFT mkArtakMSFT added the area-blazor Includes: Blazor, Razor Components label Mar 25, 2019
@mkArtakMSFT
Copy link
Member

Thanks for contacting us, @legistek.
This is not something we plan to bring support for.

@mkArtakMSFT mkArtakMSFT removed area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates labels May 9, 2019
@ghost ghost locked as resolved and limited conversation to collaborators Dec 3, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-blazor Includes: Blazor, Razor Components
Projects
None yet
Development

No branches or pull requests

3 participants