From aa6caa9b5e52554e9dd64bc4dfb3252083b4d21f Mon Sep 17 00:00:00 2001 From: Dimo Dimov <961014+dimodi@users.noreply.github.com> Date: Thu, 19 Jun 2025 14:36:53 +0300 Subject: [PATCH 1/8] docs(FileManager): Improve data binding information and add KB for data virtualization --- .../filemanager/data-binding/overview.md | 75 ++-- components/filemanager/events.md | 361 +++--------------- .../filemanager-load-file-data-on-demand.md | 207 ++++++++++ 3 files changed, 288 insertions(+), 355 deletions(-) create mode 100644 knowledge-base/filemanager-load-file-data-on-demand.md diff --git a/components/filemanager/data-binding/overview.md b/components/filemanager/data-binding/overview.md index f521daf2c..fdb3162cd 100644 --- a/components/filemanager/data-binding/overview.md +++ b/components/filemanager/data-binding/overview.md @@ -225,62 +225,41 @@ The FileManager has features that map to properties in the model. The following } ```` -The above model properties have the following meaning for the FileManager: +The following section describe the meaning of the model properties for the FileManager. +### Data Bindings + +All [FileManager item features](#fileManager-item-features) map to model properties. The properties of a FileManager item match directly to a field of the component model. You define that relationship by providing the property name from which the corresponding information is taken. To do this, use the following parameters of the main `TelerikFileManager` tag: @[template](/_contentTemplates/common/parameters-table-styles.md#table-layout) -| Property | Description | -| --- | --- | -| **Item features** | | -| `Name` | The name of the file. | -| `Size` | The size of the file. | -| `Path` | The path of the file. | -| `Extension` | The extension of the file. | -| `IsDirectory` | Whether the item is a directory. If its value is `false` the item is considered a file and not a directory. | -| `DateCreated` | The creation date of the file. | -| `DateCreateUtc` | The creation date of the file in UTC. Required. | -| `DateModified` | The modification date of the file. | -| `DateModifiedUtc` | The modification date of the file in UTC. Required. | -| **Item relations** | | -| `Id `| The unique identifier of the file. Required for [**binding to flat data**](slug:filemanager-data-binding-flat-data). | -| `ParentId` | Identifies the file's parent. Required for [**binding to flat data**](slug:filemanager-data-binding-flat-data). Set to `null` for root items. Do *not* use `ParentId` with hierarchical data. | -| `HasDirectories` | Determines whether the item has subdirectories. Required for binding to [**flat data**](slug:filemanager-data-binding-flat-data) If `true`, the directory will show an expand arrow. With [**hierarchical data**](slug:filemanager-data-binding-hierarchical-data), the FileManager renders expand icons based on `Directories`, but `HasDirectories` will take precedence. | -| `Directories` | Defines the item subdirectories. Required for [binding to **hierarchical data**](slug:filemanager-data-binding-hierarchical-data). -| `Items` | Defines all the subitems (directories and files) of the item. | - -## Data Bindings - -All [FileManager item features](#fileManager-item-features) map to model properties. The properties of a treeview item match directly to a field of the model the treeview is bound to. You provide that relationship by providing the name of the field from which the corresponding information is to be taken. To do this, in the main `TelerikFileManager` tag, use the parameters described below: - -| FileManager Parameter | Default Value | -| --- | --- | -| **Item features** | | -| `NameField`| `"Name"` | -| `SizeField`| `"Size"` | -| `PathField`| `"Path"` | -| `ExtensionField`| `"Extension"` | -| `IsDirectoryField`| `"IsDirectoryField"` | -| `DateCreatedField`| `"DateCreated"` | -| `DateCreateUtcField`| `"DateCreateUtc"` | -| `DateModifiedField`| `"DateModified"` | -| `DateModifiedUtcField`| `"DateModifiedUtc"` | -| **Item relations** | | -| `IdField `| `"Id" ` | -| `ParentIdField`| `"ParentId"` | -| `HasDirectoriesField`| `"HasDirectories"` | -| `DirectoriesField`| `"Directories"` | -| `EntriesField`| `"Entries"` | - ->important Do not use `ParentId` with hierarchical data. This will confuse the FileManager that it is bound to flat data and the component may not render any items. If the model must have a `ParentId` property, set `ParentIdField` to a non-existent property. +| FileManager Parameter | Default Parameter Value
(Model Property Name) | Model Property Type | Model Value Description | +| --- | --- | --- | --- | +| **Item features** | | | | +| `NameField`| `"Name"` | `string` | The name of the file or folder, excluding the extension. | +| `SizeField`| `"Size"` | `long` | The size of the file in bytes. | +| `PathField`| `"Path"` | `string` | The path to the item, including the name and extension. | +| `ExtensionField`| `"Extension"` | `string` | The item extension, starting with a dot `.` | +| `IsDirectoryField`| `"IsDirectoryField"` | `bool` | Whether the item is a folder. If `false`, it's treated as a file. | +| `DateCreatedField`| `"DateCreated"` | `DateTime` | The creation date of the file. | +| `DateCreateUtcField`| `"DateCreateUtc"` | `DateTime` | The creation date of the file in UTC. Required. | +| `DateModifiedField`| `"DateModified"` | `DateTime` | The modification date of the file. | +| `DateModifiedUtcField`| `"DateModifiedUtc"` | `DateTime` | The modification date of the file in UTC. Required. | +| **Item relations** | | | | +| `IdField `| `"Id" ` | any | The unique identifier of the file. Required for [binding to flat data](slug:filemanager-data-binding-flat-data). | +| `ParentIdField`| `"ParentId"` | any | Identifies the item's parent. Required for [binding to flat data](slug:filemanager-data-binding-flat-data). Set to `null` for root items. Do not use `ParentId` with hierarchical data. | +| `HasDirectoriesField`| `"HasDirectories"` | `bool` | Determines whether the item has child folders. Required for [binding to flat data](slug:filemanager-data-binding-flat-data) If `true`, the folder will show an expand arrow in the TreeView. With [hierarchical data](slug:filemanager-data-binding-hierarchical-data), the FileManager renders expand icons based on `Directories`, but `HasDirectories` takes precedence. | +| `DirectoriesField`| `"Directories"` | `IEnumerable` | The item's child folders. Required for [binding to hierarchical data](slug:filemanager-data-binding-hierarchical-data) | +| `ItemsField`| `"Items"` | `IEnumerable` | The folder's child files. Required for [binding to hierarchical data](slug:filemanager-data-binding-hierarchical-data). | + +>important Do not use `ParentId` with hierarchical data. This will confuse the FileManager that it is bound to flat data and the component may not render any items. If the model must have a `ParentId` property, set `ParentIdField` to a non-existent property name. ## Next Steps -Learn the different ways to provide data to a TreeView: - -* [Use flat data](slug:filemanager-data-binding-flat-data) -* [Use hierarchical data](slug:filemanager-data-binding-hierarchical-data) - each item holds its children in a nested property +Learn the different ways to provide data to a FileManager: +* [Use flat data](slug:filemanager-data-binding-flat-data), where all items at all levels represent a single collection. +* [Use hierarchical data](slug:filemanager-data-binding-hierarchical-data), where each folder item holds its child files and folders in nested properties. ## See Also diff --git a/components/filemanager/events.md b/components/filemanager/events.md index efa8976c1..487999bce 100644 --- a/components/filemanager/events.md +++ b/components/filemanager/events.md @@ -12,20 +12,19 @@ position: 20 This article explains the events available in the Telerik FileManager for Blazor. They are grouped logically. -* [CUD Events](#cud-events) - events related to Creating, Updating and Deleting items. +* [CRUD Events](#crud-events) - events related to Creating, Updating and Deleting items. * [OnCreate](#oncreate) - * [OnUpdate](#onupdate) - * [OnEdit](#onedit) * [OnDelete](#ondelete) -* [Read Event](#read-event) - event related to obtaining data. -* [Other Events](#other-events) - other events the grid provides. - * [OnModelInit](#onmodelinit) - * [OnDownload](#ondownload) - * [PathChanged](#pathchanged) - * [SelectedItemsChanged](#selecteditemschanged) - * [ViewChanged](#viewchanged) + * [OnEdit](#onedit) + * [OnUpdate](#onupdate) +* [OnDownload](#ondownload) +* [OnModelInit](#onmodelinit) +* [OnRead Event](#onread) - event related to obtaining data. +* [PathChanged](#pathchanged) +* [SelectedItemsChanged](#selecteditemschanged) +* [ViewChanged](#viewchanged) -## CUD Events +## CRUD Events The `OnCreate`, `OnUpdate` and `OnDelete` events let you get the data item that the user changed so you can transfer the user action to the actual data source. @@ -35,302 +34,27 @@ The `OnEdit` event let you respond to user actions - when they want to edit an i The `OnCreate` event fires when a new item is created (new folder). Its event handler receives the updated `FileManagerCreateEventArgs` as an argument. -### OnUpdate - -The `OnUpdate` event fires when a file is updated (rename finishes). Its event handler receives the updated `FileManagerUpdateEventArgs` as an argument. - -### OnEdit - -The `OnEdit` event fires when the user is about to enter edit mode for an existing item. Its event handler receives the updated `FileManagerEditEventArgs` as an argument. - ### OnDelete The `OnDelete` event fires when a file is deleted. Its event handler receives the updated `FileManagerDeleteEventArgs` as an argument. -## Read Event - -In the common case, all the data is provided to the filemanager's `Data` collection and the `FileManager` performs the operations on it for you. In some cases, you may want to do this programmatically (for example, to retrieve only a small number of items to improve the backend performance). Attach the `OnRead` event to perform all the data read operations programmatically in the `FileManager`. - -The `OnRead` event fires when the data source is read. Its event handler receives the updated `FileManagerReadEventArgs` as an argument. - ->caption Handle OnRead. - -````RAZOR -@using System.IO - - - - -@code { - private List SourceData = new List(); - - private string RootPath { get; set; } = "root-folder-path"; - private string DirectoryPath { get; set; } = "root-folder-path"; - - private async Task OnRead(FileManagerReadEventArgs args) - { - await Task.Delay(500); - - //here you can pass only the files for the current directory, so you don't load the whole data collection - args.Data = SourceData; - args.Total = SourceData.Count; - } - - private async Task OnUpdateHandler(FileManagerUpdateEventArgs args) - { - var item = args.Item as FlatFileEntry; - - if (item.IsDirectory) - { - // prevent renaming of directories. If you allow that, make sure - //to also update the Path of the children - } - else - { - // simulate update of the file name and path - var name = item.Name ?? string.Empty; - var extension = item.Extension ?? string.Empty; - var fullName = extension.Length > 0 && name.EndsWith(extension) ? - name : $"{name}{extension}"; - - var updatedItem = SourceData.FirstOrDefault(x => x.MyModelId == item.MyModelId); - - updatedItem.Name = item.Name; - updatedItem.Path = Path.Combine(DirectoryPath, fullName); - } - } - - private async Task OnDownloadHandler(FileManagerDownloadEventArgs args) - { - var selectedItem = args.Item as FlatFileEntry; - - //the FileManager does not have the actual file. - //To download it, find the actual file in the datasource - //based on the selected file (args.Item) and - //assign the following data to the argument: - - //args.Stream = the file stream of the actual selected file; - //args.MimeType = the mime type of the actual file, so it can be downloaded; - //args.FileName = allows overriding the name of the downloaded file; - } - - - private async Task OnDeleteHandler(FileManagerDeleteEventArgs args) - { - var currItem = args.Item as FlatFileEntry; - - var itemToDelete = SourceData.FirstOrDefault(x => x.MyModelId == currItem.MyModelId); - - //simulate item deletion - SourceData.Remove(itemToDelete); - - RefreshData(); - } - - private FlatFileEntry OnModelInitHandler() - { - var item = new FlatFileEntry(); - item.Name = $"New folder"; - item.Size = 0; - item.Path = Path.Combine(DirectoryPath, item.Name); - item.IsDirectory = true; - item.HasDirectories = false; - item.DateCreated = DateTime.Now; - item.DateCreatedUtc = DateTime.Now; - item.DateModified = DateTime.Now; - item.DateModifiedUtc = DateTime.Now; - - return item; - } - - private void RefreshData() - { - SourceData = new List(SourceData); - } - - // fetch the FileManager data - protected override async Task OnInitializedAsync() - { - SourceData = await GetFlatFileEntries(); - } - - // a model to bind the FileManager. Should usually be in its own separate location. - public class FlatFileEntry - { - public string MyModelId { get; set; } - public string ParentId { get; set; } - public string Name { get; set; } - public long Size { get; set; } - public string Path { get; set; } - public string Extension { get; set; } - public bool IsDirectory { get; set; } - public bool HasDirectories { get; set; } - public DateTime DateCreated { get; set; } - public DateTime DateCreatedUtc { get; set; } - public DateTime DateModified { get; set; } - public DateTime DateModifiedUtc { get; set; } - } - - // the next lines are hardcoded data generation so you can explore the FileManager freely - - private async Task> GetFlatFileEntries() - { - var workFiles = new FlatFileEntry() - { - MyModelId = "1", - ParentId = null, - Name = "Work Files", - IsDirectory = true, - HasDirectories = true, - DateCreated = new DateTime(2022, 1, 2), - DateCreatedUtc = new DateTime(2022, 1, 2), - DateModified = new DateTime(2022, 2, 3), - DateModifiedUtc = new DateTime(2022, 2, 3), - Path = Path.Combine(RootPath, "Work Files"), - Size = 3 * 1024 * 1024 - }; - - var Documents = new FlatFileEntry() - { - MyModelId = "2", - ParentId = workFiles.MyModelId, - Name = "Documents", - IsDirectory = true, - HasDirectories = false, - DateCreated = new DateTime(2022, 1, 2), - DateCreatedUtc = new DateTime(2022, 1, 2), - DateModified = new DateTime(2022, 2, 3), - DateModifiedUtc = new DateTime(2022, 2, 3), - Path = Path.Combine(workFiles.Path, "Documents"), - Size = 1024 * 1024 - }; - - var Images = new FlatFileEntry() - { - MyModelId = "3", - ParentId = workFiles.MyModelId, - Name = "Images", - IsDirectory = true, - HasDirectories = false, - DateCreated = new DateTime(2022, 1, 2), - DateCreatedUtc = new DateTime(2022, 1, 2), - DateModified = new DateTime(2022, 2, 3), - DateModifiedUtc = new DateTime(2022, 2, 3), - Path = Path.Combine(workFiles.Path, "Images"), - Size = 2 * 1024 * 1024 - }; - - var specification = new FlatFileEntry() - { - MyModelId = "4", - ParentId = Documents.MyModelId, - Name = "Specification", - IsDirectory = false, - HasDirectories = false, - Extension = ".docx", - DateCreated = new DateTime(2022, 1, 5), - DateCreatedUtc = new DateTime(2022, 1, 5), - DateModified = new DateTime(2022, 2, 3), - DateModifiedUtc = new DateTime(2022, 2, 3), - Path = Path.Combine(Documents.Path, "Specification.docx"), - Size = 462 * 1024 - }; - - var report = new FlatFileEntry() - { - MyModelId = "5", - ParentId = Documents.MyModelId, - Name = "Monthly report", - IsDirectory = false, - HasDirectories = false, - Extension = ".xlsx", - DateCreated = new DateTime(2022, 1, 20), - DateCreatedUtc = new DateTime(2022, 1, 20), - DateModified = new DateTime(2022, 1, 25), - DateModifiedUtc = new DateTime(2022, 1, 25), - Path = Path.Combine(Documents.Path, "Monthly report.xlsx"), - Size = 538 * 1024 - }; - - var dashboardDesign = new FlatFileEntry() - { - MyModelId = "6", - ParentId = Images.MyModelId, - Name = "Dashboard Design", - IsDirectory = false, - HasDirectories = false, - Extension = ".png", - DateCreated = new DateTime(2022, 1, 10), - DateCreatedUtc = new DateTime(2022, 1, 10), - DateModified = new DateTime(2022, 2, 13), - DateModifiedUtc = new DateTime(2022, 2, 13), - Path = Path.Combine(Images.Path, "Dashboard Design.png"), - Size = 1024 - }; - - var gridDesign = new FlatFileEntry() - { - MyModelId = "7", - ParentId = Images.MyModelId, - Name = "Grid Design", - IsDirectory = false, - HasDirectories = false, - Extension = ".jpg", - DateCreated = new DateTime(2022, 1, 12), - DateCreatedUtc = new DateTime(2022, 1, 12), - DateModified = new DateTime(2022, 2, 13), - DateModifiedUtc = new DateTime(2022, 2, 13), - Path = Path.Combine(Images.Path, "Grid Design.jpg"), - Size = 1024 - }; - - var files = new List() - { - workFiles, - - Documents, - specification, - report, +### OnEdit - Images, - dashboardDesign, - gridDesign - }; +The `OnEdit` event fires when the user is about to enter edit mode for an existing item. Its event handler receives the updated `FileManagerEditEventArgs` as an argument. - return await Task.FromResult(files); - } -} -```` +### OnUpdate -## Other Events +The `OnUpdate` event fires when a file is updated (rename finishes). Its event handler receives the updated `FileManagerUpdateEventArgs` as an argument. -### OnModelInit +## OnDownload -The `OnModelInit` event fires when a new instance of the model is about to be created. Handle this event to allow the creation of a new folder/file. Provide an instance of the model that the component is bound to and include the desired properties (name, path, date of creation and more). See the [example](#example). +The `OnDownload` event fires before a file download starts. The event is cancellable. The event handler argument is an `FileManagerDownloadEventArgs` object. See the [example](#example). -### OnDownload +### MIME Type -The `OnDownload` event fires before a file download starts. The event is cancellable. The event handler argument is an `FileManagerDownloadEventArgs` object. See the [example](#example). +The `FileManagerDownloadEventArgs` event argument has a `MimeType` property, which is `null` when the `OnDownload` event fires. .NET does not provide a built-in MIME type tool, so the application must set the correct MIME type, depending on the file extension or content. Consider [`Microsoft.AspNetCore.StaticFiles`](https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/StaticFiles/src/FileExtensionContentTypeProvider.cs) or a similar tool. -#### Downloading Large Files +### Downloading Large Files The files are downloaded with the help of a Base64 data URL, which is sent to the browser through `JSInterop`. JavaScript code generates an `` tag with an [object URL](https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL_static) on the web page and the tag is clicked programmatically, so that the browser shows its **Save File** dialog. @@ -341,7 +65,7 @@ Large files (tens or hundreds of megabytes) may hit the browser's max data URL l >tip You can also vote for the [FileManager feature request to expose a Proxy Url](https://feedback.telerik.com/blazor/1633629) for serving files from the server to the browser. -#### Downloading Server Files in WebAssembly Apps +### Downloading Server Files in WebAssembly Apps A FileManager in a WebAssembly app usually displays files from a remote server. In such cases, use the following download approach: @@ -349,15 +73,31 @@ A FileManager in a WebAssembly app usually displays files from a remote server. 1. The server returns the file content. 1. The `OnDownload` handler puts the returned file content to a `MemoryStream` and assigns it to `args.Stream`. -### PathChanged +## OnModelInit + +The `OnModelInit` event fires when a new instance of the model is about to be created. Handle this event to allow the creation of a new folder/file. Provide an instance of the model that the component is bound to and include the desired properties (name, path, date of creation and more). See the [example](#example). + +## OnRead + +The `OnRead` event is an alternative way to provide the FileManager with data, instead of the `Data` parameter. The event fires when the FileManager is initialized. The event handler receives a `FileManagerReadEventArgs` object as an argument. + +Use the `OnRead` event if you want to load chunks of FileManager data on demand. The following API members are required: + +* `PathChanged` event +* `Rebind()` method +* `OnRead` event + +For more information, refer to [How to Load FileManager File Data on Demand](slug:filemanager-kb-load-file-data-on-demand). + +## PathChanged The `PathChanged` event fires when the user navigates to a different folder through the TreeView or by double-clicking a folder item in the [FileManager View](slug:filemanager-views). The event handler receives the new path as a `string` argument. -### SelectedItemsChanged +## SelectedItemsChanged The `SelectedItemChanged` event fires every time the user clicks on a new file/folder in the main pane of the FileManager. You can use it with one-way binding of the `SelectedItems` parameter to respond to user selection. -### ViewChanged +## ViewChanged The `ViewChanged` event fires when the user toggles between the [two FileManager views (`Grid` and `ListView`)](slug:filemanager-views). If you are using the event, make sure to update the value of the `View` parameter, otherwise the user action will have no effect. @@ -477,24 +217,31 @@ The `ViewChanged` event fires when the user toggles between the [two FileManager private async Task OnDownloadHandler(FileManagerDownloadEventArgs args) { - var selectedItem = args.Item as FlatFileEntry; + var downloadedFile = (FlatFileEntry)args.Item; // The Filemanager does not have the actual file. - // Obtain the file contents, based on args.Item, and set the event arguments: + // Obtain the file contents, based on args.Item, and set the event arguments. + + // Get the full file path + //string filePathWithoutStartSeparator = downloadedFile.Path.IndexOf(Path.DirectorySeparatorChar) == 0 ? downloadedFile.Path.Substring(1) : downloadedFile.Path; + //string fullFilePath = Path.Combine(BasePath, filePathWithoutStartSeparator); - //args.Stream = the file stream of the actual selected file; - //args.MimeType = the MIME type of the actual file; - //args.FileName = the file name that the browser will receive (optional); + // Create a MemoryStream with the file contents + //byte[] fileBytes = await System.IO.File.ReadAllBytesAsync(fullFilePath); + //MemoryStream fileStream = new(fileBytes); - FlatFileEntry actualFile = (FlatFileEntry)args.Item; + // Set the event arguments + //args.FileName = string.Concat(downloadedFile.Name, downloadedFile.Extension); + //args.MimeType = "application/octet-stream"; + //args.Stream = fileStream; await Task.Delay(1); // simulate async operation - string dummyFileContent = $"This file is a dummy version of {actualFile.Name}. It was downloaded with the Telerik Blazor FileManager."; + string dummyFileContent = $"This file is a dummy version of {downloadedFile.Name}. It was downloaded with the Telerik Blazor FileManager."; byte[] dummyFileBuffer = System.Text.Encoding.UTF8.GetBytes(dummyFileContent); args.Stream = new MemoryStream(dummyFileBuffer); args.MimeType = "text/plain"; - args.FileName = $"filemanager-{actualFile.Name}-{DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss")}.txt"; + args.FileName = $"filemanager-{downloadedFile.Name}-{DateTime.Now.ToString("HH-mm-ss")}.txt"; } private async Task OnDeleteHandler(FileManagerDeleteEventArgs args) diff --git a/knowledge-base/filemanager-load-file-data-on-demand.md b/knowledge-base/filemanager-load-file-data-on-demand.md new file mode 100644 index 000000000..23168a57c --- /dev/null +++ b/knowledge-base/filemanager-load-file-data-on-demand.md @@ -0,0 +1,207 @@ +--- +title: Load FileManager File Data on Demand +description: Learn how to load the files from the currently selected folder in the FileManager for better performance. +type: how-to +page_title: How to Load FileManager File Data on Demand +slug: filemanager-kb-load-file-data-on-demand +tags: telerik, blazor, filemanager +ticketid: 1677209, 1665314, 1608943, 1606421, 1566070 +res_type: kb +--- + +## Environment + + + + + + + + +
ProductFileManager for Blazor
+ +## Description + +This KB article answers the following questions: + +* How to load FileManager files on demand? +* How to lazy load the FileManager data? +* How to bind the FileManager only to the files from the currently selected folder? +* How to implement data virtualization for the Telerik FileManager for Blazor? +* How to dynamically add folders and files to the FileManager data? + +## Solution + +1. Subscribe the to the [FileManager `PathChanged` event](slug:filemanager-events#pathchanged). +1. Subscribe to the [FileManager `OnRead` event](slug:filemanager-events#onread). +1. Obtain the [FileManager `@ref` (component instance)](slug:filemanager-overview#reference-and-methods). +1. Call the FileManager `Rebind()` method in the `PathChanged` event handler. +1. Load all folders for the FileManager TreeView and the files from the current folder. Set this collection to [`args.Data` in the `OnRead` handler](slug:common-features-data-binding-onread#event-argument). + +>caption Load FileManager file data on demand using OnRead and PathChanged + +````RAZOR +@using System.IO +@using Telerik.DataSource.Extensions + +

