# AiGenerativeUiView
## Description
BitAiGenerativeUiView renders a component the model chose, with the properties it produced. The model names a component and the view looks the name up in the generative UI registry - never a type name in the payload - so a model can only ever instantiate a component the app deliberately registered, and only set the parameters listed on it. Properties that are still streaming bind as far as they have arrived, so a card fills in as the model writes it; a name nothing is registered under renders a quiet placeholder, and the component runs inside an error boundary, so neither takes the answer around it down.
## Parameters
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| Classes | `BitAiGenerativeUiViewClassStyles?` | null | Custom CSS classes for different parts of the generative UI view. |
| Part | `BitAiGenerativeUiPart` | null | The generative UI part to render (required): the name of the component the model chose and the JSON of its properties. The name is resolved through the IBitAiGenerativeUiRegistry, never as a type name, and the properties are bound onto the parameters that registration lists, again whenever the part changes - so a card streaming in fills in as far as its properties have arrived. A name nothing is registered under renders a warning tag once the part has finished streaming. |
| ShowBindingErrors | `bool` | false | Lists, under the component, the properties that failed to bind (a value of the wrong shape, a required one missing) and the ones ignored because the component does not declare them, once the part has finished streaming. Useful while developing the prompt that produces them, noise in production; a BitAiGenerativeUiViewParams of a BitParams turns it on for a whole region. |
| Styles | `BitAiGenerativeUiViewClassStyles?` | null | Custom CSS styles for different parts of the generative UI view. |
| AriaLabel | `string?` | null | Gets or sets the accessible label for the component, used by assistive technologies. |
| Class | `string?` | null | Gets or sets the CSS class name(s) to apply to the rendered element. |
| Dir | `BitDir?` | null | Gets or sets the text directionality for the component's content. |
| Disabled | `bool` | false | Gets or sets a value indicating whether the component is disabled and cannot respond to user interaction. |
| ForceAnimation | `bool` | false | Gets or sets a value indicating whether the component's animations play at their full duration even when reduced motion is requested. |
| HtmlAttributes | `Dictionary<string, object>` | new Dictionary<string, object>() | Captures additional HTML attributes to be applied to the rendered element, in addition to the component's parameters. An attribute written on the component wins over an entry of the same name. |
| Id | `string?` | null | Gets or sets the unique identifier for the component's root element. |
| Style | `string?` | null | Gets or sets the CSS style string to apply to the rendered element. |
| TabIndex | `string?` | null | Gets or sets the tab order index for the component when navigating with the keyboard. |
| Visibility | `BitVisibility` | BitVisibility.Visible | Gets or sets the visibility state (visible, hidden, or collapsed) of the component. |
## Public Members
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| UniqueId | `Guid` | Guid.NewGuid() | Gets the readonly unique identifier for the component's root element, assigned when the component instance is constructed. |
| RootElement | `ElementReference` | | Gets the reference to the root HTML element associated with this component. |
## Enums
### BitAiGenerativeBindErrorKind Enum
| Name | Value | Description |
| :--- | :--- | :---------- |
| Unreadable | 0 | The value the model wrote could not be read as the type the component declares for it ("very cold" for an int); the property is skipped and the rest still bind. |
| Missing | 1 | A property the component requires was not supplied (or was null where its type cannot hold one); the component still renders, without it. |
### BitVisibility Enum
| Name | Value | Description |
| :--- | :--- | :---------- |
| Visible | 0 | The content of the component is visible. |
| Hidden | 1 | The content of the component is hidden, but the space it takes on the page remains (visibility:hidden). |
| Collapsed | 2 | The component is hidden (display:none). |
### BitDir Enum
| Name | Value | Description |
| :--- | :--- | :---------- |
| Ltr | 0 | Ltr (left to right) is to be used for languages that are written from the left to the right (like English). |
| Rtl | 1 | Rtl (right to left) is to be used for languages that are written from the right to the left (like Arabic). |
| Auto | 2 | Auto lets the user agent decide. It uses a basic algorithm as it parses the characters inside the element until it finds a character with a strong directionality, then applies that directionality to the whole element. |
## Sub Classes
### BitAiGenerativeUiViewClassStyles Properties
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| Root | `string?` | null | Custom CSS classes/styles for the root element of the BitAiGenerativeUiView. |
| Content | `string?` | null | Custom CSS classes/styles for the container of the rendered component of the BitAiGenerativeUiView. |
| Unregistered | `BitTagClassStyles?` | null | Custom CSS classes/styles for the BitTag a component name nothing is registered under is shown as by the BitAiGenerativeUiView. |
| Diagnostics | `string?` | null | Custom CSS classes/styles for the container of the binding diagnostics of the BitAiGenerativeUiView. |
| Error | `BitTagClassStyles?` | null | Custom CSS classes/styles for the BitTag of each property that failed to bind in the BitAiGenerativeUiView. |
| Ignored | `BitTagClassStyles?` | null | Custom CSS classes/styles for the BitTag of each property the component of the BitAiGenerativeUiView does not declare. |
### BitAiGenerativeUiPart Properties
A part of a message naming a component the model chose, with the properties it produced as JSON. A session creates one for each BitAiGenerativeUiEvent of its transport and fills it from its BitAiGenerativeUiDeltaEvents; an app creates one to show a component outside a conversation. Safe to read on the renderer's thread while it is appended to on the transport's.
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| new(componentName, partId?) | `constructor` | | Creates a streaming part for the component registered under that name. |
| ComponentName | `string` | | The registered component name, as the model wrote it (matched case-insensitively). |
| Props | `JsonElement?` | null | The properties once complete; until then a lenient parse of the JSON received so far, null while nothing parseable has arrived. |
| RawProps | `string` | "" | The raw JSON property text received so far. |
| IsStreaming | `bool` | true | Whether more properties may still arrive; the view says nothing of an unregistered name or of the binding until it is false. |
| AppendProps(delta) | `void` | | Appends raw JSON property text. |
| SetProps(props) | `void` | | Sets the complete properties at once. |
| Complete() | `void` | | Marks the properties complete, parsing the accumulated text strictly when SetProps did not set them. |
### BitAiGenerativeUiRegistry Properties
The components model output may render, registered as a singleton by AddBitBlazorUIAIServices (as IBitAiGenerativeUiRegistry too) and filled at startup through ConfigureGenerativeUi. Safe to read from any thread. The Register overloads read the parameter types by reflection, down to every type they reach, so they are marked [RequiresUnreferencedCode] and [RequiresDynamicCode]: an app that trims keeps those types itself and suppresses the warnings on the method that registers, with its reason.
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| Register<TComponent>(name, description?, params required) | `BitAiGenerativeComponent` | | Registers a component under a name the model uses (keep it descriptive: the model reads it), replacing one registered under the same name. Its bindable properties are its public [Parameter] properties with a public setter, less callbacks, render fragments, CaptureUnmatchedValues, anything marked [BitAiGenerativeIgnore] and any type whose graph reaches a delegate, a Type or a component. [Description] on a parameter describes it to the model, and on the component is the description when none is given; a name in required, or a [Required] parameter, must be supplied. |
| Register(componentType, name, description?, params required) | `BitAiGenerativeComponent` | | The same with the component type given as a Type; throws an ArgumentException for a type that is not a Blazor component. |
| Unregister(name) | `bool` | | Removes a registration; true when one was removed. |
| Find(name) | `BitAiGenerativeComponent?` | | The registration of a name, matched case-insensitively, or null - the case of a model naming something it should not have, which renders a placeholder. |
| Components | `IReadOnlyCollection<BitAiGenerativeComponent>` | [] | Every registration. |
| DescribeAll() | `JsonElement` | | A JSON Schema of every registration - a oneOf of { component, props } objects - for a system prompt or as the schema of a render tool. Handing it to the model is what makes generative UI reliable: without it the model guesses names. |
| IsBindable(type) | `bool (static)` | | Whether a type is plain data a model may supply: false for delegates, render fragments, event callbacks, Type and any graph containing one. |
### BitAiGenerativeComponent Properties
One registration: the component a name renders and the properties model output may set on it. It is the security boundary - a model can only name what is registered and set what is listed - and the prompting surface, through its Schema.
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| Name | `string` | | The name the model uses. |
| ComponentType | `Type` | | The Blazor component type it renders. |
| Description | `string?` | null | What the component is for, included in the schema. |
| Properties | `IReadOnlyList<BitAiGenerativeProperty>` | [] | The properties the model may set: each one's Name (as the model must spell it, matched case-insensitively), Type, Description and IsRequired. |
| Schema | `JsonElement` | | The JSON Schema of its properties: nested objects with their own properties, collections with items, enums as their names, dates, identifiers and addresses as formatted strings, and additionalProperties false. |
| FindProperty(name) | `BitAiGenerativeProperty?` | | A property by name, matched case-insensitively, as models are inconsistent. |
### BitAiGenerativeIgnoreAttribute Properties
Keeps a parameter out of the set a model may set and out of the schema the model is shown - for a value the app sets itself, such as a service key or an identifier, which is not dangerous but which a model has no business choosing: [Parameter, BitAiGenerativeIgnore] public string TenantId { get; set; }.
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| [BitAiGenerativeIgnore] | `Property | Field` | | Goes on a component parameter, or on a property or field of a parameter's type (a member of a record the component takes), once per member; inherited by overrides. The registry and the schema skip the member, and the binder ignores a value the model sends for it. |
### BitAiGenerativeProperty Properties
One bindable property of a registration (a sealed record), as Register discovers it: new BitAiGenerativeProperty(name, type, description?, isRequired?).
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| Name | `string` | | The parameter name, as the model must spell it (matched case-insensitively). |
| Type | `Type` | | The CLR type the JSON value is read as. |
| Description | `string?` | null | What the property means, from its [Description]; included in the schema the model is shown. |
| IsRequired | `bool` | false | Whether the model must supply it: named in the required of Register, or marked [Required]. A required property left out is a Missing failure. |
### IBitAiGenerativeUiRegistry Properties
What BitAiGenerativeUiView resolves names through - injected, so the registry is app-wide; AddBitBlazorUIAIServices registers BitAiGenerativeUiRegistry as it.
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| Components | `IReadOnlyCollection<BitAiGenerativeComponent>` | | Every registered component. |
| Find(name) | `BitAiGenerativeComponent?` | | The registration of a name, or null - which must render a fallback, since it is the case of a model naming something it should not have. |
### BitAiGenerativePropsBinder Properties
Turns model-produced JSON into the parameters of a registered component - strict about what it accepts, forgiving about the rest: a name the registration does not offer is ignored rather than passed, and a value of the wrong shape is reported and skipped rather than thrown, so one bad field does not lose the whole card. It tolerates partial input, since props stream in and the component renders several times before they are done. BitAiGenerativeUiView calls it whenever its part changes; an app calls it to log or check a payload itself.
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| Bind(component, props) | `BitAiGenerativeBindResult (static)` | | Binds a JSON object onto the properties of a registration, matching names case-insensitively. A null is bound only to a property that can hold it; anything but an object binds nothing and leaves every required property reported as missing. |
### BitAiGenerativeBindResult Properties
The outcome of a binding (a sealed record). Failures are not fatal: the component renders with whatever did bind, because a partly usable card beats an error message.
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| Parameters | `IReadOnlyDictionary<string, object?>` | | The parameters to render the component with, keyed by the name the component declares. |
| Failures | `IReadOnlyList<BitAiGenerativeBindError>` | [] | The properties that did not bind, each with why - what a page shows, worded in its own language. |
| Errors | `IReadOnlyList<string>` | | The same failures in English (each one's ToString()), in the same order, for a log. |
| IgnoredProperties | `IReadOnlyList<string>` | [] | Names in the payload the component does not offer - not a parameter, not bindable, or marked [BitAiGenerativeIgnore] - as the model wrote them. Not errors: models routinely add one, and a model that keeps guessing names is a sign the schema it was given is out of date. |
| IsComplete | `bool` | | True when every property supplied bound and every required one was there; ignored names do not count against it. |
### BitAiGenerativeBindError Properties
A property that did not bind, and why (a sealed record): new BitAiGenerativeBindError(kind, propertyName). It describes the failure rather than wording it, so whoever shows it words it in the language of the page - BitAiGenerativeUiView through the UnreadableProperty and MissingProperty strings.
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| Kind | `BitAiGenerativeBindErrorKind` | | Why the property did not bind. |
| PropertyName | `string` | | The property: as the model wrote it for an Unreadable value, as the component declares it for a Missing one. |
| ComponentName | `string?` | null | The name of the registration the property belongs to. |
| ExpectedType | `Type?` | null | The type an Unreadable value was to be read as. |
| Detail | `string?` | null | What the serializer said about an Unreadable value - written for a developer, in the language of the runtime; the view shows it as the tooltip of the error's tag. |
| ToString() | `string` | | The English description a log reads, the same text Errors lists. |
### BitAiStrings (generative UI) Properties
The texts of the view, members of the BitAiStrings of the options in force. Every member is virtual: a subclass overrides the ones it words differently and is handed as the Strings of the BitAiUiOptions - of a BitAiOptionsProvider, or of ConfigureUi (see /components/ai/optionsprovider#strings).
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| ComponentNotRegistered(component) | `string` | "No component named '{component}' is registered." | The tooltip and accessible name of the warning tag of an unregistered name. |
| ComponentFailed(component) | `string` | "'{component}' could not be rendered" | The notice of the error boundary when the component throws. |
| UnreadableProperty(name, type) | `string` | "'{name}' could not be read as {type}" | The text of the tag of an Unreadable failure (the type as a person reads it: Int32, List). |
| MissingProperty(name, component) | `string` | "'{name}' is required by '{component}'" | The text of the tag of a Missing failure. |
| IgnoredProperty(name) | `string` | "Ignored: {name}" | The text of the tag of an ignored name. |
| IgnoredPropertyHint | `string` | "The component does not declare this property, so it was not passed." | The tooltip of the tag of an ignored name. |
## CSS Variables
Public CSS custom properties read off the component's root. Set one on `:root` to restyle every instance, on any ancestor to restyle the ones inside it, or on the `Style` of one instance to restyle it and every instance nested inside it, which inherits the value too - a parameter changes one alone, as does the real CSS property on its `Style` / `Styles` when that property does not inherit (`opacity`); an inherited one (`color`, `font-family`) reaches the nested instances that do not set it themselves.
| Name | Default Value | Description |
| :--- | :------------ | :---------- |
| `--bit-AiGenerativeUiView-diagnostics-gap` | spacing(1) | Room between two tags of the binding diagnostics. |
| `--bit-AiGenerativeUiView-diagnostics-margin` | spacing(1) | Room between the component and its diagnostics. |
## Examples
\n**Basic**:
```razor
```
```csharp
// A finished part, as a session leaves it once the model has written the properties.
private static BitAiGenerativeUiPart Card(string componentName, string props)
{
var part = new BitAiGenerativeUiPart(componentName);
part.SetProps(JsonDocument.Parse(props).RootElement);
part.Complete();
return part;
}
private readonly BitAiGenerativeUiPart osloPart = Card("forecast_card", """{ "city": "Oslo", "degrees": -3, "condition": "Snow", "humidity": 81 }""");
```
\n**Streaming properties**:
```razor
Stream a forecast
@if (streamedPart is not null)
{
}
```
```csharp
private const string LisbonForecast = """{ "city": "Lisbon", "degrees": 17, "condition": "Clear", "humidity": 54 }""";
private bool isStreamingForecast;
private BitAiGenerativeUiPart? streamedPart;
private async Task StreamForecastAsync()
{
isStreamingForecast = true;
streamedPart = new BitAiGenerativeUiPart("forecast_card");
// Five characters at a time, the way a model writes it.
for (var i = 0; i < LisbonForecast.Length; i += 5)
{
streamedPart.AppendProps(LisbonForecast.Substring(i, Math.Min(5, LisbonForecast.Length - i)));
StateHasChanged();
await Task.Delay(80);
}
streamedPart.Complete();
isStreamingForecast = false;
}
```
\n**From a transport**:
```razor
@implements IAsyncDisposable
The weather in three cities
@if (ForecastAnswer is { } answer)
{
@foreach (var part in answer.PartsOf())
{
}
}
```
```csharp
// A scripted transport that asks for three forecast_card components between two lines of text (see the next tab).
private readonly BitAiChatSession forecastSession = new(AiDemoInteractiveTransports.GenerativeUi());
private BitAiRenderScheduler? renderScheduler;
protected override void OnInitialized()
{
// The session says so on every streamed event; the scheduler turns any number of those into one render per 50 ms.
renderScheduler = new(() => InvokeAsync(StateHasChanged));
forecastSession.StateChanged += renderScheduler.Request;
}
private BitAiMessage? ForecastAnswer => forecastSession.Conversation.LastMessage is { Role.IsAssistant: true } last ? last : null;
private Task AskForForecastsAsync() => forecastSession.SubmitAsync("The weather in Oslo, Lisbon and Auckland");
public async ValueTask DisposeAsync()
{
if (renderScheduler is not null) await renderScheduler.DisposeAsync();
await forecastSession.DisposeAsync();
}
```
`AiDemoInteractiveTransports.cs`:
```csharp
public static IBitAiTransport GenerativeUi() =>
new AiScriptedTransport((request, token) => AiScript.Stream(token, async yielder =>
{
await yielder(new BitAiMessageStartedEvent());
const string intro = "Here is the weather right now in the three cities you asked about.\n\n";
await foreach (var evt in AiScript.Write(intro, 4, 12, token)) await yielder(evt);
string[] cities =
[
"""{"city":"Oslo","degrees":-3,"condition":"Snow","humidity":81}""",
"""{"city":"Lisbon","degrees":17,"condition":"Clear","humidity":54}""",
"""{"city":"Auckland","degrees":22,"condition":"Showers","humidity":72}""",
];
// Each event names a registered component and carries its properties.
foreach (var json in cities)
{
await AiScript.Pause(350, token);
await yielder(new BitAiGenerativeUiEvent("forecast_card", AiScript.Json(json)));
}
const string outro = "\n\nOslo is the outlier. If the trip is flexible, move it a month.";
await foreach (var evt in AiScript.Write(outro, 4, 12, token)) await yielder(evt);
await yielder(new BitAiMessageCompletedEvent());
}));
```
\n**The registry**:
```razor
@inject BitAiGenerativeUiRegistry GenerativeRegistry
```
```csharp
private JsonElement registrySchema;
// The JSON Schema of every registered component, to hand the model.
protected override void OnInitialized() => registrySchema = GenerativeRegistry.DescribeAll();
```
`Program.cs`:
```csharp
builder.Services.AddBitBlazorUIAIServices(ai =>
{
ai.UseTransport();
// The components model output is allowed to instantiate, and the properties it may set.
ai.ConfigureGenerativeUi(RegisterGenerativeComponents);
});
// Registering reads the parameters by reflection, which the registry marks as unsafe to trim. It is safe here: Register
// keeps the component type whole through its annotation, and the parameters it binds are strings and integers, which
// have no members of their own for the trimmer to take away. An app binding records of its own keeps them instead.
[UnconditionalSuppressMessage("Trimming", "IL2026:RequiresUnreferencedCode", Justification = "ForecastCard is kept whole by the annotation of Register, and its bindable parameters are strings and integers.")]
[UnconditionalSuppressMessage("AOT", "IL3050:RequiresDynamicCode", Justification = "ForecastCard's bindable parameters are strings and integers, which need no code generated at run time.")]
static void RegisterGenerativeComponents(BitAiGenerativeUiRegistry registry)
{
// The name the model uses, what the component is for, and the properties it must supply.
registry.Register("forecast_card", "Shows the current weather for one city.", "City");
}
```
`ForecastCard.razor`:
```razor
@* A component the model is allowed to render, in the AI generative UI scenario.
Nothing about it knows it is generative: it is an ordinary Blazor component with ordinary parameters. The registry
(BitAiGenerativeUiRegistry, filled in AddClientSharedServices) decides that model output may instantiate it, and the
binder decides which of its parameters model output may set. *@
@code {
/// The city being forecast.
[Parameter, System.ComponentModel.Description("The city name.")]
public string City { get; set; } = string.Empty;
/// The temperature in Celsius.
[Parameter, System.ComponentModel.Description("Temperature in degrees Celsius.")]
public int Degrees { get; set; }
/// A one-word summary such as Clear or Snow.
[Parameter, System.ComponentModel.Description("One word summary, for example Clear, Snow, Showers.")]
public string Condition { get; set; } = string.Empty;
/// Relative humidity as a percentage.
[Parameter, System.ComponentModel.Description("Relative humidity as a percentage.")]
public int Humidity { get; set; }
}
```
\n**Unregistered components**:
```razor
```
```csharp
// A finished part, as a session leaves it once the model has written the properties.
private static BitAiGenerativeUiPart Card(string componentName, string props)
{
var part = new BitAiGenerativeUiPart(componentName);
part.SetProps(JsonDocument.Parse(props).RootElement);
part.Complete();
return part;
}
private readonly BitAiGenerativeUiPart unregisteredPart = Card("stock_ticker", """{ "symbol": "BIT", "price": 42.5 }""");
```
\n**Binding diagnostics**:
```razor
```
```csharp
// A finished part, as a session leaves it once the model has written the properties.
private static BitAiGenerativeUiPart Card(string componentName, string props)
{
var part = new BitAiGenerativeUiPart(componentName);
part.SetProps(JsonDocument.Parse(props).RootElement);
part.Complete();
return part;
}
// degrees is not a number, City (required) is missing, and wind is not a parameter of ForecastCard.
private readonly BitAiGenerativeUiPart faultyPart = Card("forecast_card", """{ "degrees": "very cold", "condition": "Windy", "wind": "40 km/h" }""");
```
\n**Binding in code**:
```razor
("ticket_card", "Shows a ticket for an event.", "Event");
// row binds; seats is not a number; Event (required) is missing; tenantId, onBuy and color are not offered, so ignored.
private readonly BitAiGenerativeBindResult ticketBinding = BitAiGenerativePropsBinder.Bind(ticketCard, JsonDocument.Parse("""
{ "row": "B", "seats": "two", "tenantId": "someone-else", "onBuy": "alert(1)", "color": "red" }
""").RootElement);
```
\n**Cascading parameters**:
```razor
```
```csharp
// A finished part, as a session leaves it once the model has written the properties.
private static BitAiGenerativeUiPart Card(string componentName, string props)
{
var part = new BitAiGenerativeUiPart(componentName);
part.SetProps(JsonDocument.Parse(props).RootElement);
part.Complete();
return part;
}
// degrees is not a number, City (required) is missing, and wind is not a parameter of ForecastCard.
private readonly BitAiGenerativeUiPart faultyPart = Card("forecast_card", """{ "degrees": "very cold", "condition": "Windy", "wind": "40 km/h" }""");
private bool showDiagnostics = true;
private BitAiGenerativeUiViewParams[] generativeParams => [new() { ShowBindingErrors = showDiagnostics }];
```
\n**Style & Class**:
```razor
```
```csharp
// A finished part, as a session leaves it once the model has written the properties.
private static BitAiGenerativeUiPart Card(string componentName, string props)
{
var part = new BitAiGenerativeUiPart(componentName);
part.SetProps(JsonDocument.Parse(props).RootElement);
part.Complete();
return part;
}
private readonly BitAiGenerativeUiPart osloPart = Card("forecast_card", """{ "city": "Oslo", "degrees": -3, "condition": "Snow", "humidity": 81 }""");
private readonly BitAiGenerativeUiPart faultyPart = Card("forecast_card", """{ "degrees": "very cold", "condition": "Windy", "wind": "40 km/h" }""");
```
\n**RTL**:
```razor
```
```csharp
// A finished part, as a session leaves it once the model has written the properties.
private static BitAiGenerativeUiPart Card(string componentName, string props)
{
var part = new BitAiGenerativeUiPart(componentName);
part.SetProps(JsonDocument.Parse(props).RootElement);
part.Complete();
return part;
}
private readonly BitAiGenerativeUiPart tehranPart = Card("forecast_card", """{ "city": "تهران", "degrees": 24, "condition": "آفتابی", "humidity": 30 }""");
private readonly BitAiGenerativeUiPart unregisteredPart = Card("stock_ticker", """{ "symbol": "BIT", "price": 42.5 }""");
```
@City
@Degrees°
IsComplete: @ticketBinding.IsComplete
-
@foreach (var (name, value) in ticketBinding.Parameters)
{
- Bound: @name = @value } @foreach (var failure in ticketBinding.Failures) {
- @failure.Kind: @failure.PropertyName - @failure } @foreach (var name in ticketBinding.IgnoredProperties) {
- Ignored: @name }