diff --git a/CS/GridCustomShortcuts/Components/Layout/NavMenu.razor b/CS/GridCustomShortcuts/Components/Layout/NavMenu.razor index d8ed94b..9e7f610 100644 --- a/CS/GridCustomShortcuts/Components/Layout/NavMenu.razor +++ b/CS/GridCustomShortcuts/Components/Layout/NavMenu.razor @@ -2,8 +2,6 @@ - - \ No newline at end of file diff --git a/CS/GridCustomShortcuts/Components/Pages/Counter.razor b/CS/GridCustomShortcuts/Components/Pages/Counter.razor deleted file mode 100644 index 99a48d8..0000000 --- a/CS/GridCustomShortcuts/Components/Pages/Counter.razor +++ /dev/null @@ -1,27 +0,0 @@ -@page "/counter" -@rendermode InteractiveServer -Counter - -

Counter

- -
-
-
- @currentCount -
-
- current count -
-
-
- Click me -
- -@code { - private int currentCount = 0; - - private void IncrementCount() - { - currentCount++; - } -} diff --git a/CS/GridCustomShortcuts/Components/Pages/Counter.razor.css b/CS/GridCustomShortcuts/Components/Pages/Counter.razor.css deleted file mode 100644 index 08d0ae2..0000000 --- a/CS/GridCustomShortcuts/Components/Pages/Counter.razor.css +++ /dev/null @@ -1,37 +0,0 @@ -.counter-block { - display: flex; - padding: 2.5rem 1.5rem 1.5rem 1.5rem; - flex-direction: column; - border-radius: 1rem; - gap: 1.5rem; - justify-content: center; - align-items: center; - width: 16.875rem; - height: 17rem; - position: relative; -} - - .counter-block .counter-content { - display: flex; - flex-direction: column; - align-items: center; - gap: 0.5rem; - } - - .counter-block .counter-count { - font-size: 7.5rem; - font-weight: 400; - line-height: 7.75rem; - } - - .counter-block .counter-block-back { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: var(--bs-body-color); - opacity: 0.05; - border-radius: 1rem; - z-index: -2; - } diff --git a/CS/GridCustomShortcuts/Components/Pages/Index.razor b/CS/GridCustomShortcuts/Components/Pages/Index.razor index e4b156b..2a6134d 100644 --- a/CS/GridCustomShortcuts/Components/Pages/Index.razor +++ b/CS/GridCustomShortcuts/Components/Pages/Index.razor @@ -6,6 +6,9 @@ @inject WeatherForecastService ForecastService @implements IAsyncDisposable +Blazor Grid Keyboard Shortcuts +

Weather Forecast

+ @if (forecasts == null) {

Loading...

@@ -13,13 +16,12 @@ else {
- + - + @@ -28,10 +30,10 @@ else
- - + +

Temperature: @selectedForecast?.TemperatureC °C

+

Summary: @selectedForecast?.Summary

} @@ -39,7 +41,7 @@ else private WeatherForecast[]? forecasts; private bool popupVisible; private ElementReference gridWrapper; - private DateOnly currentDate; + private WeatherForecast? selectedForecast; private IGrid grid; private IJSObjectReference? module; private DotNetObjectReference? dotNetHelper; @@ -51,7 +53,7 @@ else if (focusedItem == null) return; await grid.SaveChangesAsync(); - currentDate = focusedItem.Date; + selectedForecast = focusedItem; popupVisible = true; StateHasChanged(); } @@ -74,6 +76,7 @@ else module = await JS.InvokeAsync("import", "./Components/Pages/Index.razor.js"); dotNetHelper = DotNetObjectReference.Create(this); + await module.InvokeVoidAsync("focusGrid"); await module.InvokeVoidAsync("addCaptureKeyListener", gridWrapper, dotNetHelper); } } diff --git a/CS/GridCustomShortcuts/Components/Pages/Index.razor.js b/CS/GridCustomShortcuts/Components/Pages/Index.razor.js index f7296e2..d108705 100644 --- a/CS/GridCustomShortcuts/Components/Pages/Index.razor.js +++ b/CS/GridCustomShortcuts/Components/Pages/Index.razor.js @@ -23,4 +23,8 @@ export function removeCaptureKeyListener() { window.removeEventListener('keydown', keydownHandler, true); keydownHandler = null; } +} + +export function focusGrid() { + document.getElementsByClassName('dxbl-grid')[0].focus(); } \ No newline at end of file diff --git a/CS/GridCustomShortcuts/Components/Pages/Weather.razor b/CS/GridCustomShortcuts/Components/Pages/Weather.razor deleted file mode 100644 index fb64630..0000000 --- a/CS/GridCustomShortcuts/Components/Pages/Weather.razor +++ /dev/null @@ -1,35 +0,0 @@ -@page "/weather" - -@using GridCustomShortcuts.Services -@attribute [StreamRendering(true)] -@rendermode InteractiveServer -@inject WeatherForecastService ForecastService - -Weather -

Weather