+ Total folder and file count: @FlatData.Count; + Folders loaded: @FoldersLoadedCount; + Files loaded: @FilesLoadedCount +

+ +

Path: @FlatDirectoryPath

+ + + + +@code { + private TelerikFileManager? FileManagerRef { get; set; } + private List FlatData { get; set; } = new List(); + + private readonly string RootPath = string.Empty; + private string FlatDirectoryPath { get; set; } = string.Empty; + + private int FoldersLoadedCount { get; set; } + private int FilesLoadedCount { get; set; } + + private int FolderLevelCount { get; set; } = 5; + private int FilesInFolderMinCount { get; set; } = 3; + private int FilesInFolderMaxCount { get; set; } = 24; + private int FoldersInFolderCount { get; set; } = 3; + private int FolderNameCounter { get; set; } + private readonly List FileExtensions = new() { + ".txt", ".pdf", ".docx", ".xlsx", ".png", ".jpg", ".gif", ".zip", ".css", ".html", ".mp3", ".mpg" + }; + + private void FileManagerPathChanged(string newPath) + { + FlatDirectoryPath = newPath; + + FileManagerRef?.Rebind(); + } + + private async Task OnFileManagerRead(FileManagerReadEventArgs args) + { + var allFoldersAndVisibleFiles = FlatData.Where(x => + // all folders + x.IsDirectory || + // all files if in the root folder + (FlatDirectoryPath == RootPath && x.Path.IndexOf(Path.DirectorySeparatorChar) == x.Path.LastIndexOf(Path.DirectorySeparatorChar)) || + // all files if in another folder + x.Path.Replace(string.Concat(Path.DirectorySeparatorChar, x.Name, x.Extension), string.Empty) == FlatDirectoryPath); + + args.Data = allFoldersAndVisibleFiles; + args.Total = allFoldersAndVisibleFiles.Count(); + + FoldersLoadedCount = allFoldersAndVisibleFiles.Where(x => x.IsDirectory).Count(); + FilesLoadedCount = allFoldersAndVisibleFiles.Count() - FoldersLoadedCount; + + await Task.Delay(1); // simulate async operation + } + + protected override async Task OnInitializedAsync() + { + await Task.CompletedTask; + + FlatDirectoryPath = RootPath; + + FlatData = LoadFlatDataAsync(); + + await base.OnInitializedAsync(); + } + + private List LoadFlatDataAsync() + { + List data = new List(); + + string rootDataPath = string.IsNullOrEmpty(RootPath) ? "/" : RootPath; + + PopulateChildren(data, null, rootDataPath, 1); + + return data; + } + + private void PopulateChildren(List data, string? parentId, string parentPath, int level) + { + var rnd = Random.Shared; + var filesInCurrentFolder = rnd.Next(FilesInFolderMinCount, FilesInFolderMaxCount); + + for (int i = 1; i <= filesInCurrentFolder; i++) + { + string itemId = Guid.NewGuid().ToString(); + string itemExtension = FileExtensions[rnd.Next(0, FileExtensions.Count)]; + string itemName = $"{itemExtension.Substring(1)}-file-{(FolderNameCounter != default ? string.Concat(FolderNameCounter, "-") : string.Empty)}{i}"; + string itemPath = Path.Combine(parentPath, string.Concat(itemName, itemExtension)); + + data.Add(new FlatFileEntry() + { + Id = itemId, + ParentId = parentId, + Name = itemName, + IsDirectory = false, + HasDirectories = false, + DateCreated = DateTime.Now, + DateCreatedUtc = DateTime.Now.ToUniversalTime(), + DateModified = DateTime.Now, + DateModifiedUtc = DateTime.Now.ToUniversalTime(), + Path = itemPath, + Extension = itemExtension, + Size = rnd.Next(1_000, 3_000_000) + }); + } + + if (level < FolderLevelCount) + { + for (int i = 1; i <= FoldersInFolderCount; i++) + { + var itemId = Guid.NewGuid().ToString(); + var itemName = $"folder-{++FolderNameCounter}"; + var itemPath = Path.Combine(parentPath, itemName); + + data.Add(new FlatFileEntry() + { + Id = itemId, + ParentId = parentId, + Name = itemName, + IsDirectory = true, + HasDirectories = level < FolderLevelCount - 1, + DateCreated = DateTime.Now, + DateCreatedUtc = DateTime.Now.ToUniversalTime(), + DateModified = DateTime.Now, + DateModifiedUtc = DateTime.Now.ToUniversalTime(), + Path = itemPath, + Size = rnd.Next(100_000, 10_000_000) + }); + + PopulateChildren(data, itemId, itemPath, level + 1); + } + } + } + + public class FlatFileEntry + { + public string Id { get; set; } = Guid.NewGuid().ToString(); + public string? ParentId { get; set; } + public string Name { get; set; } = string.Empty; + public long Size { get; set; } + public string Path { get; set; } = string.Empty; + public string Extension { get; set; } = string.Empty; + public bool IsDirectory { get; set; } + public bool HasDirectories { get; set; } + public DateTime DateCreated { get; set; } + public DateTime DateCreatedUtc { get; set; } + public DateTime DateModified { get; set; } + public DateTime DateModifiedUtc { get; set; } + } +} +```` + +## See Also + +* [FileManager Events](slug:filemanager-events) From e73a1cff136ecda352dfd83bfd29e8326ab06c04 Mon Sep 17 00:00:00 2001 From: Dimo Dimov <961014+dimodi@users.noreply.github.com> Date: Thu, 19 Jun 2025 14:50:58 +0300 Subject: [PATCH 2/8] minor fixes --- .../data-binding/hierarchical-data.md | 2 +- .../filemanager/data-binding/overview.md | 28 ++++++++----------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/components/filemanager/data-binding/hierarchical-data.md b/components/filemanager/data-binding/hierarchical-data.md index 2cb836510..a80df51fa 100644 --- a/components/filemanager/data-binding/hierarchical-data.md +++ b/components/filemanager/data-binding/hierarchical-data.md @@ -14,7 +14,7 @@ This article explains how to bind the FileManager for Blazor to hierarchical dat Hierarchical data means that the collection of child items is provided in a field of its parent's model: -* The `Items` field contains a collection of all children including sub-folders and files. They will be rendered in the [Preview Pane](slug:filemanager-preview-pane) when the parent folder is selected. +* The `Items` field contains a collection of all children including sub-folders and files. They will be rendered in the [FileManager View](slug:filemanager-views) when the parent folder is selected. * The `Directories` field contains a collection of the subfolders of a directory. They will be rendered in the TreeView navigation pane. If there are `Directories` for a specific folder it will have an expand icon. The `HasDirectories` field can override this, however, but it is not required for hierarchical data binding. diff --git a/components/filemanager/data-binding/overview.md b/components/filemanager/data-binding/overview.md index fdb3162cd..dbd2aee90 100644 --- a/components/filemanager/data-binding/overview.md +++ b/components/filemanager/data-binding/overview.md @@ -8,26 +8,20 @@ published: True position: 0 --- -# FileManager Data Binding Basics +# FileManager Data Binding Overview -This article explains the different ways to provide data to a FileManager component and the properties related to data binding. Reviewing this article will explain the basics of how you can describe the hierarchy of items in your data source to the treeview component so they can render. +This FileManager Data Binding section explains the different ways to provide data to a FileManager component and the properties related to data binding. This article describes what are the available (bindable) features of FileManager data items and how to map model properties to these features. -@[template](/_contentTemplates/common/general-info.md#valuebind-vs-databind-link) - -First, review: - -* The available (bindable) [features of a FileManager items](#filemanager-item-features). -* How to match fields in the model with the FileManager item [data bindings](#data-bindings). +There are two data binding modes that the FileManager supports: -There are two modes of providing data to a FileManager, and they both use the items' features. Once you are familiar with the current article, choose the data binding more you wish to use: +* [Flat data](slug:filemanager-data-binding-flat-data)—a collection of self-referencing items with parent-child relationships. +* [Hierarchical data](slug:filemanager-data-binding-hierarchical-data)—each item holds its children in a nested property. -* [Flat data](slug:filemanager-data-binding-flat-data) - a collection of self-referencing items with parent-child relationships See the `Id` and `ParentId` settings. - -* [Hierarchical data](slug:filemanager-data-binding-hierarchical-data) - each item holds its children in a nested property. See the `Directories` setting. +@[template](/_contentTemplates/common/general-info.md#valuebind-vs-databind-link) ## FileManager Item Features -The FileManager has features that map to properties in the model. The following model uses property names that will work automatically, with no additional FileManager configuration: +The FileManager has features that map to properties in the model. The following flat data model uses property names that will work automatically, with no additional FileManager configuration: ````RAZOR @using System.IO @@ -227,9 +221,9 @@ The FileManager has features that map to properties in the model. The following The following section describe the meaning of the model properties for the FileManager. -### Data Bindings +## Data Bindings -All [FileManager item features](#fileManager-item-features) map to model properties. The properties of a FileManager item match directly to a field of the component model. You define that relationship by providing the property name from which the corresponding information is taken. To do this, use the following parameters of the main `TelerikFileManager` tag: +All [FileManager item features](#fileManager-item-features) map to model properties. You define that relationship by providing the property name from which the corresponding information is taken. To do this, use the following parameters of the main `TelerikFileManager` tag: @[template](/_contentTemplates/common/parameters-table-styles.md#table-layout) @@ -249,8 +243,8 @@ All [FileManager item features](#fileManager-item-features) map to model propert | `IdField `| `"Id" ` | any | The unique identifier of the file. Required for [binding to flat data](slug:filemanager-data-binding-flat-data). | | `ParentIdField`| `"ParentId"` | any | Identifies the item's parent. Required for [binding to flat data](slug:filemanager-data-binding-flat-data). Set to `null` for root items. Do not use `ParentId` with hierarchical data. | | `HasDirectoriesField`| `"HasDirectories"` | `bool` | Determines whether the item has child folders. Required for [binding to flat data](slug:filemanager-data-binding-flat-data) If `true`, the folder will show an expand arrow in the TreeView. With [hierarchical data](slug:filemanager-data-binding-hierarchical-data), the FileManager renders expand icons based on `Directories`, but `HasDirectories` takes precedence. | -| `DirectoriesField`| `"Directories"` | `IEnumerable` | The item's child folders. Required for [binding to hierarchical data](slug:filemanager-data-binding-hierarchical-data) | -| `ItemsField`| `"Items"` | `IEnumerable` | The folder's child files. Required for [binding to hierarchical data](slug:filemanager-data-binding-hierarchical-data). | +| `DirectoriesField`| `"Directories"` | `IEnumerable` | The item's child folders to display in the TreeView. Required for [binding to hierarchical data](slug:filemanager-data-binding-hierarchical-data) | +| `ItemsField`| `"Items"` | `IEnumerable` | The folder's child files and folders to display in the FileManager view. Required for [binding to hierarchical data](slug:filemanager-data-binding-hierarchical-data). | >important Do not use `ParentId` with hierarchical data. This will confuse the FileManager that it is bound to flat data and the component may not render any items. If the model must have a `ParentId` property, set `ParentIdField` to a non-existent property name. From 2721c41cca396a6b9ce5fea30b6e50085aa28804 Mon Sep 17 00:00:00 2001 From: Dimo Dimov <961014+dimodi@users.noreply.github.com> Date: Fri, 20 Jun 2025 11:06:52 +0300 Subject: [PATCH 3/8] Update components/filemanager/data-binding/overview.md Co-authored-by: Iva Stefanova Koevska-Atanasova --- components/filemanager/data-binding/overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/filemanager/data-binding/overview.md b/components/filemanager/data-binding/overview.md index dbd2aee90..f295157d3 100644 --- a/components/filemanager/data-binding/overview.md +++ b/components/filemanager/data-binding/overview.md @@ -219,7 +219,7 @@ The FileManager has features that map to properties in the model. The following } ```` -The following section describe the meaning of the model properties for the FileManager. +The following section describes the meaning of the model properties for the FileManager. ## Data Bindings From 0970a77646095b5943fb571fec5ba4f4fccb474b Mon Sep 17 00:00:00 2001 From: Dimo Dimov <961014+dimodi@users.noreply.github.com> Date: Fri, 20 Jun 2025 11:08:09 +0300 Subject: [PATCH 4/8] Update components/filemanager/data-binding/overview.md --- components/filemanager/data-binding/overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/filemanager/data-binding/overview.md b/components/filemanager/data-binding/overview.md index f295157d3..d48412aa2 100644 --- a/components/filemanager/data-binding/overview.md +++ b/components/filemanager/data-binding/overview.md @@ -234,7 +234,7 @@ All [FileManager item features](#fileManager-item-features) map to model propert | `SizeField`| `"Size"` | `long` | The size of the file in bytes. | | `PathField`| `"Path"` | `string` | The path to the item, including the name and extension. | | `ExtensionField`| `"Extension"` | `string` | The item extension, starting with a dot `.` | -| `IsDirectoryField`| `"IsDirectoryField"` | `bool` | Whether the item is a folder. If `false`, it's treated as a file. | +| `IsDirectoryField`| `"IsDirectory"` | `bool` | Whether the item is a folder. If `false`, it's treated as a file. | | `DateCreatedField`| `"DateCreated"` | `DateTime` | The creation date of the file. | | `DateCreateUtcField`| `"DateCreateUtc"` | `DateTime` | The creation date of the file in UTC. Required. | | `DateModifiedField`| `"DateModified"` | `DateTime` | The modification date of the file. | From 9db21918fbd44f77fb0a0833470c689cc1b0456c Mon Sep 17 00:00:00 2001 From: Dimo Dimov <961014+dimodi@users.noreply.github.com> Date: Fri, 20 Jun 2025 11:08:35 +0300 Subject: [PATCH 5/8] Update components/filemanager/data-binding/overview.md --- components/filemanager/data-binding/overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/filemanager/data-binding/overview.md b/components/filemanager/data-binding/overview.md index d48412aa2..ef619dc88 100644 --- a/components/filemanager/data-binding/overview.md +++ b/components/filemanager/data-binding/overview.md @@ -236,7 +236,7 @@ All [FileManager item features](#fileManager-item-features) map to model propert | `ExtensionField`| `"Extension"` | `string` | The item extension, starting with a dot `.` | | `IsDirectoryField`| `"IsDirectory"` | `bool` | Whether the item is a folder. If `false`, it's treated as a file. | | `DateCreatedField`| `"DateCreated"` | `DateTime` | The creation date of the file. | -| `DateCreateUtcField`| `"DateCreateUtc"` | `DateTime` | The creation date of the file in UTC. Required. | +| `DateCreatedUtcField`| `"DateCreatedUtc"` | `DateTime` | The creation date of the file in UTC. Required. | | `DateModifiedField`| `"DateModified"` | `DateTime` | The modification date of the file. | | `DateModifiedUtcField`| `"DateModifiedUtc"` | `DateTime` | The modification date of the file in UTC. Required. | | **Item relations** | | | | From 1224b4d0bea5dc6931eb83a1224b76cf65ef8ff6 Mon Sep 17 00:00:00 2001 From: Dimo Dimov <961014+dimodi@users.noreply.github.com> Date: Fri, 20 Jun 2025 11:08:49 +0300 Subject: [PATCH 6/8] Update components/filemanager/data-binding/overview.md Co-authored-by: Iva Stefanova Koevska-Atanasova --- components/filemanager/data-binding/overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/filemanager/data-binding/overview.md b/components/filemanager/data-binding/overview.md index ef619dc88..60e8ca354 100644 --- a/components/filemanager/data-binding/overview.md +++ b/components/filemanager/data-binding/overview.md @@ -242,7 +242,7 @@ All [FileManager item features](#fileManager-item-features) map to model propert | **Item relations** | | | | | `IdField `| `"Id" ` | any | The unique identifier of the file. Required for [binding to flat data](slug:filemanager-data-binding-flat-data). | | `ParentIdField`| `"ParentId"` | any | Identifies the item's parent. Required for [binding to flat data](slug:filemanager-data-binding-flat-data). Set to `null` for root items. Do not use `ParentId` with hierarchical data. | -| `HasDirectoriesField`| `"HasDirectories"` | `bool` | Determines whether the item has child folders. Required for [binding to flat data](slug:filemanager-data-binding-flat-data) If `true`, the folder will show an expand arrow in the TreeView. With [hierarchical data](slug:filemanager-data-binding-hierarchical-data), the FileManager renders expand icons based on `Directories`, but `HasDirectories` takes precedence. | +| `HasDirectoriesField`| `"HasDirectories"` | `bool` | Determines whether the item has child folders. Required for [binding to flat data](slug:filemanager-data-binding-flat-data). If `true`, the folder will show an expand arrow in the TreeView. With [hierarchical data](slug:filemanager-data-binding-hierarchical-data), the FileManager renders expand icons based on `Directories`, but `HasDirectories` takes precedence. | | `DirectoriesField`| `"Directories"` | `IEnumerable` | The item's child folders to display in the TreeView. Required for [binding to hierarchical data](slug:filemanager-data-binding-hierarchical-data) | | `ItemsField`| `"Items"` | `IEnumerable` | The folder's child files and folders to display in the FileManager view. Required for [binding to hierarchical data](slug:filemanager-data-binding-hierarchical-data). | From 7381ca170e76b14a29c6d09c9e6973db4cb11e30 Mon Sep 17 00:00:00 2001 From: Dimo Dimov <961014+dimodi@users.noreply.github.com> Date: Fri, 20 Jun 2025 11:08:57 +0300 Subject: [PATCH 7/8] Update components/filemanager/data-binding/overview.md Co-authored-by: Iva Stefanova Koevska-Atanasova --- components/filemanager/data-binding/overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/filemanager/data-binding/overview.md b/components/filemanager/data-binding/overview.md index 60e8ca354..8659e69de 100644 --- a/components/filemanager/data-binding/overview.md +++ b/components/filemanager/data-binding/overview.md @@ -243,7 +243,7 @@ All [FileManager item features](#fileManager-item-features) map to model propert | `IdField `| `"Id" ` | any | The unique identifier of the file. Required for [binding to flat data](slug:filemanager-data-binding-flat-data). | | `ParentIdField`| `"ParentId"` | any | Identifies the item's parent. Required for [binding to flat data](slug:filemanager-data-binding-flat-data). Set to `null` for root items. Do not use `ParentId` with hierarchical data. | | `HasDirectoriesField`| `"HasDirectories"` | `bool` | Determines whether the item has child folders. Required for [binding to flat data](slug:filemanager-data-binding-flat-data). If `true`, the folder will show an expand arrow in the TreeView. With [hierarchical data](slug:filemanager-data-binding-hierarchical-data), the FileManager renders expand icons based on `Directories`, but `HasDirectories` takes precedence. | -| `DirectoriesField`| `"Directories"` | `IEnumerable` | The item's child folders to display in the TreeView. Required for [binding to hierarchical data](slug:filemanager-data-binding-hierarchical-data) | +| `DirectoriesField`| `"Directories"` | `IEnumerable` | The item's child folders to display in the TreeView. Required for [binding to hierarchical data](slug:filemanager-data-binding-hierarchical-data). | | `ItemsField`| `"Items"` | `IEnumerable` | The folder's child files and folders to display in the FileManager view. Required for [binding to hierarchical data](slug:filemanager-data-binding-hierarchical-data). | >important Do not use `ParentId` with hierarchical data. This will confuse the FileManager that it is bound to flat data and the component may not render any items. If the model must have a `ParentId` property, set `ParentIdField` to a non-existent property name. From 122a2174f3a843bdcb99e56a404e788ca11bb2d9 Mon Sep 17 00:00:00 2001 From: Dimo Dimov <961014+dimodi@users.noreply.github.com> Date: Fri, 20 Jun 2025 11:11:04 +0300 Subject: [PATCH 8/8] Update components/filemanager/data-binding/overview.md --- components/filemanager/data-binding/overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/filemanager/data-binding/overview.md b/components/filemanager/data-binding/overview.md index 8659e69de..6c765f684 100644 --- a/components/filemanager/data-binding/overview.md +++ b/components/filemanager/data-binding/overview.md @@ -21,7 +21,7 @@ There are two data binding modes that the FileManager supports: ## FileManager Item Features -The FileManager has features that map to properties in the model. The following flat data model uses property names that will work automatically, with no additional FileManager configuration: +The FileManager extracts information about the displayed files and folders from properties in the model. The following flat data model uses property names that will work automatically, with no additional FileManager configuration: ````RAZOR @using System.IO