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

Add DynamicComponent component #26781

Closed
mwpowellhtx opened this issue Oct 10, 2020 · 23 comments
Closed

Add DynamicComponent component #26781

mwpowellhtx opened this issue Oct 10, 2020 · 23 comments
Assignees
Labels
affected-most This issue impacts most of the customers area-blazor Includes: Blazor, Razor Components Done This issue has been fixed enhancement This issue represents an ask for new feature or an enhancement to an existing one severity-major This label is used by an internal tool
Milestone

Comments

@mwpowellhtx
Copy link

It may be similar to dynamic rendering, I'm not sure, but I will just state the goal: property grids.

I am working with <insert-third-party-component-here/>, suffice to say VendorDataGrid as a basis, and a RYO view model approach, that takes the target object for which we want the property grid, and, thanks to the magic of Reflection, identifies the properties and corresponding property view models for those properties for the property grid approach.

I can handle probably 80-90% of the conceivable use cases within the core PG asset itself, but there are moments when a custom display and/or editor view would be handy, as provided by the view model.

So I wonder if a framework such as this might be possible given the Blazor rendering constraints, that is, view model provides, say, an instance of ComponentBase, whatever that may be, as a basis for an editor view. All the back end wiring is done by the property grid property view models themselves, I just want for a view to ostensibly potentially provide a view for itself to the parent property grid.

Thanks...

@mkArtakMSFT mkArtakMSFT added area-blazor Includes: Blazor, Razor Components Docs This issue tracks updating documentation labels Oct 11, 2020
@mkArtakMSFT mkArtakMSFT added this to the Next sprint planning milestone Oct 12, 2020
@ghost
Copy link

ghost commented Oct 12, 2020

Thanks for contacting us.
We're moving this issue to the Next sprint planning milestone for future evaluation / consideration. We will evaluate the request when we are planning the work for the next milestone. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

@mkArtakMSFT
Copy link
Member

Here are some notes for further consideration, @SteveSandersonMS. We think that the main ask here is to given a type render a component.

@mkArtakMSFT mkArtakMSFT added enhancement This issue represents an ask for new feature or an enhancement to an existing one and removed Docs This issue tracks updating documentation labels Oct 12, 2020
@SteveSandersonMS
Copy link
Member

@mwpowellhtx We're thinking of shipping a component called DynamicComponent that would render an arbitrary other component and pass a dictionary of parameters to it. You'd use it like this:

<DynamicComponent Type="@gridCell.EditorComponentType" Parameters="@gridCell.EditorComponentParameters" />

This would allow your propertygrid viewmodel to completely control the display/editor based on your own dynamic logic.

Do you think this would satisfy your requirements? If so we'd be happy to add this to the backlog.

@mwpowellhtx
Copy link
Author

@SteveSandersonMS Thanks for the consideration. I would reserve judgment until I saw it exercised in practice, but, on paper, yes, it sounds plausible.

@SteveSandersonMS SteveSandersonMS changed the title [Blazor] Provide guidelines or working solution for component rendering extensibility Add DynamicComponent component Oct 12, 2020
@SteveSandersonMS SteveSandersonMS added affected-most This issue impacts most of the customers severity-major This label is used by an internal tool labels Oct 12, 2020 — with ASP.NET Core Issue Ranking
@mwpowellhtx
Copy link
Author

@SteveSandersonMS Offering a bit of constructive feedback, I have in mind for my view model to report its view to the parent view. I should think there is very little such a thing needs to do but "host" it. Such as, from C# property perspective:

public abstract class ViewModel
{
    /// <summary>
    /// Gets the Editor View associated with the ViewModel.
    /// </summary>
    public abstract ComponentBase EditorView { get; }
}

Possible as a derivative of ComponentBase.

public abstract class ViewModel<TEditorComponent>
    where TEditorComponent : ComponentBase
{
    /// <summary>
    /// Gets the Editor View associated with the ViewModel.
    /// </summary>
    public abstract TEditorComponent EditorView { get; }
}

Along these lines.

How might that get received by a DynamicComponent? If it is even necessary...

@SteveSandersonMS
Copy link
Member

@mwpowellhtx For the reasons described in #25154 (comment), we would not want to support passing in an actual instance of a component. This explains why it needs to be a type+parameters instead of a pre-constructed instance.

@mwpowellhtx
Copy link
Author

@SteveSandersonMS Okay, how does it know which parameters to use? Do we relay those as Expressions?

@SteveSandersonMS
Copy link
Member

As per the comment at #26781 (comment), the developer would pass whatever dictionary of parameters they want it to use.

@mwpowellhtx
Copy link
Author

@SteveSandersonMS That could work, thank you.

pranavkm pushed a commit that referenced this issue Nov 24, 2020
Implements #26781

Although developers have been able to implement custom rendertree builder for dynamic component selection since the beginning of Blazor, we've always intended to make this a simpler built-in feature.

It's fairly simple, so I can't think of any reason not to just do it now.

### Usage

```razor
<DynamicComponent Type="@sometype" />

@code {
    Type someType = typeof(MyOtherComponent); // Or use custom logic to vary this at runtime
}
```

... or:

```razor
<DynamicComponent Type="@sometype" Parameters="@myDictionaryOfParameters" />

@code {
    Type someType = ...
    IDictionary<string, object> myDictionaryOfParameters = ...
}
```
@ghost ghost added Done This issue has been fixed and removed Working labels Nov 25, 2020
@mwpowellhtx
Copy link
Author