- -@if (forecasts == null) -{ -

Loading...

-} -else -{ - - - - - - - - -} - -@code { - private WeatherForecast[]? forecasts; - - protected override async Task OnInitializedAsync() - { - forecasts = await ForecastService.GetForecastAsync(DateOnly.FromDateTime(DateTime.Now)); - } -} \ No newline at end of file diff --git a/README.md b/README.md index f258469..d8a3300 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,60 @@ -![](https://img.shields.io/endpoint?url=https://codecentral.devexpress.com/api/v1/VersionRange/970685143/24.2.1%2B) [![](https://img.shields.io/badge/Open_in_DevExpress_Support_Center-FF7200?style=flat-square&logo=DevExpress&logoColor=white)](https://supportcenter.devexpress.com/ticket/details/T1290517) [![](https://img.shields.io/badge/📖_How_to_use_DevExpress_Examples-e9f6fc?style=flat-square)](https://docs.devexpress.com/GeneralInformation/403183) [![](https://img.shields.io/badge/💬_Leave_Feedback-feecdd?style=flat-square)](#does-this-example-address-your-development-requirementsobjectives) -# Product/Platform - Task +# Blazor Grid - Custom Keyboard Shortcuts -This is the repository template for creating new examples. Describe the solved task here. +The DevExpress Blazor [Grid](https://docs.devexpress.com/Blazor/403143/components/grid) supports a number of keyboard shortcuts out-of-the-box. You can also define custom key combinations to further enhance interaction speed and streamline workflows according to business requirements or user preferences. -Put a screenshot that illustrates the result here. +This example binds custom keyboard shortcuts to the Grid component: -Then, add implementation details (steps, code snippets, and other technical information in a free form), or add a link to an existing document with implementation details. +- Ctrl + A: select all rows +- Shift + Enter: open row details + +![Blazor Grid Custom Keyboard Shortcuts](images/grid-keyboard-shortcuts.gif) + +> [!NOTE] +> For keyboard shortcuts to operate, the Grid component must be focused. To bring the grid into focus, click anywhere within its area. + +## Implementation Details + +Add [DxGrid](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxGrid) and [DxPopup](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxPopup) components to the [page](CS/GridCustomShortcuts/Components/Pages/Index.razor). The popup will display the selected cell's details when a user presses Shift + Enter. + +Create a [JavaScript file](CS/GridCustomShortcuts/Components/Pages/Index.razor.js) in the project. This file implements the following functions for managing keyboard shortcuts: + +- `addCaptureKeyListener` - Attaches a keyboard event listener to the grid and defines custom shortcuts. To prevent default web browser actions for the same key combinations, call `event.stopPropagation();` within the event handler. +- `removeCaptureKeyListener` - Removes the previously attached keyboard event listener. +- `focusGrid` - Focus the grid programmatically on page load. This ensures shortcuts are instantly available. + +### Bind JavaScript with .NET Code + +In the `@code` section of the [Index.razor](CS/GridCustomShortcuts/Components/Pages/Index.razor) page: + +1. Register the JavaScript code in `OnAfterRenderAsync` lifecycle method. +2. Call the `focusGrid` JavaScript function. +3. Call the `addCaptureKeyListener` JavaScript function. Pass the `DotNetObjectReference` (for interoperability from JavaScript to .NET) and a reference to the `
` element that surrounds the grid (for capturing keyboard events.) +4. Implement `SelectAllRows` and `HandleKeyDown` JSInvokable methods to handle operations triggered by keyboard shortcuts. + +For technical details, read [Call .NET methods from JavaScript functions in ASP.NET Core Blazor](https://learn.microsoft.com/en-us/aspnet/core/blazor/javascript-interoperability/call-dotnet-from-javascript) article. + +### Release Resources + +In the `@code` section of the [Index.razor](CS/GridCustomShortcuts/Components/Pages/Index.razor) page, implement a `DisposeAsync` method. It removes the keyboard event listener, cleans up JavaScript resources, and frees allocated memory. + +For technical details, read [Implement a DisposeAsync method](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-disposeasync) article. ## Files to Review -- link.cs (VB: link.vb) -- link.js -- ... +- [Index.razor](CS/GridCustomShortcuts/Components/Pages/Index.razor) +- [Index.razor.js](CS/GridCustomShortcuts/Components/Pages/Index.razor.js) ## Documentation -- link -- link -- ... - -## More Examples +- [Keyboard Support in Blazor Grid](https://docs.devexpress.com/Blazor/404652/components/grid/keyboard-support) +- [DxGrid Class](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxGrid) +- [DxPopup Class](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxPopup) -- link -- link -- ... ## Does this example address your development requirements/objectives? diff --git a/config.json b/config.json index d660d4a..038dbef 100644 --- a/config.json +++ b/config.json @@ -1,4 +1,4 @@ { - "autoGenerateVb": true, + "autoGenerateVb": false, "runOnWeb": false } \ No newline at end of file diff --git a/images/grid-keyboard-shortcuts.gif b/images/grid-keyboard-shortcuts.gif new file mode 100644 index 0000000..8b4395f Binary files /dev/null and b/images/grid-keyboard-shortcuts.gif differ