Standardmäßig MainGrid und SubGrid rendere die Spalteneinstellung, die die aktive Dataverse-Ansicht zurückgibt. Die Komponente GridColumn ermöglicht es Ihnen, explizite Kontrolle zu übernehmen: Wenn ein oder mehrere GridColumn Kinder deklariert werden, rendert das Raster nur diese Spalten in der deklarierten Reihenfolge, und die serverseitige Projektion wird neu geschrieben, um genau die deklarierte Menge abzurufen. Nutzen Sie das, um ein Raster auf die Spalten zu verkleinern, die für eine bestimmte Seite wichtig sind, sie neu zu ordnen, Breite / Ausrichtung anzupassen, vorzuweisen Vorlagen pro Zelle oder Oberflächenspalten, die nicht in der zugrundeliegenden Ansicht sind – ohne die Dataverse-Ansicht selbst zu bearbeiten.
Live-Demo
A über der contact Tabelle, gemischt MainGrid mit GridTemplateColumn vier regulären GridColumn Kindern. Die erste Zelle ist synthetisch – sie besteht aus einem Initialen-Avatar plus einem fettgedruckten Namen aus Raw firstname + lastname Werten, die über in die Projektion gezogen werdenDependsOn. Die nächsten drei zeigen pro Zelle Vorlagen auf gebundenen Spalten: einen mailto: Link, eine Telefonnummer mit einem Inline-Symbol und ein farbcodiertes Altersabzeichen, das das Raw DecimalValue Via GetValueOrDefault<T>() für den Schwellenvergleich liest. Das letzte, Geburtstag, hat keine Vorlage, sodass die eingebaute Datumszelle es rendert. Klicken Sie auf das Zahnrad-Symbol und aktivieren Sie Editable, um die Spalte EditChildContent der Vorlage in Aktion zu sehen – die Vollname-Zelle wechselt vom Avatar-Rendering zu zwei nebeneinander TextEdit stehenden Editoren, die auf firstname + lastnamegebunden sind.
Bauteile in einen GridColumns Wrapper unter das Gitter werfenGridColumn. Deklarierte Spaltennamen überschreiben die <attribute> Projektion des FetchXML – der Server ruft die deklarierten Spalten ab, selbst wenn sie nicht in der Spaltenauswahl der aktiven Ansicht sind. Der Parameter TableName ist im deklarierten Modus optional: Wenn er weggelassen wird, wird der eigene TableName Parameter verwendet (es muss nicht in jeder Spalte wiederholt werden).
Das Deklarieren eines Children GridColumn schaltet das Gitter in den Ersetzmodus: Deklarierte Spalten sind die gesamte gerenderte Spaltenmenge UND die gesamte geholfene Spaltenmenge. Ansichtsspalten, die hier nicht deklariert sind, werden sowohl aus dem Render als auch aus der Serverprojektion entfernt. Wenn du die meisten View-Spalten mit ein oder zwei Anpassungen möchtest, verzichte komplett auf den Wrapper oder baue eine benutzerdefinierte Ansicht über CustomViewDefinitions.
Erforderliche Parameter
Jede Erklärung GridColumn lautet:
ColumnName — Pflicht. Logischer Name der Spalte, die projiziert werden soll. Unterstützt Dot-Notation für aliasierte verknüpfte Entitäten-Spalten (primarycontactid.emailaddress1); das Alias muss bereits als a <link-entity> in der aktiven Ansicht von FetchXML existieren.
TableName — Optional. Logischer Name der Tabelle, deren Metadaten diese Spalte beschreiben. Wenn es weggelassen wird, greift es auf das Raster TableName zurück – praktisch, um den Verbraucheraufschlag auf Ein-Tisch-Gittern kurz zu halten.
Spaltenbreite
Verwenden Sie Width es, um die gespeicherte Breite der Ansicht zu überschreiben. Akzeptiert jede CSS-Länge – Pixel ("150px"), Prozentsätze ("20%") oder "auto". Ohne eine explizite Breite fällt das Raster auf den metadatenbasierten Standard und die natürliche Verteilung der Tabelle zurück.
Benutze sie, Align um die horizontale Ausrichtung sowohl für den Header als auch für die Körperzelle zu überschreiben. Numerische und Geld-Spalten werden standardmäßig (rechts ausgerichtet) über das metadatenbasierte Rückfallback-System gesetzt Align.End ; boolesche Spalten standardmäßig auf Align.Center. Stelle sie explizit ein, wenn du eine nicht-standardmäßige Ausrichtung möchtest oder eine benutzerdefinierte Vorlagenzelle konsistent ausrichten möchtest.
React
Blazor
{/* Numerische und Geld-Spalten richten sich bereits über die
Metadatenbasierte Rückfallversicherung. Stelle Align explizit ein, wenn du
Ich möchte eine nicht-standardmäßige Ausrichtung. */}
<GridColumns>
<GridColumn columnName="firstname" />
<GridColumn columnName="creditlimit" align="end" />
<GridColumn columnName="donotemail" align="center" />
</GridColumns>
<!-- Numerische und Geld-Spalten richten sich bereits über die
Metadatenbasierte Rückfallversicherung. Set Align explizit ein, wenn du
Ich möchte eine nicht-standardmäßige Ausrichtung. -->
<GridColumns>
<GridColumn ColumnName="firstname" />
<GridColumn ColumnName="creditlimit" Align="DataGridCellAlignment.End" />
<GridColumn ColumnName="donotemail" Align="DataGridCellAlignment.Center" />
</GridColumns>
Linked-Entity-Spalten
Aliased Linked-Entity-Spalten verwenden eine Dot-Notation, die der FetchXML-Aliasierung der Ansicht entspricht. Der Alias muss bereits in der aktiven Ansicht als a <link-entity> definiert sein. Setzen TableName Sie auf die Quelltabelle , auf die der Alias zeigt, sodass die Metadaten-Auflösung auf der richtigen Entität landet. Der Server gibt diese Spalten mit ihrem für die Elterntabelle qualifizierten lokalisierten Anzeigenamen zurück (z. B. "Email (Primary Contact)") – keine clientseitige Humanisierung erforderlich.
React
Blazor
<MainGrid tableName="account">
<GridColumns>
<GridColumn columnName="name" />
{/* Aliasierte Linked-Entity-Spalte: Die Dot-Notation stimmt mit
wie die Spalte im FetchXML-Alias der Ansicht erscheint.
Der Server löst die Metadaten der Link-Entität automatisch auf
aus dem FetchXML – kein separates tableName-Prop erforderlich. */}
<GridColumn columnName="primarycontactid.emailaddress1" />
</GridColumns>
</MainGrid>
<MainGrid TableName="account">
<GridColumns>
<GridColumn ColumnName="name" />
<!-- Aliasierte Linked-Entity-Spalte: Die Dot-Notation stimmt mit
wie die Spalte im FetchXML-Alias der Ansicht erscheint.
TableName muss auf die Tabelle der LINK-ENTITY verweisen, also
Metadaten lösen sich gegen die richtige Entität auf. -->
<GridColumn ColumnName="primarycontactid.emailaddress1"
TableName="contact" />
</GridColumns>
</MainGrid>
Pro-Zell-Vorlagen
Liefern ChildContent , um jede Zelle mit individuellem Markup zu rendern. Die Vorlage erhält GridRowContext – ihre PrimaryRecord Eigenschaft stellt die vollständige TableRecord Zeilenzahl offen (getippte Spaltenwerte, formatierte Werte, Berechtigungen, alles). Nützlich für bedingte Formatierung (roter Text über einem Schwellenwert), Symbole, Abzeichen, Links oder alles andere, was man aus dem Zeilendatensatz bauen kann.
React
Blazor
<GridColumns>
<GridColumn columnName="fullname" />
<GridColumn
columnName="creditlimit"
cellRenderer={({ record }) => {
// Der TableRecord der Zeile – roh + formatierte Werte sind beide verfügbar.
const raw = (record.properties?.creditlimit as { value?: number })?.value;
const over = typeof raw === 'number' && raw >= 100_000;
const formatted = record.formattedValues?.creditlimit ?? '-';
return (
<span style={{ color: over ? 'var(--colorStatusDangerForeground1)' : 'inherit' }}>
{formatted}
</span>
);
}}
/>
</GridColumns>
<GridColumns>
<GridColumn ColumnName="fullname" />
<GridColumn ColumnName="creditlimit">
<ChildContent>
@{
var raw = context.PrimaryRecord
.GetValueOrDefault<MoneyValue>("creditlimit")?.Value;
var over = raw is decimal d && d >= 100_000m;
}
<span style="color: @(over ? "var(--colorStatusDangerForeground1)" : "inherit")">
@(context.PrimaryRecord.FormattedValues["creditlimit"] ?? "-")
</span>
</ChildContent>
</GridColumn>
</GridColumns>
Die Zelle kennen: CellTemplate
ChildContentErhält die Zeile, die jede Zelle teilt, sodass sie nicht erkennen kann, welche Spalte sie rendert – oder welche Rastersuche darin übereinstimmt. Wenn die Zelle wissen muss, liefert stattdessen ein. CellTemplate Sie erhält : GridColumnCellContext, Rowdie Zelle ColumnNameMetadata , und mit Value, dann DisplayValue würde die eingebaute Zelle zeigen, und Highlight(text), was markiert, was die Suche genau wie die eingebauten Zellen entspricht – den Suchbegriff im Text, Such- und Auswahlspalten sowie den gesamten Wert einer Zahlen- oder Datumsspalte, deren Vergleich gilt. Sie hat Vorrang, ChildContent wenn beide gesetzt sind. In React erhält a bereits die valueZelle metadata , und searchText: für Text übergeben <Highlighter>searchText, und für eine Zahl oder Geldspalte prüfen Sie sie mit parseNumericSearch und matchesNumericSearch, und für eine Datumsspalte mit parseDateSearch und matchesDateSearch – die den formatierten Text der Zelle statt ihres Werts nimmt, da der Tag, an dem ein Datum liegt, von der Zeitzone abhängt, in der es angezeigt wird, und vom Ort aus useLocale() – wobei der Wert mit markiert wird<HighlightFull>, wenn sie übereinstimmen.cellRenderer
React
Blazor
<GridColumn
columnName="emailaddress1"
cellRenderer={({ record, searchText }) => {
// Markieren Sie, was mit der Suche im Raster übereinstimmt, wie es die eingebauten Zellen tun.
const email = resolveColumnDisplayValue(record, 'emailaddress1') ?? '';
return (
<a href={`mailto:${email}`}>
<Highlighter text={email} searchText={searchText ?? null} />
</a>
);
}}
/>
<GridColumn ColumnName="emailaddress1">
<CellTemplate Context="cell">
<!-- Markieren Sie, was mit der Suche im Raster übereinstimmt, wie es die eingebauten Zellen tun. -->
<a href="mailto:@cell.DisplayValue">@cell.Highlight(cell.DisplayValue)</a>
</CellTemplate>
</GridColumn>
Elterndatensatz in SubGrids
Wenn das Gitter als ein SubGridmontiert wird, GridRowContext.ParentRecord wird der umgebende RecordContextDatensatz (der Elternteil des SubGrid) freigegeben. Greifen Sie in einer ChildContent Vorlage heran, wenn die bedingte Formatierung die Spalte einer Zeile mit der der Elternseite vergleichen muss – z. B. Kontakte markieren, deren industrycode nicht mit dem des Elternkontos übereinstimmt, oder Zeilen beschriften, die dem Eigentümer des Elternkontos gehören. null Auf einem eigenständigen MainGrid Konto, bei dem es keinen Elterndatensatz gibt.
<SubGrid RelationshipName="contact_customer_accounts">
<GridColumns>
<GridColumn ColumnName="fullname" TableName="contact" />
<GridColumn ColumnName="industrycode" TableName="contact">
<ChildContent>
@{
var rowIndustry = context.PrimaryRecord.FormattedValues
.GetValueOrDefault("industrycode");
var parentIndustry = context.ParentRecord?.FormattedValues
.GetValueOrDefault("industrycode");
var mismatch = parentIndustry is not null
&& rowIndustry is not null
&& rowIndustry != parentIndustry;
}
<span style="color: @(mismatch ? "var(--colorStatusDangerForeground1)" : "inherit")">
@(rowIndustry ?? "-")
</span>
</ChildContent>
</GridColumn>
</GridColumns>
</SubGrid>
Reaktionsparität
Die React-Seite bedeckt dieselbe Fläche wie cellRenderer's parentRecord Prop (CellRendererProps.parentRecord).
GridTemplateColumn
Verwenden GridTemplateColumn Sie, wenn eine Spalte nicht auf eine einzelne Dataverse-Spalte abgebildet ist – kombinieren Sie mehrere Rohwerte in einer Zelle, stellen Sie ein Statusabzeichen auf mehrere Felder dar oder geben Sie eine reine Dekorationsaktionszelle ohne jegliche Datenabhängigkeit aus. Im Gegensatz zu GridColumn, hat eine Template-Spalte kein ColumnName: deklariert die Spalten, über die der Renderer liest DependsOn , und das Framework fügt sie in die FetchXML-Projektion ein, sodass die Daten beim Ausführen Ihrer Vorlage landen ctx.Row.PrimaryRecord . Der erhält ChildContent ein GridTemplateColumnContext (verwende das Attribut Context="ctx" zur Bezeichnung), das die Zeile, den optionalen SubGrid-Elternteil und eine vorgefertigte DependsOnMetadata Abfrage enthält, die mit den von dir deklarierten Spaltennamen verbunden ist.
React
Blazor
<MainGrid tableName="contact">
<GridColumns>
{/* Kombinieren Sie Vorname + Nachname zu einem einzigen "Vollständigen Namen"
Zelle. dependsOn sagt dem Framework, welche Spalten die
Template-Reads, sodass sie in den Fetch projiziert werden.
sortBy verweist auf die Überschrift sortieren auf Nachname.
searchBy setzt beide in die Suche des Rasters; Der Markiermarker markiert die Übereinstimmung. */}
<GridTemplateColumn
displayName="Vollständiger Name"
dependsOn={['firstname', 'lastname']}
sortBy="lastname"
searchBy={['firstname', 'lastname']}
cellRenderer={({ record, searchText }) => {
const first = (record.properties?.firstname as { value?: string })?.value ?? '';
const last = (record.properties?.lastname as { value?: string })?.value ?? '';
return <strong><Highlighter text={`${first} ${last}`} searchText={searchText ?? null} /></strong>;
}}
/>
<GridColumn columnName="emailaddress1" />
</GridColumns>
</MainGrid>
<MainGrid TableName="contact">
<Columns>
<GridColumns>
<!-- Kombinieren Sie Vorname + Nachname zu einem einzigen "Vollständigen Namen"
Zelle. DependsOn sagt dem Framework, welche Spalten die
Template-Reads, sodass sie in den Fetch projiziert werden.
SortBy zeigt auf den Header Sort auf Lastname.
SearchBy fügt beide in die Suche des Rasters ein; Hervorheben markiert die Übereinstimmung. -->
<GridTemplateColumn Title="Vollständiger Name"
DependsOn="@(new[] { "firstname", "lastname" })"
SortBy="lastname"
SearchBy="@(new[] { "firstname", "lastname" })">
<ChildContent Context="ctx">
@{
var first = ctx.Row.PrimaryRecord
.GetValueOrDefault<StringValue>("firstname")?.Value ?? "";
var last = ctx.Row.PrimaryRecord
.GetValueOrDefault<StringValue>("lastname")?.Value ?? "";
}
<strong>@ctx.Highlight($"{first} {last}")</strong>
</ChildContent>
</GridTemplateColumn>
<GridColumn ColumnName="emailaddress1" />
</GridColumns>
</Columns>
</MainGrid>
Eine Vorlagenspalte ist nicht Teil der Suche des Rasters, es sei denn, man sagt an, nach welcher Methode man suchen soll. SearchBy (searchBy in React) nennt die Spalten: Sie werden automatisch abgerufen, mit den üblichen Regeln des Rasters für ihren Typ abgeglichen (Text beginnt mit der Suche oder enthält sie nach einem Einführung *; eine Zahlen- oder Datumsspalte wird verglichen) und im Suchfeld unter dem Titel der Vorlagenspalte aufgeführt. Die Spalten in DependsOn werden nur abgerufen, nie durchsucht – ein Statuscode hinter einem Abzeichen sollte nicht mit dem übereinstimmen, was jemand eingibt. Um zu markieren, was die Suche so wie die eingebauten Zellen, sollte man den Text der Zelle in Blazor darstellen ctx.Highlight(text) oder den Renderer searchText in <Highlighter> React weitergeben; beides ist für eine Spalte ohne SearchByleer .
Template column vs. GridColumn ChildContent
GridColumn ChildContent passt weiterhin eine gebundene Spalte an – Sorting, Edit Dispatch und die Spaltenkopfzeile sind alle von ihrem einzigen ColumnName. Greifen Sie nur GridTemplateColumn , wenn es keine einzelne zugrundeliegende Spalte gibt, an die man binden kann (zusammengesetzte Zellen, dekorative Aktionszellen, Statusabzeichen, die mehrere Felder kombinieren). Die beiden zu mischen ist in Ordnung – sie verweben sich in deklarierter Reihenfolge über das Spaltenset des Gitters.
Dekorative Säulen (keine Datenabhängigkeit)
Überspringe DependsOn komplett, wenn die Zelle reine Dekorationsinhalte wie Inline-Buttons oder Icons rendert. Das Gerüst montiert die Spalte weiterhin an der richtigen Position in der gerenderten Tabelle; Für diese Spalte wird nichts zur Serverprojektion hinzugefügt.
React
Blazor
{/* Reine Dekorations-Template-Spalte: keine Abhängigkeit von, dem Renderer
Liest nicht von der Reihe ab. Nützlich für Aktionstasten / Symbole. */}
<GridTemplateColumn
displayName=""
width="80px"
cellRenderer={({ record }) => (
<Button
icon={<MoreHorizontal16Regular />}
onClick={() => openContextMenu(record.id)}
/>
)}
/>
<!-- Reine Dekorations-Vorlagenspalte: kein DependsOn, der Renderer
Liest nicht von der Reihe ab. Nützlich für Aktionstasten / Symbole. -->
<GridTemplateColumn Title="" Width="80px">
<ChildContent Context="ctx">
<FluentButton IconStart="@(new Icons.Regular.Size16.MoreHorizontal())"
OnClick="@(() => OpenContextMenu(ctx.Row.PrimaryRecord.Id))" />
</ChildContent>
</GridTemplateColumn>
Inline-Edit-Vorlagen
Kombinieren Sie den GridTemplateColumnLesemodus ChildContent eines mit an EditChildContent , um die Spalte bearbeitbar zu machen, wenn der Editierbar-Schalter des Rasters aktiviert ist. Die Bearbeitungsvorlage erhält einen GridTemplateColumnEditContext — denselben Zeilenkontext wie die Lesevorlage (editCtx.Row.PrimaryRecord, der optionale editCtx.Row.ParentRecord in einem SubGrid, die editCtx.DependsOnMetadata Nachschlage) sowie einen imperativen editCtx.SetValue(columnName, value) Helfer.
EditChildContent ausgelöst wird, wenn das Raster bearbeitbar ist (AllowEdit="true" auf dem Raster plus der Benutzer hat im Zahnradmenü der Werkzeugleiste den Wechselschalter umgelegt), die Zeile nicht auf 'Pending-Delete' festgelegt ist und die Spalte selbst eine Bearbeitungsvorlage deklariert. Dekorative Template-Spalten, die das weglassen EditChildContent , bleiben auch im Bearbeitungsmodus lesegeschützt – nützlich für Aktionsspalten, die immer dieselben Buttons darstellen sollten.
Muster 1 — Standard-Editoren für Drop-in
Der häufigste Fall: Die Zelle besteht aus mehreren gebundenen Spalten, und du möchtest dem Benutzer erlauben, jede einzelne zu bearbeiten. Fügen Sie die Matching <TextEdit> / <NumberEdit> / Editoren <ColumnEdit> hinein EditChildContent – das Framework kaskadierend den primären Datensatz und das Matching EditContextValidator der Zeile in diesen Scope, sodass sich die Editoren für Dirty Tracking und Validierung genau so registrieren, wie sie es unter einer Schranke <GridColumn>von ChildContent. Keine zusätzliche Verkabelung erforderlich.
React
Blazor
<GridTemplateColumn
displayName="Vollständiger Name"
dependsOn={['firstname', 'lastname']}
sortBy="lastname"
// Schreibgeschützte Vorlage (existiert).
cellRenderer={({ record }) => {
const first = (record.properties?.firstname as { value?: string })?.value ?? '';
const last = (record.properties?.lastname as { value?: string })?.value ?? '';
return <strong>{first} {last}</strong>;
}}
// Vorlage bearbeiten: Löst aus, wenn der editierbare Schalter des Grids aktiviert ist
// UND die Zeile ist veränderlich. Zwei '<TextEdit>' Redakteure auf der Seite
// Nebenbei, und sie schalten automatisch zu Dirty-Tracking und Validierung um
// Genau wie sie es unter einer gebundenen Bindung tun<GridColumn>.
editRenderer={() => (
<div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>
<TextEdit columnName="firstname" displayLabelWhenAvailable={false} />
<TextEdit columnName="lastname" displayLabelWhenAvailable={false} />
</div>
)}
/>
<GridTemplateColumn Title="Vollständiger Name"
DependsOn="@(new[] { "firstname", "lastname" })"
SortBy="lastname">
<!-- Schreibgeschützte Vorlage (existiert). -->
<ChildContent Context="ctx">
<strong>
@(ctx.Row.PrimaryRecord.GetValueOrDefault<StringValue>("firstname")?.Value)
@(ctx.Row.PrimaryRecord.GetValueOrDefault<StringValue>("lastname")?.Value)
</strong>
</ChildContent>
<!-- Bearbeitungsvorlage: Löst aus, wenn der Editable-Schalter des Grids aktiviert ist
UND die Zeile ist veränderlich. Zwei '<TextEdit>' Redakteure auf der Seite
Nebenbei, und sie schalten automatisch zu Dirty-Tracking und Validierung um
Genau wie sie es unter einer gebundenen Bindung tun<GridColumn>. -->
<EditChildContent Context="editCtx">
<FluentStack Orientation="Orientation.Horizontal" HorizontalGap="6"
VerticalAlignment="VerticalAlignment.Center">
<TextEdit ColumnName="firstname"
DisplayLabelWhenAvailable="false"
DisplayTooltipWhenAvailable="false" />
<TextEdit ColumnName="lastname"
DisplayLabelWhenAvailable="false"
DisplayTooltipWhenAvailable="false" />
</FluentStack>
</EditChildContent>
</GridTemplateColumn>
Muster 2 — Benutzerdefiniertes Widget mit SetValue
Wenn die Editor-Oberfläche nicht 1:1 einer Dataverse-Spalte zugeordnet ist – also einem einzigen "First Last"-Textfeld, das in zwei Spalten geteilt wird, einem Schieberegler, der an mehrere Prozentfelder gebunden ist, einem benutzerdefinierten Date-Range-Picker, der Start + Ende schreibt – rendere du für jede betroffene Spalte deine eigene Eingabe und den Aufruf editCtx.SetValue(columnName, value) . Das Framework routet den Schreib an die richtige AliasedTableRecord (mit Punktnotation Link-Entitäten-Spaltennamen) und löst das ValueChanged Ereignis des Datensatzes aus, sodass Dirty-Tracking und die Warteschlange für ausstehende Aktualisierungen der Zeile die Änderung aufnehmen.
React
Blazor
<GridTemplateColumn
displayName="Vollständiger Name"
dependsOn={['firstname', 'lastname']}
sortBy="lastname"
cellRenderer={({ record }) => {
const first = (record.properties?.firstname as { value?: string })?.value ?? '';
const last = (record.properties?.lastname as { value?: string })?.value ?? '';
return <strong>{first} {last}</strong>;
}}
editRenderer={({ record, setValue }) => {
const first = (record.properties?.firstname as { value?: string })?.value ?? '';
const last = (record.properties?.lastname as { value?: string })?.value ?? '';
const combined = [first, last].filter(Boolean).join(' ');
return (
<Input
value={combined}
onChange={(_, data) => {
const next = data.value ?? '';
// Teilen Sie sich auf das erste Feld – alles danach landet im Nachnamen.
const idx = next.indexOf(' ');
const head = idx === -1 ? next : next.slice(0, idx);
const tail = idx === -1 ? '' : next.slice(idx + 1);
setValue('firstname', { $type: 'StringValue', value: head });
setValue('lastname', { $type: 'StringValue', value: tail || null });
}}
/>
);
}}
/>
<GridTemplateColumn Title="Vollständiger Name"
DependsOn="@(new[] { "firstname", "lastname" })"
SortBy="lastname">
<ChildContent Context="ctx">
@{
var first = ctx.Row.PrimaryRecord.GetValueOrDefault<StringValue>("firstname")?.Value;
var last = ctx.Row.PrimaryRecord.GetValueOrDefault<StringValue>("lastname")?.Value;
}
<strong>@first @last</strong>
</ChildContent>
<EditChildContent Context="editCtx">
@{
var combined =
(editCtx.Row.PrimaryRecord.GetValueOrDefault<StringValue>("firstname")?.Value ?? "")
+ " "
+ (editCtx.Row.PrimaryRecord.GetValueOrDefault<StringValue>("lastname")?.Value ?? "");
}
<FluentTextInput Value="@combined.Trim()" ValueChanged="@(next =>
{
// Teilen Sie sich auf das erste Feld – alles danach landet im Nachnamen.
var parts = next.Split(' ', 2);
editCtx.SetValue("firstname", new StringValue { Value = parts[0] });
editCtx.SetValue("lastname", new StringValue { Value = parts.Length > 1 ? parts[1] : null });
})" />
</EditChildContent>
</GridTemplateColumn>
Validierung auf dem imperativen Weg
Standard-Editoren wurden automatisch in EditChildContent die Register der Zeilen EditContextValidator eingefügt und nehmen am Validate-before-Save-Gate des Frameworks teil. Der Pfad editCtx.SetValueumgeht diese Pipeline – das Framework kann keine Werte validieren, die nicht von einem registrierten Editor stammen. Wenn dein benutzerdefiniertes Widget Constraints erzwingen muss, führe sie im ValueChanged Callback aus, bevor du aufrufst SetValue, oder greife wenn möglich auf das Drop-in-Editor-Muster zurück.
In einem SubGrid
Alles, was auf MainGrid gilt, funktioniert auf identisch auf SubGrid. Kombinieren Sie deklarierte Spalten mit Symbolleisten-Buttons im Buttons Renderfragment für ein fokussiertes Inline-Editing-Erlebnis, das auf die zugehörige Sammlung des übergeordneten Datensatzes zugeschnitten ist – und kombinieren Sie sie mit @@context.ParentRecord In-Cell-Vorlagen für bedingte Formatierung, die auf dem übergeordneten SubGrid basiert.
Pflicht. Logischer Name der Spalte; unterstützt die Punktnotation für getäuschte verknüpfte Entitäten-Spalten.
TableName
Optional. Logischer Name der Tabelle, deren Metadaten diese Spalte beschreiben. Erbt das Raster, TableName wenn es weggelassen wird.
Width
Optionale CSS-Länge für die Breite der Spalte.
Align
Optionale horizontale Ausrichtungsübersteuerung (Align.Start, Align.Center, Align.End). Greift auf den metadatenbasierten Standard zurück, wenn er weggelassen wird.
Title
Optionale Überschreibung des Header-Labels. Greift auf den lokalisierten Anzeigenamen der Spalte zurück.
HeaderTooltip
Optionales Header-Tooltip — nützlich zur Erklärung berechneter oder getäuschter Spalten. (Benannt, um die kleinschreibunsensitive Kollision mit dem vererbten Tooltip Bool-Parameter auf zu TemplateColumnvermeiden.)
Visible
Optional. false unterdrückt die Spalte aus der gerenderten Tabelle und aus der Serverprojektion, selbst wenn andere deklarierte Spalten vorhanden sind. Standardmäßig gilt true.
IsDefaultSortColumn / InitialSortDirection
Optional. Markiere eine deklarierte Spalte als Anfangssortierung des Gitters. Die Sortierrichtung ist standardmäßig aufsteigend.
ChildContent
Optionaler Empfang GridRowContextpro Zellvorlage . Rendert in jeder Körperzelle, wenn sie bereitgestellt wird; Zugriff auf die Zeile über @@context.PrimaryRecord und (in einem SubGrid) auf das Elternsystem über @@context.ParentRecord.
Parameter:ColumnName
Beschreibung:Pflicht. Logischer Name der Spalte; unterstützt die Punktnotation für getäuschte verknüpfte Entitäten-Spalten.
Parameter:TableName
Beschreibung:Optional. Logischer Name der Tabelle, deren Metadaten diese Spalte beschreiben. Erbt das Raster, TableName wenn es weggelassen wird.
Parameter:Width
Beschreibung:Optionale CSS-Länge für die Breite der Spalte.
Parameter:Align
Beschreibung:Optionale horizontale Ausrichtungsübersteuerung (Align.Start, Align.Center, Align.End). Greift auf den metadatenbasierten Standard zurück, wenn er weggelassen wird.
Parameter:Title
Beschreibung:Optionale Überschreibung des Header-Labels. Greift auf den lokalisierten Anzeigenamen der Spalte zurück.
Parameter:HeaderTooltip
Beschreibung:Optionales Header-Tooltip — nützlich zur Erklärung berechneter oder getäuschter Spalten. (Benannt, um die kleinschreibunsensitive Kollision mit dem vererbten Tooltip Bool-Parameter auf zu TemplateColumnvermeiden.)
Parameter:Visible
Beschreibung:Optional. false unterdrückt die Spalte aus der gerenderten Tabelle und aus der Serverprojektion, selbst wenn andere deklarierte Spalten vorhanden sind. Standardmäßig gilt true.
Beschreibung:Optional. Markiere eine deklarierte Spalte als Anfangssortierung des Gitters. Die Sortierrichtung ist standardmäßig aufsteigend.
Parameter:ChildContent
Beschreibung:Optionaler Empfang GridRowContextpro Zellvorlage . Rendert in jeder Körperzelle, wenn sie bereitgestellt wird; Zugriff auf die Zeile über @@context.PrimaryRecord und (in einem SubGrid) auf das Elternsystem über @@context.ParentRecord.
GridTemplateColumn-Parameter
Parameter
Beschreibung
Id
Optionale stabile Kennung. Wenn sie weggelassen wird, generiert das Framework automatisch eine Spalte basierend __template-{index} auf der Position der Vorlagenspalte unter den anderen Vorlagen. Gib eine explizite ID weiter, wenn deine Deklarationen sich dynamisch neu anordnen können.
Title
Erforderliches Header-Label. Keine gebundenen Spaltenmetadaten, von denen ein Standard hergeleitet werden könnte.
DependsOn
Optional. Logische Dataverse-Spaltennamen, die der Renderer aus der Zeile liest. Das Framework führt diese in die FetchXML-Projektion zusammen, sodass die Daten in ctx.Row.PrimaryRecord. Weggelassen / leer für dekorative Zellen.
SortBy
Optional. Logischer Spaltenname, um nach dem Klick auf den Header zu sortieren. Weggelassen = Header ist nicht sortierbar.
Width
Optionale CSS-Länge für die Breite der Spalte.
Align
Optionale horizontale Ausrichtungs-Übersteuerung. Standardmäßig ( Align.Start kein metadatenbasierter Standard, da es keinen zugrundeliegenden Spaltentyp gibt).
Tooltip
Optionaler Header-Tooltip-Text.
Visible
Optional. false unterdrückt die Spalte aus der gerenderten Tabelle UND entfernt ihre DependsOn Einträge aus der Serverprojektion. Standardmäßig gilt true.
ChildContent
Erforderlicher Empfang GridTemplateColumnContextpro Zellvorlage . Lesen Sie die Zeile über ctx.Row.PrimaryRecord (und in einem SubGrid die Elternseite über ctx.Row.ParentRecord); verwenden Sie ctx.DependsOnMetadata[name] für Spalten-Metadaten, wenn der Renderer sie benötigt.
EditChildContent
Optionale Bearbeitungsmodus-Vorlage erhält GridTemplateColumnEditContext. Wird aufgerufen, anstatt ChildContent wenn das Raster im Inline-Edit-Modus ist und die Zeile veränderbar ist. Derselbe Zeilenkontext wie die Lesevorlage plus editCtx.SetValue(name, value) für imperative Schreibvorgänge. Siehe oben Inline-Edit-Vorlagen für die beiden Autorenmuster.
Parameter:Id
Beschreibung:Optionale stabile Kennung. Wenn sie weggelassen wird, generiert das Framework automatisch eine Spalte basierend __template-{index} auf der Position der Vorlagenspalte unter den anderen Vorlagen. Gib eine explizite ID weiter, wenn deine Deklarationen sich dynamisch neu anordnen können.
Parameter:Title
Beschreibung:Erforderliches Header-Label. Keine gebundenen Spaltenmetadaten, von denen ein Standard hergeleitet werden könnte.
Parameter:DependsOn
Beschreibung:Optional. Logische Dataverse-Spaltennamen, die der Renderer aus der Zeile liest. Das Framework führt diese in die FetchXML-Projektion zusammen, sodass die Daten in ctx.Row.PrimaryRecord. Weggelassen / leer für dekorative Zellen.
Parameter:SortBy
Beschreibung:Optional. Logischer Spaltenname, um nach dem Klick auf den Header zu sortieren. Weggelassen = Header ist nicht sortierbar.
Parameter:Width
Beschreibung:Optionale CSS-Länge für die Breite der Spalte.
Parameter:Align
Beschreibung:Optionale horizontale Ausrichtungs-Übersteuerung. Standardmäßig ( Align.Start kein metadatenbasierter Standard, da es keinen zugrundeliegenden Spaltentyp gibt).
Parameter:Tooltip
Beschreibung:Optionaler Header-Tooltip-Text.
Parameter:Visible
Beschreibung:Optional. false unterdrückt die Spalte aus der gerenderten Tabelle UND entfernt ihre DependsOn Einträge aus der Serverprojektion. Standardmäßig gilt true.
Parameter:ChildContent
Beschreibung:Erforderlicher Empfang GridTemplateColumnContextpro Zellvorlage . Lesen Sie die Zeile über ctx.Row.PrimaryRecord (und in einem SubGrid die Elternseite über ctx.Row.ParentRecord); verwenden Sie ctx.DependsOnMetadata[name] für Spalten-Metadaten, wenn der Renderer sie benötigt.
Parameter:EditChildContent
Beschreibung:Optionale Bearbeitungsmodus-Vorlage erhält GridTemplateColumnEditContext. Wird aufgerufen, anstatt ChildContent wenn das Raster im Inline-Edit-Modus ist und die Zeile veränderbar ist. Derselbe Zeilenkontext wie die Lesevorlage plus editCtx.SetValue(name, value) für imperative Schreibvorgänge. Siehe oben Inline-Edit-Vorlagen für die beiden Autorenmuster.
Apply beginnt mit einem Filter in den folgenden Spalten:
E-Mail Telefon Vollständiger Name
Verwendet Zahlenvergleiche in den folgenden Spalten:
Alter
Verwendet Datums- oder Jahresvergleiche in den folgenden Spalten:
Geburtstag
Apply beginnt mit einem Filter in den folgenden Spalten:
E-Mail Telefon Vollständiger Name
Apply beginnt mit einem Filter in den folgenden Spalten:
E-Mail Telefon Vollständiger Name
Verwendet Zahlenvergleiche in den folgenden Spalten:
Alter
Verwendet Datums- oder Jahresvergleiche in den folgenden Spalten:
Geburtstag
Apply beginnt mit einem Filter in den folgenden Spalten: