diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml
index ced11ef25..f94ca5313 100644
--- a/.github/workflows/pull_request.yml
+++ b/.github/workflows/pull_request.yml
@@ -12,7 +12,7 @@ jobs:
steps:
- name: Create branch comment
if: ${{ github.base_ref == 'master' && contains(join(github.event.pull_request.labels.*.name, ''), 'merge-to-production') }}
- uses: peter-evans/create-or-update-comment@v1
+ uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043
with:
issue-number: ${{github.event.number}}
body: |
diff --git a/.github/workflows/pull_request_closed.yml b/.github/workflows/pull_request_closed.yml
index 7bdf9b920..0960834d2 100644
--- a/.github/workflows/pull_request_closed.yml
+++ b/.github/workflows/pull_request_closed.yml
@@ -1,15 +1,17 @@
name: Pull Request Closed
+
on:
pull_request:
branches: [master]
types: [closed]
+
jobs:
cherry_pick:
if: ${{github.event.pull_request.merged == true}}
runs-on: ubuntu-22.04
steps:
- name: Should create PR to production?
- uses: peter-evans/find-comment@v1
+ uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e
id: fc
with:
issue-number: ${{github.event.number}}
@@ -39,7 +41,7 @@ jobs:
echo "##[set-output name=branch;]$(echo ${BRANCH_NAME})"
- name: Failed cherry-pick
if: ${{ failure() }}
- uses: peter-evans/create-or-update-comment@v1
+ uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043
with:
issue-number: ${{github.event.number}}
body: |
@@ -47,18 +49,14 @@ jobs:
- name: pull-request
id: pr
if: steps.fc.outputs.comment-id != ''
- uses: repo-sync/pull-request@v2
+ uses: actions/checkout@v3
with:
- destination_branch: "production"
- source_branch: ${{ steps.cp.outputs.branch }}
- github_token: ${{ secrets.GITHUB_TOKEN }}
- pr_title: "Merge ${{ steps.cp.outputs.branch }} into production"
- pr_body: |
- *This is automatically generated PR*
- PR from master branch: #${{github.event.number}}. Once the change is merged, upload the changes to LIVE.
+ token: '${{ secrets.GITHUB_TOKEN }}'
+ run: |
+ gh pr create --base production --head ${{ steps.cp.outputs.branch }} --title "Merge ${{ steps.cp.outputs.branch }} into production" --body "Automatically generated PR from master branch: #${{github.event.number}}. Once the change is merged, upload the changes to LIVE."
- name: Post PR link
if: steps.pr.outputs.pr_url != ''
- uses: peter-evans/create-or-update-comment@v1
+ uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043
with:
issue-number: ${{github.event.number}}
body: |
diff --git a/_contentTemplates/common/ai-coding-assistant.md b/_contentTemplates/common/ai-coding-assistant.md
new file mode 100644
index 000000000..3384d2abe
--- /dev/null
+++ b/_contentTemplates/common/ai-coding-assistant.md
@@ -0,0 +1,3 @@
+#number-of-requests
+A Telerik [Subscription license](https://www.telerik.com/purchase/faq/licensing-purchasing) is recommended in order to use the Telerik Blazor AI Coding Assistant without restrictions. Perpetual license holders and trial users can make a [limited number of requests per year](slug:ai-overview#number-of-requests).
+#end
diff --git a/_contentTemplates/common/get-started.md b/_contentTemplates/common/get-started.md
index a59f43f57..eeb3892e8 100644
--- a/_contentTemplates/common/get-started.md
+++ b/_contentTemplates/common/get-started.md
@@ -208,4 +208,10 @@ This will make the license key available to all Telerik .NET apps that you devel
The [Telerik License Key](slug:installation-license-key) article provides additional details on installing and updating your Telerik license key in different scenarios. [Automatic license key maintenance](slug:installation-license-key#automatic-installation) is more effective and recommended in the long run.
+#end
+
+#ai-coding-assistant-ad
+
+Use the [Telerik AI Coding Assistant](slug:ai-overview) through the [Telerik Blazor MCP server](slug:ai-mcp-server) or the [Telerik Blazor GitHub Copilot extension](slug:ai-copilot-extension). These tools help you receive tips and generate code snippets that include Telerik UI for Blazor components and API.
+
#end
\ No newline at end of file
diff --git a/_contentTemplates/grid/state.md b/_contentTemplates/grid/state.md
index 5c64aefa3..9eaaadb69 100644
--- a/_contentTemplates/grid/state.md
+++ b/_contentTemplates/grid/state.md
@@ -716,14 +716,17 @@
+ Reorderable="true"
+ Resizable="true">
Reorder Price and Quantity
- Make Id Column Last
+ Resize Columns
- Reset Column Order
+ Reset Column Configuration
@@ -784,13 +787,32 @@
}
}
- private async Task ResetColumnOrder()
+ private async Task ResizeColumns()
+ {
+ if (GridRef != null)
+ {
+ var gridState = GridRef.GetState();
+ int newColumnWidth = 160;
+
+ foreach (GridColumnState columnState in gridState.ColumnStates)
+ {
+ columnState.Width = $"{newColumnWidth}px";
+ }
+
+ gridState.TableWidth = $"{newColumnWidth * gridState.ColumnStates.Count}px";
+
+ await GridRef.SetStateAsync(gridState);
+ }
+ }
+
+ private async Task ResetColumns()
{
if (GridRef != null)
{
var gridState = GridRef.GetState();
gridState.ColumnStates = new List();
+ gridState.TableWidth = null;
await GridRef.SetStateAsync(gridState);
}
diff --git a/ai/copilot-extension.md b/ai/copilot-extension.md
index 9ffaa2837..d82d0b07c 100644
--- a/ai/copilot-extension.md
+++ b/ai/copilot-extension.md
@@ -4,7 +4,7 @@ page_title: Telerik Blazor GitHub Copilot Extension
description: Learn how to add and use the Telerik Blazor GitHub Copilot extension as a Blazor AI coding assistant and code generator for better developer productivity. The Telerik Blazor GitHub Copilot extension provides proprietary context about Telerik UI for Blazor to AI-powered software.
slug: ai-copilot-extension
tags: telerik,blazor,ai
-published: False
+published: True
position: 10
---
@@ -55,15 +55,7 @@ The following list describes how your prompts may look like:
## Number of Requests
-> The usage limits below will take place after June 28, 2025. Until then, each customer with an active commercial or trial license can make up to 300 daily requests.
-
-The Telerik Blazor Copilot extension allows the following maximum number of requests, depending on your [Telerik license type](https://www.telerik.com/purchase/faq/licensing-purchasing):
-
-* Perpetual licenses: 50 requests per year
-* Subscription licenses: virtually unlimited number of requests with a fair use threshold of 300 requests per day
-* Trial licenses: 300 requests per trial per year. Activating the same trial for a new release does not grant additional 300 requests.
-
-> All Telerik AI tools share a single request limit for your Telerik account. For example, the Telerik Copilot extension and the Telerik MCP server both take up from the same usage quota.
+@[template](/_contentTemplates/common/ai-coding-assistant.md#number-of-requests)
## See Also
diff --git a/ai/mcp-server.md b/ai/mcp-server.md
index 2b5fb288a..8f1e365ca 100644
--- a/ai/mcp-server.md
+++ b/ai/mcp-server.md
@@ -4,7 +4,7 @@ page_title: Telerik Blazor MCP Server
description: Learn how to add and use the Telerik Blazor MCP Server as a Blazor AI coding assistant and code generator for better developer productivity. The Telerik Blazor MCP server provides proprietary context about Telerik UI for Blazor to AI-powered software.
slug: ai-mcp-server
tags: telerik,blazor,ai
-published: False
+published: True
position: 20
---
@@ -34,7 +34,7 @@ Use the documentation of your AI-powered MCP client to add the Telerik MCP serve
You also need to add your [Telerik licence key](slug:installation-license-key) as an `env` parameter in the `mcp.json` file. There are two options:
* (recommended) Use a `TELERIK_LICENSE_PATH` argument and point to your Telerik license file location.
-* Use a `TELERIK_LICENSE_KEY` argument and paste your Telerik license key. Make sure to [update the license key](slug:installation-license-key#license-key-updates) when necessary.
+* Use a `TELERIK_LICENSE` argument and paste your Telerik license key. Make sure to [update the license key](slug:installation-license-key#license-key-updates) when necessary.
### Visual Studio
@@ -167,20 +167,13 @@ The following list describes how your prompts may look like:
* "Telerik Generate a ComboBox for Blazor that shows a list of products. Create a Product class and generate sample data."
* "Telerik Show me sample code for a Blazor Grid with virtual scrolling for the rows and columns."
-
## Number of Requests
-> The usage limits below will take place after June 28, 2025. Until then, each customer with an active commercial or trial license can make up to 300 daily requests.
-
-The Telerik Blazor MCP Server allows the following maximum number of requests, depending on your [Telerik license type](https://www.telerik.com/purchase/faq/licensing-purchasing):
+@[template](/_contentTemplates/common/ai-coding-assistant.md#number-of-requests)
-* Perpetual licenses: 50 requests per year
-* Subscription licenses: virtually unlimited number of requests with a fair use threshold of 300 requests per day
-* Trial licenses: 300 requests per trial per year. Activating the same trial for a new release does not grant additional 300 requests.
+## Connect to Local AI Model
-> One prompt may trigger several requests to the MCP server, depending on the complexity.
->
-> All Telerik AI tools share a single request limit for your Telerik account. For example, the Telerik MCP server and the Telerik Copilot extension both take up from the same usage quota.
+You can use the Telerik Blazor MCP server with local large language models (LLM). For example, run your local model through [Ollama](https://ollama.com) and use a third-party package such as [MCP-LLM Bridge](https://github.com/patruff/ollama-mcp-bridge) to connect the model to the Telerik MCP server. This will allow you to use the Telerik AI Coding Assistant without a cloud-based AI model.
## See Also
diff --git a/ai/overview.md b/ai/overview.md
index 75828e8e1..9a1fb1f9e 100644
--- a/ai/overview.md
+++ b/ai/overview.md
@@ -4,7 +4,7 @@ page_title: Telerik Blazor AI Tooling Overview
description: Learn about the AI-powered developer tools that integrate with your IDE or code editor for greater productivity and enhanced developer experience.
slug: ai-overview
tags: telerik,blazor,ai
-published: False
+published: True
position: 1
---
@@ -19,8 +19,8 @@ The Telerik AI Coding Assistant is integrated in:
The major differences between these tools are:
-* The MCP server is more powerful and can handle more complex prompts that require several requests to the AI model. An MCP-enabled client like GitHub Copilot in **Agent** mode can make changes to your app and rebuild it to verify the AI suggestions.
-* The responses of the GitHub Copilot extension may contain shorter or partial code snippets and more explanations how to accomplish the task. When using the MCP server, the AI response is mostly code.
+* The MCP server is more powerful and can handle more complex prompts that require several requests to the AI model. An MCP-enabled client like Cursor or GitHub Copilot in **Agent** mode can directly suggest changes to your app and even rebuild it to verify the new AI generated code.
+* The responses of the GitHub Copilot extension may contain more explanations how to accomplish the task, and shorter or partial code snippets. When using the MCP server, the AI response is mostly code.
## Getting Started
@@ -29,11 +29,32 @@ To use the Telerik Blazor AI Coding Assistant, you need:
* A [Telerik user account](https://www.telerik.com/account/).
* An active [DevCraft or Telerik UI for Blazor license](https://www.telerik.com/purchase/blazor-ui) or a [Telerik UI for Blazor trial](https://www.telerik.com/blazor-ui).
* A [Blazor application that includes Telerik UI for Blazor](slug:blazor-overview#getting-started).
+* @[template](/_contentTemplates/common/ai-coding-assistant.md#number-of-requests)
-> A Telerik [Subscription license](https://www.telerik.com/purchase/faq/licensing-purchasing) is recommended in order to use the Telerik Blazor AI Coding Assistant:
->
-> * Subscription license holders can make an unlimited number of requests.
-> * Perpetual license holders and trial users have a limited number of requests per year.
+## Number of Requests
+
+> The usage limits below will take place after June 28, 2025. Until then, each customer with an active commercial or trial license can make up to 300 daily requests.
+
+The Telerik Blazor AI Conding Assistant allows the following maximum number of requests, depending on your [Telerik license type](https://www.telerik.com/purchase/faq/licensing-purchasing):
+
+* Perpetual licenses: 50 requests per year
+* Subscription licenses: virtually unlimited number of requests with a fair use threshold of 300 requests per day
+* Trial licenses: 300 requests per trial per year. Activating the same trial for a new release does not grant additional 300 requests.
+
+> All Telerik AI tools share a single request limit for your Telerik account. For example, the [Telerik Copilot extension](slug:ai-copilot-extension) and the [Telerik MCP server](slug:ai-mcp-server) both take up from the same usage quota.
+> When using the Telerik MCP server, one prompt may trigger several requests, depending on the prompt complexity.
+
+## Privacy
+
+The Telerik Blazor AI Coding Assistant operates under the following conditions:
+
+* The Assistant does not have access to your workspace and application code. Note that when using the Telerik MCP server (or any other MCP server), the LLM generates parameters for the MCP server request, which may include parts of your application code.
+* The Assistant does not use your prompts to train Telerik AI models.
+* The Assistant does not generate the actual responses and has no access to these responses. The Assistant only provides a better context that helps your selected model (for example, GPT, Gemini, Claude) provide better responses.
+* The Assistant does not associate your prompts to your Telerik user account. Your prompts and generated context are anonymized and stored for statistical and troubleshooting purposes.
+* The Assistant stores metrics about how often and how much you use it in order to ensure compliance with the [allowed number of requests that correspond to your current license](#number-of-requests).
+
+Make sure to also get familiar with the terms and privacy policy of your selected AI model and AI client.
## Next Steps
diff --git a/components/autocomplete/data-bind.md b/components/autocomplete/data-bind.md
index 75b85c3d0..f380ecd47 100644
--- a/components/autocomplete/data-bind.md
+++ b/components/autocomplete/data-bind.md
@@ -92,57 +92,7 @@ To bind the AutoComplete to a model:
}
````
-## Considerations
-
-### Reference
-
-The AutoComplete is a generic component and its type depends on the type of its `Data` and `Value`.
-
-
-````RAZOR String
-@*Reference when binding to a string collection*@
-
-
-
-@code{
- private TelerikAutoComplete AutoCompleteRef { get; set; }
-
- private string AutoCompleteValue { get; set; }
-
- private List Suggestions { get; set; } = new List { "first", "second", "third" };
-}
-````
-````RAZOR Model
-@*Reference when binding to a model collection*@
-
-
-
-@code{
- private TelerikAutoComplete AutoCompleteRef { get; set; }
-
- private string AutoCompleteValue { get; set; }
-
- private List Suggestions { get; set; } = new List
- {
- new SuggestionsModel { Suggestion = "first", SomeOtherField = 1 },
- new SuggestionsModel { Suggestion = "second", SomeOtherField = 2 },
- new SuggestionsModel { Suggestion = "third", SomeOtherField = 3 }
- };
-
- public class SuggestionsModel
- {
- public string Suggestion { get; set; }//the auto complete needs only the string field
- public int SomeOtherField { get; set; }
- }
-}
-````
-
-### Missing Data
+## Missing Data
The AutoComplete is, essentially, a textbox. This means that its `Value` is always a string and it is up to you to bind and/or use it. The `Data` parameter, however, is required for the functionality of the component, and it must never be `null`. If there are no suggestions that you wish to provide to the user, consider using a regular TextBox, or creating an empty collection.
diff --git a/components/autocomplete/overview.md b/components/autocomplete/overview.md
index acbe6b685..92d6411f5 100644
--- a/components/autocomplete/overview.md
+++ b/components/autocomplete/overview.md
@@ -145,9 +145,7 @@ The AutoComplete provides the following popup settings:
## AutoComplete Reference and Methods
-The AutoComplete is a generic component and its type is determined by the type of the model you use as its data source. You can find examples in the [Data Bind - Considerations](slug:autocomplete-databind#considerations) article.
-
-Add a reference to the component instance to use the [AutoComplete's methods](slug:Telerik.Blazor.Components.TelerikAutoComplete-1).
+Add a reference to the component instance to use the [AutoComplete's methods](slug:Telerik.Blazor.Components.TelerikAutoComplete-1). Note that the [AutoComplete is a generic component](slug:common-features-data-binding-overview#component-type).
@[template](/_contentTemplates/dropdowns/methods.md#methods-list)
diff --git a/components/barcodes/qrcode/overview.md b/components/barcodes/qrcode/overview.md
index 69e97a3d0..1ce01892c 100644
--- a/components/barcodes/qrcode/overview.md
+++ b/components/barcodes/qrcode/overview.md
@@ -16,19 +16,16 @@ The generated image from the component is a machine-readable label that contains
## Creating Blazor QRCode
-1. Add the `TelerikQRCode` tag to add the component to your razor page.
+1. Use the `TelerikQRCode` tag to add the component to your razor page.
+1. Set the `Value` parameter, according to the [encoding recommendations](slug:qrcode-encoding).
+1. Set the `Size` parameter, depending on the expected scanning distance and the required data capacity.
+1. (optional) Define a [QRCode overlay type](slug:qrcode-qr-code-types)).
-1. Set the `Value` property.
-
-1. Set its `Size` property.
-
-1. Optionally, choose a `QRCode Type` (one of the [types we support](slug:qrcode-qr-code-types)).
-
->caption A basic configuration of the Telerik QRCode
+>caption Basic Telerik QRCode
````RAZOR
-
+
````
@@ -58,7 +55,7 @@ The Blazor Barcode provides various parameters that allow you to configure the c
| `QRCodeEncoding` | `enum` | The encoding mode used to encode the value. |
| `QRCodeErrorCorrection` | `enum` | The error correction level used to encode the value. |
| `Value` | `string` | Defines the initial value of the QRCode. |
-| `Size` | `string` | Specifies the size (`Width` and `Height`) of a QR code in pixels (i.e. "200px") as the QRCode is a square. You can read more details for the dimension properties in the [Dimensions article](slug:common-features/dimensions). Setting both `Size` and `Width` and/or `Height` will throw an error. Setting different values to `Width` and `Height` will also cause an issue. |
+| `Size` | `string` | Specifies the size (`Width` and `Height`) of a QR code in pixels (i.e. "200px") as the QRCode is a square. You can read more details for the dimension properties in the [Dimensions article](slug:common-features/dimensions). Setting both `Size` and `Width` and/or `Height` will throw an error. Setting different values to `Width` and `Height` will also cause an issue. To set an optimal `Size`, consider the expected scanning distance and data capacity. |
| `Width` | `string` | Sets the width of the QRCode. If `Height` is set and the `Size` property is not set, the same value as `Width` should be set to `Height`. |
| `Height` | `string` | Sets the height of the QRCode. If `Height` is set and the `Size` property is not set, the same value as `Height` should be set to `Width`. |
| `Class` | `string` | The CSS class that will be rendered on the main wrapping element of the QRCode component. |
@@ -84,7 +81,7 @@ The nested `QRCodeBorder` tag exposes parameters that enable you to customize th
| Parameter | Type | Description |
| ----------- | ----------- | ----------- |
| `Color` | `string` | The color of the border. Accepts a valid CSS color string, including HEX and RGB. |
-| `Width` | `double` | The width of the border in pixels. By default the border width is set to zero which means that the border will not be visible. |
+| `Width` | `double` | The width of the border in pixels. The default value is `0` and the border is not visible. The QR Code border is part of the component `Size`. Thus, a wider border may require a larger `Size`. |
## Next Steps
diff --git a/components/buttongroup/buttons.md b/components/buttongroup/buttons.md
index 5e446dd68..019739554 100644
--- a/components/buttongroup/buttons.md
+++ b/components/buttongroup/buttons.md
@@ -10,12 +10,45 @@ position: 5
# ButtonGroup Buttons
-The ButtonGroup component supports two types of buttons that have different behavior:
+The ButtonGroup component supports two types of buttons that have different behaviors:
-* [`ButtonGroupToggleButton`](#buttongroup-togglebutton)
* [`ButtonGroupButton`](#buttongroup-button)
+* [`ButtonGroupToggleButton`](#buttongroup-togglebutton)
+
+You can add the desired button instances by declaring the dedicated button tags. Additionally, you can individually configure their [appearance](slug:buttongroup-appearance), [enabled/disabled state](#disabled-state) and [visibility](#visibility) through the parameters of each button tag.
+
+## ButtonGroup Button
+
+The `ButtonGroupButton` does not change its visual state when clicked. It behaves as a regular button and does not support selection.
+
+The `ButtonGroupButton` inherits the parameters and behavior of the [Telerik UI for Blazor Button](slug:components/button/overview) component.
+
+>caption Using Buttons in a group
+
+````RAZOR
+
+ Button 1
+ Button 2
+ Button 3
+
-You can add the desired button instances by declaring the dedicated button tags. Additionally, you can individually configure their [appearance](slug:buttongroup-appearance), [enabled/disabled state](#disabled-state) and [visibility](#visibility) through the parameters each button tag exposes.
+@code {
+ private void OnButton1Click()
+ {
+ // ...
+ }
+
+ private void OnButton2Click()
+ {
+ // ...
+ }
+
+ private void OnButton3Click()
+ {
+ // ...
+ }
+}
+````
## ButtonGroup ToggleButton
@@ -23,11 +56,39 @@ The `ButtonGroupToggleButton` becomes selected when clicked and deselects when a
The `ButtonGroupToggleButton` inherits the parameters and behavior of the [`TelerikToggleButton`](slug:togglebutton-overview) component.
-## ButtonGroup Button
+>caption Using ToogleButtons in a group
-The `ButtonGroupButton` does not change its visual state when clicked. It behaves as a regular button and does not support selection.
+````RAZOR
+
+ Toggle Button 1
+ Toggle Button 2
+ Toggle Button 3
+
-The `ButtonGroupButton` inherits the parameters and behavior of the [Telerik UI for Blazor Button](slug:components/button/overview) component.
+@code {
+ private bool ToggleButton1Selected { get; set; } = true;
+ private bool ToggleButton2Selected { get; set; }
+ private bool ToggleButton3Selected { get; set; }
+
+ private void OnToggleButton1Click()
+ {
+ // ...
+ }
+
+ private void OnToggleButton2Click()
+ {
+ // ...
+ }
+
+ private void OnToggleButton3Click()
+ {
+ // ...
+ }
+}
+````
## Disabled State
@@ -37,13 +98,18 @@ To disable a button, set its `Enabled` attribute to `false`.
````RAZOR
- Enabled
- Disabled
- Enabled
- Disabled
+ Enabled Button
+ Disabled Button
+ Enabled ToggleButton
+ Enabled ToggleButton
+ Disabled ToggleButton
-````
+@code {
+ private bool ToggleButton1Selected { get; set; } = true;
+ private bool ToggleButton2Selected { get; set; }
+}
+````
## Visibility
@@ -53,13 +119,26 @@ You can set the `Visible` parameter of individual buttons to `false` to hide the
````RAZOR
- First
- Hidden
- Third
- Fourth
+ Button
+ Button Hidden
+ ToggleButton
+ ToggleButton Hidden
+
+
+
+
+Show Hidden Buttons
+
+@code {
+ private bool ShowHiddenButtons { get; set; }
+
+ private bool ToggleButton1Selected { get; set; } = true;
+ private bool ToggleButton2Selected { get; set; }
+}
````
## See Also
- * [Live Demo: Button Types](https://demos.telerik.com/blazor-ui/buttongroup/button-types)
\ No newline at end of file
+ * [Live Demo: Button Types](https://demos.telerik.com/blazor-ui/buttongroup/button-types)
diff --git a/components/combobox/data-bind.md b/components/combobox/data-bind.md
index f8e07d49f..1a236bedf 100644
--- a/components/combobox/data-bind.md
+++ b/components/combobox/data-bind.md
@@ -23,7 +23,6 @@ There are also some considerations you may find useful, such as showing the `Pla
* [Considerations](#considerations)
* [Value Out of Range](#value-out-of-range)
- * [Component Reference](#component-reference)
* [Missing Value or Data](#missing-value-or-data)
## Strings and Value Types
@@ -105,7 +104,7 @@ To bind the ComboBox to a model:
## Considerations
-The ComboBox component attempts to infer the type of its model and value based on the provided `Data` and initial `Value`. This affects the way its [reference is obtained](#component-reference) and what happens [if you can't provide data or a value](#missing-value-or-data). Providing a [value that is not in the data source](#value-out-of-range) needs to be taken into account be the app, because the component will not change it.
+The ComboBox component attempts to infer the type of its model and value based on the provided `Data` and initial `Value`. This affects the way its [reference is obtained](slug:common-features-data-binding-overview#component-type) and what happens [if you can't provide data or a value](#missing-value-or-data). Providing a [value that is not in the data source](#value-out-of-range) needs to be taken into account by the app, because the component will not change it.
### Value Out of Range
@@ -119,63 +118,6 @@ Handling such "unexpected" values is up to the application - for example, throug
When `AllowCustom="true"`, what the user types in the input will be set to the `Value` of the component regardless of the data source.
-### Component Reference
-
-The ComboBox is a generic component and its type depends on the type of its `Data` and `Value`.
-
-
-````RAZOR String
-@*ComboBox reference when binding to a string collection*@
-
-
-
-
-@code {
- private TelerikComboBox? ComboBoxRef { get; set; }
-
- private List ComboBoxData = new List() { "first", "second", "third" };
-
- private string ComboBoxValue { get; set; } = string.Empty;
-
- protected override void OnInitialized()
- {
- ComboBoxValue = "third";
- }
-}
-````
-````RAZOR Model
-@*ComboBox reference when binding to a model collection*@
-
-
-
-
-@code {
- private TelerikComboBox? ComboBoxRef { get; set; }
-
- private IEnumerable ComboBoxData = Enumerable.Range(1, 20)
- .Select(x => new ComboBoxItem { MyTextField = "Item " + x, MyValueField = x });
-
- private int ComboBoxValue { get; set; }
-
- protected override void OnInitialized()
- {
- ComboBoxValue = 3;
- }
-
- public class ComboBoxItem
- {
- public int MyValueField { get; set; }
- public string MyTextField { get; set; } = string.Empty;
- }
-}
-````
-
### Missing Value or Data
In case you cannot provide strongly-typed `Value` or `Data` at compile time, you need to set the corresponding type properties to the `TItem` and `TValue` properties as shown below.
diff --git a/components/combobox/overview.md b/components/combobox/overview.md
index 4dfa3234a..da2113065 100644
--- a/components/combobox/overview.md
+++ b/components/combobox/overview.md
@@ -145,9 +145,8 @@ The ComboBox provides the following popup settings:
## ComboBox Reference and Methods
-The ComboBox is a generic component and its type is determined by the type of the model you pass to it, and the type of its value field. You can find examples in the [Data Bind - Considerations](slug:components/combobox/databind#considerations) article.
+Add a reference to the component instance to use the [ComboBox's methods](slug:Telerik.Blazor.Components.TelerikComboBox-2). Note that the [ComboBox is a generic component](slug:common-features-data-binding-overview#component-type).
-Add a reference to the component instance to use the [ComboBox's methods](slug:Telerik.Blazor.Components.TelerikComboBox-2).
@[template](/_contentTemplates/dropdowns/methods.md#methods-list)
diff --git a/components/dockmanager/events.md b/components/dockmanager/events.md
index aba596d3a..1ce9a6502 100644
--- a/components/dockmanager/events.md
+++ b/components/dockmanager/events.md
@@ -16,6 +16,7 @@ This article explains the events available in the Telerik DockManager for Blazor
* [OnUndock](#ondock)
* [VisibleChanged](#visiblechanged)
* [SizeChanged](#sizechanged)
+* [UnpinnedSizeChanged](#unpinnedsizechanged)
* [OnPaneResize](#onpaneresize)
* [State Events](#state-events)
* [OnPin](#onpin)
@@ -53,9 +54,13 @@ The `VisibleChanged` event is fired when the user tries to hide a given pane. Yo
The `SizeChanged` event is triggered when the `Size` parameter of the corresponding pane is changed.
+## UnpinnedSizeChanged
+
+The `UnpinnedSizeChanged` event is triggered when the `UnpinnedSize` parameter of the corresponding pane is changed.
+
## OnPaneResize
-The `OnPaneResize` event is fired when any pane is resized. It lets you respond to that change if needed - for example, call the `.Refresh()` method of a chart or otherwise repaint a child component in the content. You can also use it to, for example, update the saved [state](slug:dockmanager-state) for your users.
+The `OnPaneResize` event is fired when a pane is resized, except unpinned panes. It lets you respond to that change if needed - for example, call the `.Refresh()` method of a chart or otherwise repaint a child component in the content. You can also use it to, for example, update the saved [state](slug:dockmanager-state) for your users.
The event handler receives as an argument an `DockManagerPaneResizeEventArgs` object that contains:
@@ -119,9 +124,13 @@ The event handler receives as an argument an `DockManagerUnpinEventArgs` object
Pane 1. Undocking is allowed. Docking over it is cancelled.
+ UnpinnedSizeChanged is handled.
+ Current UnpinnedSize: @Pane1UnpinnedSize
@@ -195,8 +204,9 @@ The event handler receives as an argument an `DockManagerUnpinEventArgs` object
@code {
- private TelerikDockManager DockManagerRef { get; set; }
+ private TelerikDockManager? DockManagerRef { get; set; }
+ private string Pane1UnpinnedSize { get; set; } = "360px";
private bool Pane4Visible { get; set; } = true;
private bool FloatingPaneVisible { get; set; } = true;
@@ -246,6 +256,13 @@ The event handler receives as an argument an `DockManagerUnpinEventArgs` object
DockManagetEventLog.Insert(0, $"Pane {args.PaneId} was resized to {args.Size}.");
}
+ private void Pane1UnpinnedSizeChanged(string newUnpinnedSize)
+ {
+ Pane1UnpinnedSize = newUnpinnedSize;
+
+ DockManagetEventLog.Insert(0, $"Pane Pane 1 was resized to {newUnpinnedSize} while unpinned.");
+ }
+
private void OnPaneUnpin(DockManagerUnpinEventArgs args)
{
if (args.PaneId == "Pane4")
@@ -282,4 +299,4 @@ The event handler receives as an argument an `DockManagerUnpinEventArgs` object
## See Also
-* [DockManager Overview](slug:dockmanager-overview)
\ No newline at end of file
+* [DockManager Overview](slug:dockmanager-overview)
diff --git a/components/dockmanager/overview.md b/components/dockmanager/overview.md
index 64eb0507e..bfa6c429c 100644
--- a/components/dockmanager/overview.md
+++ b/components/dockmanager/overview.md
@@ -130,6 +130,7 @@ The following table lists the Dock Manager parameters. Also check the [DockManag
| `Size` | `string` | Determines the size of the splitter pane. |
| `Unpinnable` | `bool` (`false`) | Determines whether the pane can be unpinned. |
| `Unpinned` | `bool` (`true`) | Determines whether the pane is unpinned. |
+| `UnpinnedSize` | `string` | Determines the size of the splitter pane when it is unpinned. |
| `Visible` | `bool` (`true`) | Determines whether the tab/pane is rendered. |
### DockManagerSplitPane Parameters
diff --git a/components/dropdownlist/data-bind.md b/components/dropdownlist/data-bind.md
index f3a2d27f9..35c7249a4 100644
--- a/components/dropdownlist/data-bind.md
+++ b/components/dropdownlist/data-bind.md
@@ -23,7 +23,6 @@ There are also some considerations you may find useful, such as showing the `Def
* [Considerations](#considerations)
* [Value Out of Range](#value-out-of-range)
- * [Component Reference](#component-reference)
* [Missing Value or Data](#missing-value-or-data)
## Strings or Value Types
@@ -93,7 +92,7 @@ To bind the DropDownList to a model:
## Considerations
-The DropDownList component attempts to infer the type of its model and value based on the provided `Data` and initial `Value`. This affects the way its [reference is obtained](#component-reference) and what happens [if you can't provide data or a value](#missing-value-or-data). Providing a [value that is not in the data source](#value-out-of-range) needs to be taken into account be the app, because the component will not change it.
+The DropDownList component attempts to infer the type of its model and value based on the provided `Data` and initial `Value`. This affects the way its [reference is obtained](slug:common-features-data-binding-overview#component-type) and what happens [if you can't provide data or a value](#missing-value-or-data). Providing a [value that is not in the data source](#value-out-of-range) needs to be taken into account by the app, because the component will not change it.
### Value Out of Range
@@ -102,57 +101,6 @@ When the `Value` the application provides does not match any of the values prese
If you have set the `DefaultText` and the `Value` matches the `default` value of the type (for example, `0` for an `int` or `null` for an `int?` or `string`), you will see the `DefaultText`. A `Value` that is non-`default` will not show the `DefaultText`.
Handling such "unexpected" values is up to the application - for example, through defensive checks, or through form validation, or by first checking what is present in the data source before setting a new `Value`.
-
-### Component Reference
-
-The DropDownList is a generic component and its type depends on the type of its `Data` and `Value`.
-
-
-````RAZOR String
-
-
-@code {
- private TelerikDropDownList? DropDownListRef { get; set; }
-
- private List DropDownListData = new List() { "first", "second", "third" };
-
- private string DropDownListValue { get; set; } = string.Empty;
-
- protected override void OnInitialized()
- {
- DropDownListValue = "second";
- }
-}
-````
-````RAZOR Model
-
-
-@code {
- private TelerikDropDownList? DropDownListRef { get; set; }
-
- private int DropDownListValue { get; set; }
-
- private IEnumerable DropDownListData = Enumerable.Range(1, 20)
- .Select(x => new DropDownListItem { Text = $"Item {x}", Value = x });
-
- protected override void OnInitialized()
- {
- DropDownListValue = 3;
- }
-
- public class DropDownListItem
- {
- public int Value { get; set; }
- public string Text { get; set; } = string.Empty;
- }
-}
-````
### Missing Value or Data
diff --git a/components/dropdownlist/overview.md b/components/dropdownlist/overview.md
index 561965a5a..e40d20d5d 100644
--- a/components/dropdownlist/overview.md
+++ b/components/dropdownlist/overview.md
@@ -145,9 +145,8 @@ The DropDownList provides the following popup settings:
## DropDownList Reference and Methods
-The DropDownList is a generic component and its type comes from the model it is bound to and from the value field type. See the [Component Reference](slug:components/dropdownlist/databind#component-reference) section in the Data Binding article for details and examples.
+Add a reference to the component instance to use the [DropDownList's methods](slug:Telerik.Blazor.Components.TelerikDropDownList-2). Note that the [DropDownList is a generic component](slug:common-features-data-binding-overview#component-type).
-Add a reference to the component instance to use the [DropDownList's methods](slug:Telerik.Blazor.Components.TelerikDropDownList-2).
@[template](/_contentTemplates/dropdowns/methods.md#methods-list)
diff --git a/components/editor/ai-integration/integration-with-inline-prompt.md b/components/editor/ai-integration/integration-with-inline-prompt.md
index 7b00ac426..39ef15a80 100644
--- a/components/editor/ai-integration/integration-with-inline-prompt.md
+++ b/components/editor/ai-integration/integration-with-inline-prompt.md
@@ -64,7 +64,7 @@ The Editor allows customizing some of the integrated Inline Prompt's settings. F
| Parameter | Type and Default value | Description |
|-----------|------------------------|-------------|
-| `SystemPrompt` | `string` | The system prompt that will be passed to the integrated Inline Prompt. If not provided, the Inline Prompt will use its [default `SystemPrompt` value](slug:Inline Prompt-overview#Inline Prompt-parameters). |
+| `SystemPrompt` | `string` | The system prompt that will be passed to the integrated Inline Prompt. If not provided, the Inline Prompt will use its [default `SystemPrompt` value](slug:aiprompt-overview#aiprompt-parameters). |
| `Commands` | `List` | The commands displayed within the Commands view. If not set the Inline Prompt will use the [default predefined commands](slug:editor-ai-integration-overview#ai-integration-capabilities). |
>caption Customizing the Inline Prompt in the Editor
diff --git a/components/form/formgroups.md b/components/form/formgroups.md
index 5ff7da282..5919bfc08 100644
--- a/components/form/formgroups.md
+++ b/components/form/formgroups.md
@@ -25,7 +25,7 @@ The `FormGroup` tag exposes the following parameters:
* `Columns` - `int` - defines the number of columns in the group.
-* `ColumnSpacing` - `string` - defines the space between the editors in the group.
+* `ColumnSpacing` - `string` - defines the horizontal space between the editors in the group.
## Example - Organize FormItems into Groups
@@ -51,7 +51,7 @@ You can organize some FormItems into logical groups. You can configure the label
-
+
diff --git a/components/form/overview.md b/components/form/overview.md
index 57643d171..989fe67a8 100644
--- a/components/form/overview.md
+++ b/components/form/overview.md
@@ -207,7 +207,7 @@ The [Blazor Form](https://demos.telerik.com/blazor-ui/form/overview) exposes mul
|-----------|------------------------|-------------|
| `ButtonsLayout` | `FormButtonsLayout` enum (`Start`) | Determines the position and width of all Form buttons. See [Form Buttons](slug:form-formitems-buttons). |
| `Columns` | `int` | Defines the number of columns in the Form. See the [Columns](slug:form-columns) article for more information |
-| `ColumnSpacing` | `string` | Defines the amout of vertical space between the Columns. See the [Columns](slug:form-columns) article for more information. |
+| `ColumnSpacing` | `string` | Defines the amout of horizontal space between the Columns. See the [Columns](slug:form-columns) article for more information. |
| `Orientation` | `FormOrientation` enum (`Vertical`) | Determines the position of each label with regard to its editor. See [Orientation](slug:form-orientation) for more information. |
### Styling and Appearance
diff --git a/components/form/validation.md b/components/form/validation.md
index 81d5171fb..f092d624f 100644
--- a/components/form/validation.md
+++ b/components/form/validation.md
@@ -133,7 +133,6 @@ You can use the built-in `DataAnnotationsValidator` that comes with the Blazor f
-
@code {
public Person person { get; set; } = new Person();
@@ -158,8 +157,7 @@ You can use the
-````RAZOR
+````RAZOR.skip-repl
@using System.Dynamic
@using System.ComponentModel.DataAnnotations
@@ -228,50 +226,122 @@ When using a model with nested objects and fields, specify their `Field` setting
### Fluent Validation
-You can use third-party validation libraries that integrate with the standard `EditContext` such as FluentValidation together with the Telerik Form for Blazor.
+You can use third-party validation libraries that integrate with the standard `EditContext` such as [FluentValidation](https://fluentvalidation.net/) together with the Telerik Form for Blazor.
->note Such third party tools are not included with the Telerik UI for Blazor package. Your project must reference their NuGet packages explicitly. The code snippet below will not run unless you install the an appropriate package first. You can find some in their official documentation.
+The example below:
+* Requires the [`Blazored.FluentValidation` NuGet package](https://www.nuget.org/packages/Blazored.FluentValidation). Also refer to the [FluentValidation documentation](https://docs.fluentvalidation.net/en/latest/blazor.html).
+* Shows how to pass `ValueExpression` from a parent component to optional custom child components in a [Form item template](slug:form-formitems-template) or a [Grid editor template](slug:grid-templates-editor). If the `ValueExpression` is not passed correctly, the app will throw [exception similar to: `Cannot validate instances of type 'ComponentName'. This validator can only validate instances of type 'ModelClassName'`](slug:form-kb-fluent-validation-cannot-validate-instances-of-type).
>caption Using FluentValidation
-
-````RAZOR
-@using Microsoft.AspNetCore.Components.Forms
-@using FluentValidation
+````RAZOR Home.razor
@using Blazored.FluentValidation
+@using FluentValidation
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@FormSubmitResult
@code {
- public EditContext EditContext {get; set; }
- public Customer MyModel { get; set; } = new Customer();
- public CustomerValidator Validator { get; set; } = new CustomerValidator();
+ private Person PersonToEdit { get; set; } = new();
+
+ public PersonValidator PersonFluentValidator { get; set; } = new();
- protected override void OnInitialized()
+ private string FormSubmitResult { get; set; } = string.Empty;
+
+ private void LastNameChanged(string newLastName)
{
- EditContext = new EditContext(MyModel);
- base.OnInitialized();
+ PersonToEdit.LastName = newLastName;
}
- public class Customer
+ private void OnFormValidSubmit()
{
- public string FirstName { get; set; }
- public string LastName { get; set; }
+ FormSubmitResult = $"Form Submit Success at {DateTime.Now.ToString("HH:mm:ss")}";
+ }
+
+ public class PersonValidator : AbstractValidator
+ {
+ public PersonValidator()
+ {
+ RuleFor(customer => customer.FirstName).NotEmpty().MinimumLength(2).MaximumLength(60);
+ RuleFor(customer => customer.MiddleName).NotEmpty().MaximumLength(60);
+ RuleFor(customer => customer.LastName).NotEmpty().MinimumLength(2).MaximumLength(60);
+ }
+ }
+
+ public class Person
+ {
+ public int Id { get; set; }
+
+ public string FirstName { get; set; } = string.Empty;
+
+ public string MiddleName { get; set; } = string.Empty;
+
+ public string LastName { get; set; } = string.Empty;
}
+}
+````
+````RAZOR TextBox.razor
+@using System.Linq.Expressions
+
+
+
+@code {
+ [Parameter]
+ public string Value { get; set; } = string.Empty;
+
+ [Parameter]
+ public EventCallback ValueChanged { get; set; }
+
+ [Parameter]
+ public Expression>? ValueExpression { get; set; }
- public class CustomerValidator : AbstractValidator
+ [Parameter]
+ public string Id { get; set; } = string.Empty;
+
+ private async Task TextBoxValueChanged(string newValue)
{
- public CustomerValidator()
+ Value = newValue;
+
+ if (ValueChanged.HasDelegate)
{
- RuleFor(customer => customer.FirstName).NotEmpty().MaximumLength(50);
- RuleFor(customer => customer.LastName).NotEmpty().MaximumLength(50);
+ await ValueChanged.InvokeAsync(newValue);
}
}
}
diff --git a/components/grid/editing/incell.md b/components/grid/editing/incell.md
index 570f0a1c3..07a8552ba 100644
--- a/components/grid/editing/incell.md
+++ b/components/grid/editing/incell.md
@@ -72,6 +72,8 @@ This section explains what happens when the user tries to perform another data o
* If the validation is satisfied, then editing completes and the component fires `OnUpdate`.
* If the validation is not satisfied, then editing aborts and the component fires `OnCancel`.
+Deleting items that are currently in edit mode [fires `OnDelete` with a cloned data item instance](slug:grid-editing-overview#delete-operations).
+
### Selection
To enable [row selection](slug:grid-selection-row) with in-cell edit mode, use a [checkbox column](slug:components/grid/columns/checkbox). More information on that can be read in the [Row Selection](slug:grid-selection-row#selection-and-editing-modes) article.
diff --git a/components/grid/editing/inline.md b/components/grid/editing/inline.md
index 047e99ba5..96490aee5 100644
--- a/components/grid/editing/inline.md
+++ b/components/grid/editing/inline.md
@@ -54,6 +54,8 @@ This section explains what happens when the component is already in add or edit
If the component is already in add or edit mode, and the user tries to perform another data operation, then editing aborts and the component fires `OnCancel`.
+Deleting items that are currently in edit mode [fires `OnDelete` with a cloned data item instance](slug:grid-editing-overview#delete-operations).
+
## Examples
### Basic
diff --git a/components/grid/editing/overview.md b/components/grid/editing/overview.md
index ead20360c..87a3cf9ff 100644
--- a/components/grid/editing/overview.md
+++ b/components/grid/editing/overview.md
@@ -35,6 +35,7 @@ The Grid CRUD operations rely on the following algorithm:
Adding or editing rows in the Grid sets the following requirements on the Grid model:
* The Grid model class must have a parameterless constructor. Otherwise, use the [Grid `OnModelInit` event](slug:grid-events#onmodelinit) to provide a data item instance [when the Grid needs to create one](#item-instances). Optinally, you can also [set some default values](slug://grid-kb-default-value-for-new-row).
+* There must be a non-editable property that serves as a unique identifier.
* All editable properties must be `public` and have setters. These properties must not be `readonly`.
* All complex properties used in the Grid must be instantiated in the [Grid `OnModelInit` event](slug:grid-events#onmodelinit).
* Self-referencing or inherited properties must not cause `StackOverflowException` or `AmbiguousMatchException` during [programmatic model instance creation](#item-instances).
@@ -79,6 +80,8 @@ Delete operations provide the same user experience in all Grid edit modes and re
Delete operations can work even if the Grid `EditMode` parameter value is `None`.
+If the Grid contains Delete command buttons that display and operate in edit mode, these buttons will fire the [`OnDelete` event](#events) with a [cloned data item instance](#item-instances) in the [event argument](#gridcommandeventargs). To find the original data item in the Grid data source, use the item ID or [override the `Equals()` method of the Grid model class](slug://grid-kb-editing-in-hierarchy).
+
>tip See the delete operations in action in the complete examples for Grid [inline](slug:grid-editing-inline#examples), [in-cell](slug:grid-editing-incell#examples), and [popup](slug:grid-editing-popup#examples) editing. Also check how to [customize the Delete Confirmation Dialog](slug:grid-kb-customize-delete-confirmation-dialog).
## Commands
@@ -97,7 +100,9 @@ Users execute commands in the following ways:
* By clicking on editable cells in [in-cell edit mode](slug:grid-editing-incell) and then anywhere else on the page.
* By using the [Grid keyboard navigation](https://demos.telerik.com/blazor-ui/grid/keyboard-navigation).
-Command buttons can only reside in a [Grid Command Column](slug:components/grid/columns/command) or the [Grid ToolBar](slug:components/grid/features/toolbar). You can also [trigger add and edit operations programmatically](slug:grid-kb-add-edit-state) from anywhere on the web page through the [Grid State](slug:grid-state).
+Command buttons can only reside in a [Grid Command Column](slug:components/grid/columns/command) or the [Grid ToolBar](slug:components/grid/features/toolbar). Each command button in the command column is visible only in display mode or only in edit mode, depending on the button's `ShowInEdit` boolean parameter value.
+
+You can also [trigger add and edit operations programmatically](slug:grid-kb-add-edit-state) from anywhere on the web page through the [Grid State](slug:grid-state).
## Events
@@ -110,7 +115,7 @@ The following table describes the Grid events, which are related to adding, dele
| `OnAdd` | No | Fires on `Add` [command button](slug://components/grid/columns/command) click, before the Grid enters add mode. This event preceeds `OnCreate` or `OnCancel`. | [New](#item-instances) | Grid remains in read mode. |
| `OnCancel` | No | Fires on `Cancel` command invocation. | [New or cloned](#item-instances) | Grid remains in add or edit mode. |
| `OnCreate` | To add new items. | Fires on `Save` command invocation for new items. This event succeeds `OnAdd`. | [New](#item-instances) | Grid remains in add mode. |
-| `OnDelete` | To [delete items](#delete-operations). | Fires on `Delete` command button click. | Original | Grid won't rebind. Deletion depends on the app itself. |
+| `OnDelete` | To [delete items](#delete-operations). | Fires on `Delete` command button click. | [Original or cloned](#item-instances) | Grid won't rebind. Deletion depends on the app itself. |
| `OnEdit` | No | Fires on `Edit` command invocation, before the Grid actually enters edit mode. This event preceeds `OnUpdate` or `OnCancel`. | Original | Grid remains in read mode. |
| `OnModelInit` | [Depends on the Grid model type](slug:grid-events#onmodelinit) | Fires when the Grid requires a [new model instance](#item-instances), which is immediately before `OnAdd` or immediately after `OnEdit`. Use this event when the Grid model type is an [interface, abstract class, or has no parameterless constructor](slug:grid-events#onmodelinit). | No event arguments | Not cancellable |
| `OnUpdate` | To edit existing items. | Fires on `Save` command invocation for existing items. This event succeeds `OnEdit`. | [Cloned](#item-instances) | Grid remains in edit mode. |
diff --git a/components/grid/state.md b/components/grid/state.md
index 049bc989f..fb6c7f7b6 100644
--- a/components/grid/state.md
+++ b/components/grid/state.md
@@ -43,7 +43,7 @@ The Grid state is a generic [class `GridState`](slug:Telerik.Blazor.Compo
| `SelectedItems` | `ICollection` | The currently [selected data item(s)](slug:grid-selection-overview). |
| `Skip` | `int?` | The number of scrolled data items when using [virtual row scrolling](slug:components/grid/virtual-scrolling). In other words, this is the number of rows above the currently visible ones. |
| `SortDescriptors` | `ICollection` | The currently applied [sorts](slug:components/grid/features/sorting). |
-| `TableWidth` | `string` | The sum of all visible column widths. This property changes together with `ColumnStates`. The `OnStateChanged` event does not fire separately for it. |
+| `TableWidth` | `string` | The sum of all visible column widths. The initial value is always `null` regardless of the column configuration. The `TableWidth` value changes during column resizing together with `ColumnStates` and the`OnStateChanged` event does not fire separately for it. When you resize a column programmatically, and all other columns already have widths, you must update the `TableWidth` too, otherwise the other columns will resize unexpectedly. |
\* `TItem` is the Grid model type.
diff --git a/components/multicolumncombobox/data-bind.md b/components/multicolumncombobox/data-bind.md
index fa4826e31..2ccbc89eb 100644
--- a/components/multicolumncombobox/data-bind.md
+++ b/components/multicolumncombobox/data-bind.md
@@ -53,7 +53,7 @@ Missing selection is most common when:
## Missing Value or Data
-The MultiColumnCombobox component attempts to infer the type of its model and value based on the provided `Data` and initial `Value`. This affects its [object reference](slug:multicolumncombobox-overview#component-reference-and-methods).
+The MultiColumnCombobox component attempts to infer the type of its model and value based on the provided `Data` and initial `Value`. This affects its [object reference](slug:common-features-data-binding-overview#component-type).
In case you cannot provide either the `Value` or `Data` initially, you need to [set the corresponding types to the `TItem` and `TValue` parameters](slug:common-features-data-binding-overview#component-type).
diff --git a/components/multicolumncombobox/overview.md b/components/multicolumncombobox/overview.md
index 313e883c9..ea6b2b9cd 100644
--- a/components/multicolumncombobox/overview.md
+++ b/components/multicolumncombobox/overview.md
@@ -166,11 +166,7 @@ The MultiColumnComboBox provides the following popup settings:
## Component Reference and Methods
-To execute MultiColumnComboBox methods, obtain reference to the component instance via `@ref`.
-
-The MultiColumnComboBox is a generic component. Its type depends on the type of its model and the type of its `Value`. In case you cannot provide either the `Value` or `Data` initially, you need to [set the corresponding types to the `TItem` and `TValue` parameters](slug:common-features-data-binding-overview#component-type).
-
-The table below lists the MultiComboBox methods. Also consult the [MultiColumnComboBox API](slug:Telerik.Blazor.Components.TelerikMultiColumnComboBox-2).
+Add a reference to the component instance to use the [MultiColumnComboBox's methods](slug:Telerik.Blazor.Components.TelerikMultiColumnComboBox-2). Note that the [MultiColumnComboBox is a generic component](slug:common-features-data-binding-overview#component-type).
| Method | Description |
| --- | --- |
diff --git a/components/multiselect/data-bind.md b/components/multiselect/data-bind.md
index 6000ec15c..d21e14201 100644
--- a/components/multiselect/data-bind.md
+++ b/components/multiselect/data-bind.md
@@ -128,57 +128,7 @@ To bind the MultiSelect to a model:
## Considerations
-The MultiSelect component attempts to infer the type of its model and value based on the provided `Data` and initial `Value`. This affects the way its [reference is obtained](#reference) and what happens [if you can't provide data or a value](#missing-value-or-data).
-
-### Reference
-
-The MultiSelect is a generic component and its type depends on the type of its `Data` and `Value`.
-
-
-````RAZOR String
-@*Reference type when binding to a string collection*@
-
-
-
-@code {
- private TelerikMultiSelect? MultiSelectRef { get; set; }
-
- private List MultiSelectValue { get; set; } = new();
-
- private List MultiSelectData { get; set; } = new List { "first", "second", "third" };
-}
-````
-````RAZOR Model
-@*Reference when binding to a model collection*@
-
-
-
-@code {
- private TelerikMultiSelect? MultiSelectRef { get; set; }
-
- private List MultiSelectValue { get; set; } = new();
-
- private List MultiSelectData { get; set; } = new List()
- {
- new MultiSelectItem { Text = "first", Value = 1 },
- new MultiSelectItem { Text = "second", Value = 2 },
- new MultiSelectItem { Text = "third", Value = 3 }
- };
-
- public class MultiSelectItem
- {
- public string Text { get; set; } = string.Empty;
-
- public int Value { get; set; }
- }
-}
-````
+The MultiSelect component attempts to infer the type of its model and value based on the provided `Data` and initial `Value`. This affects the way its [reference is obtained](slug:common-features-data-binding-overview#component-type) and what happens [if you can't provide data or a value](#missing-value-or-data).
### Missing Value Or Data
diff --git a/components/multiselect/overview.md b/components/multiselect/overview.md
index f95842f7f..29c438c9e 100644
--- a/components/multiselect/overview.md
+++ b/components/multiselect/overview.md
@@ -165,9 +165,8 @@ The MultiSelect provides the following popup settings:
## MultiSelect Reference and Methods
-The MultiSelect is a generic component and its type is determined by the type of the model you use as its data source. You can find examples in the [Data Bind - Considerations](slug:multiselect-databind#considerations) article.
+Add a reference to the component instance to use the [MultiSelect's methods](slug:Telerik.Blazor.Components.TelerikMultiSelect-2). Note that the [MultiSelect is a generic component](slug:common-features-data-binding-overview#component-type).
-Add a reference to the component instance to use the [MultiSelect's methods](slug:Telerik.Blazor.Components.TelerikMultiSelect-2).
@[template](/_contentTemplates/dropdowns/methods.md#methods-list)
diff --git a/components/panelbar/data-binding/overview.md b/components/panelbar/data-binding/overview.md
index b3d735677..9381161ec 100644
--- a/components/panelbar/data-binding/overview.md
+++ b/components/panelbar/data-binding/overview.md
@@ -66,7 +66,7 @@ Each `PanelBarBinding` tag exposes the following properties that refer to item p
* ItemsField => Items
-* Level - this is used for defining [different bindings for different levels](#multiple-level-bindings). If no level is set, the bindings are taken as default for any level that does not have explicit settings. You should have one `TelerikPanelBarBinding` without a level.
+* Level—this is used for defining [custom field bindings](#custom-field-bindings) or [different bindings for different levels](#multiple-level-bindings). If no level is set, the bindings are taken as default for any level that does not have explicit settings. You must have one `TelerikPanelBarBinding` without a level to set the default bindings.
>tip There are default values for the field names. If your model names match the defaults, you don't have to define them in the bindings settings.
@@ -182,6 +182,15 @@ The following **Example** shows how to define simple binding to match item field

+### Custom Field Bindings
+
+If you are using custom field names, you must ensure their binding for each level. Otherwise, the PanelBar will not render items where the field bindings are missing.
+
+For that purpose, you must do either of the following:
+
+* Add one `TelerikPanelBarBinding` without a level to set the default bindings.
+* Add `TelerikPanelBarBinding` for each level where you explicitly set the field bindings to your custom fields.
+
### Multiple Level Bindings
You can define different binding settings for the different levels of nodes in the PanelBar. With this, the children of a node can consume a different field than their parent, and this may make your application more flexible. If you use [hierarchical data binding](slug:panelbar-data-binding-hierarchical), the children can even use a different field or model from their parent.
diff --git a/components/panelbar/templates/header.md b/components/panelbar/templates/header.md
index 80a45dd9e..accc52ec2 100644
--- a/components/panelbar/templates/header.md
+++ b/components/panelbar/templates/header.md
@@ -13,9 +13,9 @@ position: 5
You can control and customize the rendering of the header items in the PanelBar by using the `HeaderTemplate`. It provides a `context` object that you can cast to the type that the PanelBar is bound to.
-The `HeaderTemplate` of a level is defined under the `PanelBarBinding` tag.
+The `HeaderTemplate` of a level is defined under the `PanelBarBinding` tag. Set the `Level` parameter of the `PanelBarBinding` to specify the level the `HeaderTemplate` must be applied to.
-If no levels are defined the `HeaderTemplate` will apply to the entire data.
+If the `Level` parameter of the `PanelBarBinding` is not set, the `HeaderTemplate` will apply to the entire data.
>caption Use HeaderTemplate to customize the rendering of the headers in the PanelBar
@@ -26,7 +26,7 @@ If no levels are defined the `HeaderTemplate` will apply to the entire data.
-
+
@{
var item = context as PanelBarItem;
@@ -42,8 +42,9 @@ If no levels are defined the `HeaderTemplate` will apply to the entire data.
@code {
- public List Items { get; set; }
- public IEnumerable
-
-
-
-
-
-
-
Current value: @person.Role
-
-
- Submit
-
+````RAZOR DropDownList.razor
+@using System.Linq.Expressions
+
+@typeparam TItem
+@typeparam TValue
+
+
@code {
- Person person = new Person();
+ [Parameter]
+ public List? Data { get; set; }
- IEnumerable teams = new List
- {
- new MyDdlModel {MyTextField = "Team 1", MyValueField = 1},
- new MyDdlModel {MyTextField = "Team 2", MyValueField = 2},
- new MyDdlModel {MyTextField = "Team 3", MyValueField = 3},
- new MyDdlModel {MyTextField = "CEO", MyValueField = 4}
- };
+ [Parameter]
+ public TValue? Value { get; set; }
- IEnumerable roles = new List
- {
- new MyDdlModelString { Text = "Developer", Value = "Dev" },
- new MyDdlModelString { Text = "QA", Value = "QA" },
- new MyDdlModelString { Text = "Support", Value = "Support" }
- };
+ [Parameter]
+ public EventCallback ValueChanged { get; set; }
+
+ [Parameter]
+ public Expression>? ValueExpression { get; set; }
+
+ [Parameter]
+ public string Id { get; set; } = string.Empty;
- void HandleValidSubmit()
+ [Parameter]
+ public string TextField { get; set; } = string.Empty;
+
+ [Parameter]
+ public string ValueField { get; set; } = string.Empty;
+
+ private async Task TextBoxValueChanged(TValue? newValue)
{
- Console.WriteLine("OnValidSubmit");
+ Value = newValue;
+
+ if (ValueChanged.HasDelegate)
+ {
+ await ValueChanged.InvokeAsync(newValue);
+ }
}
}
````
-````C# Person
+````C# Customer.cs
using System.ComponentModel.DataAnnotations;
-public class Person
+public class Customer
{
- [Required(ErrorMessage = "Team is mandatory.")]//the value field in the combobox model must be null for this to have effect
- [Range(1, 3, ErrorMessage = "Please select an actual team.")] //limits the fourth option just to showcase this is honored
- public int? Team { get; set; }
+ public int Id { get; set; }
[Required]
- [StringLength(10, ErrorMessage = "Enter less than 10 symbols")]
- public string Role { get; set; }
-}
-````
-````C# MyDdlModel
-public class MyDdlModel
-{
- public int? MyValueField { get; set; }
- public string MyTextField { get; set; }
+ public string Name { get; set; } = string.Empty;
+
+ [Required]
+ public int? CountryId { get; set; }
}
+
````
-````C# MyDdlModelString
-public class MyDdlModelString
+````C# Country.cs
+public class Country
{
- public string Value { get; set; }
- public string Text { get; set; }
+ public int Id { get; set; }
+
+ public string Name { get; set; } = string.Empty;
}
````
## See also
* [Knowledge Base article: How to handle the ValueChanged event and use forms and validation. ](slug:value-changed-validation-model)
+* [Form Validation](slug:form-validation)
+* [FormItem Template](slug:form-formitems-template)
diff --git a/knowledge-base/mediaquery-initmediaquery-jsonexception.md b/knowledge-base/mediaquery-initmediaquery-jsonexception.md
new file mode 100644
index 000000000..b9d270f77
--- /dev/null
+++ b/knowledge-base/mediaquery-initmediaquery-jsonexception.md
@@ -0,0 +1,108 @@
+---
+title: InitMediaQueryWidget Throws JsonException
+description: Learn how to troubleshoot and find the cause for a JsonException that may be thrown by the Telerik InitMediaQueryWidget method.
+type: troubleshooting
+page_title: InitMediaQueryWidget Throws JsonException Due to Invalid Cast
+slug: mediaquery-kb-initmediaquery-jsonexception
+tags: blazor, mediaquery, serialization
+ticketid: 1676092, 1680874
+res_type: kb
+---
+
+## Environment
+
+
+
+
+
Product
+
+ MediaQuery for Blazor
+
+
+
+
+
+## Description
+
+A Blazor app may throw a runtime JSON serialization exception on startup that is similar to:
+
+```C#.skip-repl
+Microsoft.JSInterop.JSException: An exception occurred executing JS interop: DeserializeUnableToConvertValue, System.Boolean Path: $ | LineNumber: 0 | BytePositionInLine: 4.. See InnerException for more details.
+
+ ---> System.Text.Json.JsonException: DeserializeUnableToConvertValue, System.Boolean Path: $ | LineNumber: 0 | BytePositionInLine: 4.
+ ---> System.InvalidOperationException: InvalidCast, Null, boolean
+ at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_ExpectedBoolean(JsonTokenType )
+ at System.Text.Json.Utf8JsonReader.GetBoolean()
+
+ ...
+
+ at Microsoft.JSInterop.JSRuntime..MoveNext()
+ at Telerik.Blazor.Components.TelerikMediaQuery.InitMediaQueryWidget()
+ at Telerik.Blazor.Components.TelerikMediaQuery.OnAfterRenderAsync(Boolean firstRender)
+```
+
+or
+
+```C#.skip-repl
+Microsoft.JSInterop.JSException: An exception occurred executing JS interop: The JSON value could not be converted to System.Boolean. Path: $ | LineNumber: 0 | BytePositionInLine: 4.. See InnerException for more details.
+
+ ---> System.Text.Json.JsonException: The JSON value could not be converted to System.Boolean. Path: $ | LineNumber: 0 | BytePositionInLine: 4.
+ ---> System.InvalidOperationException: Cannot get the value of a token type 'Null' as a boolean.
+ at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_ExpectedBoolean(JsonTokenType tokenType)
+ at System.Text.Json.Utf8JsonReader.GetBoolean()
+ ...
+
+ at Microsoft.JSInterop.JSRuntime..MoveNext()
+ at Telerik.Blazor.Components.TelerikMediaQuery.InitMediaQueryWidget()
+ at Telerik.Blazor.Components.TelerikMediaQuery.OnAfterRenderAsync(Boolean firstRender)
+```
+
+## Cause
+
+The [`TelerikRootComponent`](slug:rootcomponent-overview) creates a few [MediaQuery](slug:mediaquery-overview) components. These MediaQuery instances are responsible for the [adaptive behavior of all Telerik dropdowns and popups](slug:adaptive-rendering). During initialization, each Telerik MediaQuery component performs a JSInterop call in `OnAfterRenderAsync` that returns a boolean value back to the .NET runtime. This bool value shows whether the current browser viewport size matches the MediaQuery `Media` parameter value.
+
+An JSON exception in the above algorithm indicates that the received value cannot be converted to boolean type. This can happen if the application is using a third-party package or middleware (for example, Serilog) that overrides the .NET serialization mechanism. As a result, the .NET runtime may receive `null` instead of `true` or `false`.
+
+## Solution
+
+The recommended approach is to modify the app configuration or third-party tooling, so that the .NET serialization works by default.
+
+## Suggested Workaround
+
+In some cases, it may be possible to avoid the JSON error by rendering all Razor components in the app with a delay in `OnAfterRenderAsync`:
+
+>caption MainLayout.razor
+
+````RAZOR.skip-repl
+@inherits LayoutComponentBase
+
+@if (ShouldRenderApp)
+{
+
+ @Body
+
+}
+
+@code {
+ private bool ShouldRenderApp { get; set; }
+
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ if (firstRender)
+ {
+ await Task.Delay(1);
+
+ ShouldRenderApp = true;
+ StateHasChanged();
+ }
+
+ await base.OnAfterRenderAsync(firstRender);
+ }
+}
+````
+
+## See Also
+
+* [DataSourceRequest Filters not Working When You Add Reporting or Newtonsoft.Json](slug:common-kb-newtonsoft-breaks-datasourcerequest-serialization)
+* [Chart not Working with Newtonsoft.Json Properties](slug:chart-kb-newtonsoft-seialization-settings)
+* [Troubleshooting JavaScript Errors](slug:troubleshooting-js-errors)
diff --git a/knowledge-base/tabstrip-dynamic-tabs.md b/knowledge-base/tabstrip-dynamic-tabs.md
index b2ae2f693..d8b889505 100644
--- a/knowledge-base/tabstrip-dynamic-tabs.md
+++ b/knowledge-base/tabstrip-dynamic-tabs.md
@@ -1,11 +1,11 @@
---
-title: Dynamic Tabs
-description: How to create Dynamic Tabs in TabStip.
+title: Add and Remove TabStrip Tabs
+description: Learn how to dynamically add and remove tabs
type: how-to
-page_title: Dynamic Tabs
-slug: tabstrip-kb-dynamic-tabs
-position:
-tags:
+page_title: How to Add and Remove TabStrip Tabs
+slug: tabstrip-kb-add-remove-tabs
+tags: telerik,blazor,tabstrip,add tabs,remove tabs
+ticketid:
res_type: kb
---
@@ -20,12 +20,180 @@ res_type: kb
-
## Description
-How to create Dynamic Tabs in TabStip? How to add and remove tabs dynamically? How to get information about the currently active tab? How to set the content of the tabs dynamically?
+I have a collection of items representing separate tabs. I am iterating through that collection to render a tab for each item as shown in the [Tabs Collection article](slug:tabstrip-tabs-collection). I want to allow the user to add and remove tabs. How to achieve that?
+
+This KB article also answers the following questions:
+* How to implement add and remove tab functionality with the Telerik TabStrip component.
+* How to remove a tab using an "X" button in the tab header.
+* How to add a new tab with a "+" button, similar to browser tab controls.
+* How to position the add ("+") button next to the last tab header.
## Solution
-An example is available in the following project: [https://github.com/telerik/blazor-ui/tree/master/tabstrip/DynamicTabs](https://github.com/telerik/blazor-ui/tree/master/tabstrip/DynamicTabs).
\ No newline at end of file
+1. [Render the TabStrip tabs in a loop](slug:tabstrip-tabs-collection).
+1. Use a [`HeaderTemplate`](slug:tabstrip-header-template) for the tabs to add Remove buttons. You can display the buttons conditionally based on the tab count.
+1. Declare a button for adding new tabs.
+1. Use custom styling and JavaScript to position the Add button next to the last tab header.
+
+>caption Adding and removing TabStrip tabs at runtime
+
+````RAZOR
+@inject IJSRuntime JS
+
+
+
+
+
+ @foreach (Tab tab in Tabs)
+ {
+
+
+
+ @tab.Title
+ @if (Tabs.Count > 1)
+ {
+
+ }
+
+
+
+ Content for @tab.Title
+
+
+ }
+
+
+
+
+
+@* Move JavaScript code to a JS file *@
+
+
+
+@code {
+ private List Tabs = new List()
+ {
+ new Tab { Title = "Tab 1" },
+ new Tab { Title = "Tab 2" },
+ new Tab { Title = "Tab 3" }
+ };
+
+ private string ActiveTabId { get; set; } = string.Empty;
+
+ private bool ShouldPositionAddButton { get; set; }
+
+ private int LastTabNumber { get; set; } = 3;
+
+ private void AddTab()
+ {
+ Tab tabToAdd = new Tab { Id = Guid.NewGuid().ToString(), Title = $"New Tab {++LastTabNumber}" };
+
+ Tabs.Add(tabToAdd);
+
+ //In this example, we are always activating the newly added tab. Adjust the logic to activate a different tab if needed.
+ ActiveTabId = tabToAdd.Id;
+
+ ShouldPositionAddButton = true;
+ }
+
+ private void RemoveTab(Tab tab)
+ {
+ if (Tabs.Count <= 1)
+ {
+ return;
+ }
+
+ // Activate the tab after or before the removed one if it's active
+ if (ActiveTabId == tab.Id)
+ {
+ int removedTabIndex = Tabs.FindIndex(x => x.Id == tab.Id);
+ if (removedTabIndex == Tabs.Count - 1)
+ {
+ ActiveTabId = Tabs.ElementAt(removedTabIndex - 1).Id;
+ }
+ else
+ {
+ ActiveTabId = Tabs.ElementAt(removedTabIndex + 1).Id;
+ }
+ }
+
+ Tabs.Remove(tab);
+
+ ShouldPositionAddButton = true;
+ }
+
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ if (firstRender || ShouldPositionAddButton)
+ {
+ ShouldPositionAddButton = false;
+ await JS.InvokeVoidAsync("positionAddTabButton");
+ }
+
+ await base.OnAfterRenderAsync(firstRender);
+ }
+
+ public class Tab
+ {
+ public string Id { get; set; } = Guid.NewGuid().ToString();
+
+ public string Title { get; set; } = string.Empty;
+ }
+
+}
+````
+
+## See Also
+
+* [Dynamic Tab Collection](slug:tabstrip-tabs-collection)
+* [TabStrip Tab `HeaderTemplate`](slug:tabstrip-header-template)
diff --git a/knowledge-base/value-changed-validation-model.md b/knowledge-base/value-changed-validation-model.md
index e9f09b192..7cc77e9a3 100644
--- a/knowledge-base/value-changed-validation-model.md
+++ b/knowledge-base/value-changed-validation-model.md
@@ -97,4 +97,4 @@ from model: @person.theTbValue
## See also
-* [Knowledge Base article: Validate a Telerik component as child control and apply invalid border ](slug:inputs-kb-validate-child-component)
+* [Validate a Telerik component as child control and apply invalid border ](slug:inputs-kb-validate-child-component)
diff --git a/troubleshooting/license-key-errors.md b/troubleshooting/license-key-errors.md
index e918d4aab..8f075b877 100644
--- a/troubleshooting/license-key-errors.md
+++ b/troubleshooting/license-key-errors.md
@@ -22,6 +22,7 @@ A Telerik license key error may occur in the following scenarios:
* The license key is outdated or does not include the product version that you are using.
* Your subscription license or trial has expired.
* You have different conflicting license keys in the same environment. For example, using one global license key and one in the app. Or, using a license key file together with an environment variable in CI/CD environment.
+* Telerik UI for Blazor is used in the **Client** project of a WebAssembly app that uses pre-rendering. In such cases, you can briefly see a yellow banner in the browser, which says "[We couldn't verify your license key for Telerik UI for Blazor. Please see the build log for details and resolution steps](#we-couldn-t-verify-your-license-key-for-telerik-ui-for-blazor-yellow-banner)".
Refer to the specific error messages and tips below.
@@ -70,6 +71,12 @@ This error applies to subscription licenses. [Renew your subscription](https://w
[Purchase a commercial license to continue using Telerik UI for Blazor](https://www.telerik.com/purchase/blazor-ui).
+### We couldn't verify your license key for Telerik UI for Blazor (yellow banner)
+
+This section assumes an existing valid license key, so that the problem is not any of the above.
+
+If you briefly see a yellow warning banner in the web browser that says "**We couldn't verify your license key**", then refer to [Using Telerik Packages in Referenced Projects](slug:installation-license-key#using-telerik-packages-in-referenced-projects).
+
## See Also
* [Download and Install License Key](slug:installation-license-key)
diff --git a/upgrade/breaking-changes/9-0-0.md b/upgrade/breaking-changes/9-0-0.md
index e0ddb02b1..5983ad4e4 100644
--- a/upgrade/breaking-changes/9-0-0.md
+++ b/upgrade/breaking-changes/9-0-0.md
@@ -8,9 +8,15 @@ position: 960
# Breaking Changes in 9.0.0
+## Common
+
### Trial and commercial users now use the same product package
The trial and commercial product versions merged into a single unified distribution package. The product access now depends on a license key file. This eliminates the need for separate trial downloads. For more information, please refer to the [Telerik License Key](slug:installation-license-key).
### .NET Support
-Telerik UI for Blazor 9.0.0 targets .NET 8 and no longer supports .NET 6 and .NET 7. For more information, see [System Requirements](slug:system-requirements).
\ No newline at end of file
+Telerik UI for Blazor 9.0.0 targets .NET 8 and no longer supports .NET 6 and .NET 7. For more information, see [System Requirements](slug:system-requirements).
+
+## Window
+
+The `Centered` parameter is removed. The Window is centered by default if the `Top` and `Left` parameters are equal to an empty string or if they are not set. To center the Window programmatically at any time, [reset the `Top` and `Left` parameter values](slug:components/window/position#top-and-left).