@SteveSandersonMS Okay, so if you are dismissing this one out of hand, at least provide examples how to workaround the stated behavior. Thank you.

@SteveSandersonMS
Copy link
Member

Sorry, I don't know what you mean. I thought I answered your question and you replied "That could work, thank you.".

What are you referring to?

@mwpowellhtx
Copy link
Author

@SteveSandersonMS Perhaps I misunderstood; I have not actually verified it. Again, we want to relay an actual view via view model properties. Is it even possible? That I know of in my early attempts, this was not possible. Not sure how that translates into a "dictionary" of values, per se.

@SteveSandersonMS
Copy link
Member

Again, we want to relay an actual view via view model properties. Is it even possible?

No, that's now how Blazor or similar diff-based frameworks work (such as React). Your model properties need to contain data, and then you use .razor components to translate that into UI. If you want, you can use <DynamicComponent> to transform a System.Type instance into a component instance if you want to do it dynamically like that.

@mwpowellhtx
Copy link
Author

@SteveSandersonMS As I explained earlier, I've got a case, specifically, where the view model for property grid can meet perhaps 75-85% of the common cases in the view itself. However, for those 15-25% cases, we need for the view model to provide the view required to view, edit, etc. Was this not clear before?

@SteveSandersonMS
Copy link
Member

we need for the view model to provide the view required to view, edit, etc.

Is there some reason why you need to provide the component instance? Why isn't it possible to provide the information needed to create the component during rendering? The latter is how rendering is meant to work in Blazor.

If you could help clarify that, I might be able to point towards a solution.

@mwpowellhtx
Copy link
Author

@SteveSandersonMS To be clear, I don't care if I have to provide an instance, or a blueprint of an instance. That's the guidance that I am requesting. I am simply stating the goal: the view model (not model itself, mind you) may need to provide its view and/or editor, in some way shape or form, I care not how. Because, as I stated clearly, the property grid can meet perhaps 75-85% of the view/editor use cases, but for those edge cases, the view model must provide its own that the grid can inject.

@SteveSandersonMS
Copy link
Member

SteveSandersonMS commented Nov 25, 2020

or a blueprint of an instance

That's what I'm suggesting you do. Have your model contain information saying what kind of view should be rendered. This information could be in the form of a System.Type instance, or it could be an Enum value, or a string, and possibly with some dictionary of parameters - whatever is most convenient for you.

And then in your host component's rendering logic, you can translate that into some rendered UI. For example you could do:

@switch (myModel.ViewType) // Assuming this is some enum
{
    case MyViewType.Customer:
        <CustomerEditor Data="@myModel" />
        break;
    case MyViewType.WeatherInfo:
        <WeatherForecast Data="@myModel" />
        break;
}

Or if you want, you could have your data model contain the Type and parameters for a component to be rendered, and then:

<DynamicComponent Type="@myModel.RenderAsComponentType" Parameters="@myModel.ComponentParameters" />

This is what I mean by "providing the information to determine what to render" or "a blueprint of a component instance". If this is not sufficient for your scenario for some reason, then I'd need clarification on why this approach can't be sufficient.

@mwpowellhtx
Copy link
Author

@SteveSandersonMS Maybe I have not been clear. I am designing the property grid as a generic component. Maybe it lands in OS, maybe not, I do not know yet. In the general form, that is essentially what it does, for the 85% case, for things like int, double (i.e. spin editors), string (i.e. text editor), even for enum cases (i.e. a drop down). However, at a general level, cannot know about application specific bits like Customer or WeatherInfo. All the property grid knows about, it is given a sequence of ViewModel instances. That's it. So it can either fill in the 85% cases, and when it cannot, must ask that level of detail from the particular instance. Is that clear now? Maybe this is too much of a pattern for little ole SPA Blazor?

@mwpowellhtx
Copy link
Author

@SteveSandersonMS Again to clarify, how did property grids of old ever work? They had to have distilled this sort of editor capability abstraction at some level. Canned 85-90% of the common cases, let's say, and allowed for extensibility for custom application specific bits. That's the goal here.

@SteveSandersonMS
Copy link
Member

How is DynamicComponent not sufficient for that?

@mwpowellhtx
Copy link
Author

@SteveSandersonMS I explained it. PG cannot know the application specific bits except that there is a ViewModel instance being injected. So ViewModel must provide its own display and editor bits. How does it do that when the PG is rendering?

@mwpowellhtx
Copy link
Author

@SteveSandersonMS Would it help if we jumped on a conference call and I could try to demo the PG and what I am trying to accomplish with it? Maybe it will be clearer.

@SteveSandersonMS
Copy link
Member

Sorry, I’m not available, but I am confident that DynamicComponent is sufficient for this scenario. You can supply arbitrary type instances and parameter dictionaries from your view models, so you can have your view models dictate that any component of their choice is used to render them.

@ghost ghost locked as resolved and limited conversation to collaborators Dec 25, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
affected-most This issue impacts most of the customers area-blazor Includes: Blazor, Razor Components Done This issue has been fixed enhancement This issue represents an ask for new feature or an enhancement to an existing one severity-major This label is used by an internal tool
Projects
None yet
Development

No branches or pull requests

3 participants