From c2802dafe7ad919b0de9d492f317f4273692894b Mon Sep 17 00:00:00 2001 From: Dimo Dimov Date: Mon, 13 Sep 2021 16:18:28 +0300 Subject: [PATCH 1/5] Add interface binding docs --- _contentTemplates/treelist/databinding.md | 5 +- components/grid/data-binding.md | 147 ++++++++++++++++++ components/grid/overview.md | 30 +--- components/treelist/data-binding/interface.md | 127 +++++++++++++++ components/treelist/data-binding/overview.md | 1 - 5 files changed, 279 insertions(+), 31 deletions(-) create mode 100644 components/grid/data-binding.md create mode 100644 components/treelist/data-binding/interface.md diff --git a/_contentTemplates/treelist/databinding.md b/_contentTemplates/treelist/databinding.md index ad72816ee7..0c75ff6fa4 100644 --- a/_contentTemplates/treelist/databinding.md +++ b/_contentTemplates/treelist/databinding.md @@ -4,9 +4,10 @@ * [Flat data]({%slug treelist-data-binding-flat-data%}) - a single collection of items with defined parent-child relationships. See the `Id` and `ParentId` settings. -In either mode you can also do [Load on Demand]({%slug treelist-data-binding-load-on-demand%}) or lazy loading - that is, provide children to a node when it expands through an event. See the `HasChildren` setting and the `OnExpand` event. -#end +In either mode, you can implement [Load on Demand]({%slug treelist-data-binding-load-on-demand%}) or lazy loading - that is, provide children to a node when it expands through an event. See the `HasChildren` setting and the `OnExpand` event. +Finally, you can also [bind the TreeList to an interface]({%slug treelist-data-binding-interface%}), no matter if you are using flat data or hierarchical data. +#end #link-to-basics diff --git a/components/grid/data-binding.md b/components/grid/data-binding.md new file mode 100644 index 0000000000..c3689789e1 --- /dev/null +++ b/components/grid/data-binding.md @@ -0,0 +1,147 @@ +--- +title: Data Binding +page_title: Data Binding | Grid for Blazor +description: Data bind the Blazor Grid to any of the supported data sources. +slug: grid-data-binding +tags: telerik,blazor,grid,data,binding,databind,databinding +published: true +position: 10 +--- + +# Grid Data Binding + +Telerik Blazor Grid is data source agnostic - you can use any database and service according to your project. You only need to get the collection of data models to the Grid in the view-model of the component hosting it. + +## Data Sources and Scenarios + +The following list of resources provides examples for data binding a grid in various scenarios: + +* Basic **example**, tutorial **video** and **notes** - [Grid Bound Columns Overview]({%slug components/grid/columns/bound%}). Also lists the features (parameters) of a bound column. + +* **Optimizing the data source queries** - see the [Notes]({%slug components/grid/columns/bound%}#notes) section in the article above. In a server-side app, an `IQueriable` that ties to an appropriate context (such as EntityFramework) that can optimize the LINQ queries the grid generates is a quick option. For full control, use the [OnRead event]({%slug components/grid/manual-operations%}). + +* **SQL** (or any other) **database** - you can find examples in our [online demos](https://demos.telerik.com/blazor-ui/grid/overview). You can see an offline version of the demos project in the `demos` folder of your installation ([automated]({%slug installation/msi%}) or [archive]({%slug installation/zip%})). They showcase an EntityFramework context using an SQL database that provides data to a grid through a service, which is a common architecture for decouping the front-end from the actual data source that you can apply to any database. + + * The **CRUD sample project** our extensions for [Visual Studio]({%slug getting-started-vs-integration-new-project%}) and [Visual Studio Code]({%slug getting-started-vs-code-integration-overview%}) can generate for you showcases a similar architecture that you can use as a starting point. + + * The [Blazing Coffee sample application](https://github.com/telerik/blazor-ui/tree/master/sample-applications/blazing-coffee) shows how to provide data from a SQL (uses SQLite) database to the Grid using Entity Framework Core services. + +* **WebAPI** data source - you can see how to send an appropriate request for data and return an optimized query in the following sample projects: [Grid DataSourceRequest on the server](https://github.com/telerik/blazor-ui/tree/master/grid/datasourcerequest-on-server). This is a flexible approach that you can use for any type of service you have - serializing and deserializing the data according to the application logic and needs, and optimizing the database queries on the backend. + +* **OData** data source - an extension method we provide lets you make OData v4 queries as shown in the following example: [Grid and OData](https://github.com/telerik/blazor-ui/tree/master/grid/odata). + +* **DataTable**, **ExpandoObject** collection - If you don't have actual strongly typed models (yet) and you use `ExpandoObject`, or your backend comes from an older technology and still returns `DataTable`s, the grid can accommodate such dynamic data types. You can get started from our examples on how to bind the grid to a [ExpandoObject collection](https://github.com/telerik/blazor-ui/tree/master/grid/binding-to-expando-object) and to a [DataTable](https://demos.telerik.com/blazor-ui/grid/data-table) which also support [editing]({%slug components/grid/overview%}#editing). + +* **gRPC** - the gRPC tooling supports .NET Core, and as of mid-June 2020, there is a package that brings it to WebAssembly. You can find a basic example and more resources to get you started with gRPC in Blazor in the [Grid Data from gRPC Sample Project](https://github.com/telerik/blazor-ui/tree/master/common/grpc-example). + +* **Foreign Keys** - using foreign tables and keys is usually done through the grid templates. You can read more and find examples in the [Grid - Foreign Key]({%slug grids-foreign-key%}) KnowledgeBase article. + +## Binding to Interface + +Since version 2.27, the Grid supports binding to a collection of multiple model types that implement the same interface. + +Note the usage of [`OnModelInit`]({%slug grid-events%}#onmodelinit) in the example below. The event handler sets the model type to be used for new items in the Grid. One-type model creation is supported out-of-the-box. If you need to support adding instances of different types: + +* Use custom **Add** buttons in the [Grid Toolbar]({%slug components/grid/features/toolbar%}), one for each model type. +* In each button click handler, define an `InsertedItem` of the correct type in the [Grid State]({%slug grid-state%}). +* [Put the Grid in Insert mode]({%slug grid-state%}#initiate-editing-or-inserting-of-an-item) with the [SetState method]({%slug grid-state%}#methods). + +>caption Data Binding the Grid to an Interface + +````CSHTML + + + Add + + + + + Edit + Save + Cancel + + + + +@code { + public interface IModel + { + public int Id { get; set; } + public int IntProperty { get; set; } + } + + public class Model1 : IModel + { + public int Id { get; set; } + public int IntProperty { get; set; } + } + + public class Model2 : IModel + { + public int Id { get; set; } + public int IntProperty { get; set; } + } + + List GridData { get; set; } + + protected override void OnInitialized() + { + var data = new List(); + + data.Add(new Model1() + { + Id = 1, + IntProperty = 1 + }); + data.Add(new Model2() + { + Id = 2, + IntProperty = 2 + }); + + GridData = data; + } + + public void UpdateHandler(GridCommandEventArgs args) + { + var model = (IModel)args.Item; + + var matchingItem = GridData.FirstOrDefault(c => c.Id == model.Id); + + if (matchingItem != null) + { + matchingItem.IntProperty = model.IntProperty; + } + } + + public void DeleteHandler(GridCommandEventArgs args) + { + var model = (IModel)args.Item; + + GridData.Remove(model); + } + + public void CreateHandler(GridCommandEventArgs args) + { + var model = (IModel)args.Item; + + model.Id = GridData.Max(d => d.Id) + 1; + + GridData.Insert(0, model); + } +} +```` + +>note Up to version 2.26, the `Data` collection of the Grid must contain instances of only one model type. + +## See Also + + * [Live Demo: Bind Grid to Observable Data](https://demos.telerik.com/blazor-ui/grid/observable-data) + * [Live Demo: Bind Grid to DataTable](https://demos.telerik.com/blazor-ui/grid/data-table) + * [Live Demo: Manual Grid Data Operations](https://demos.telerik.com/blazor-ui/grid/manual-operations) diff --git a/components/grid/overview.md b/components/grid/overview.md index 3ef3fb8ae0..f988aac45f 100644 --- a/components/grid/overview.md +++ b/components/grid/overview.md @@ -69,35 +69,9 @@ General grid with its most common features ## Data Binding -To show data in a grid, you need to define [GridColumn]({%slug components/grid/columns/bound%}) instances - they take a model `Field` and expose settings for [templates]({%slug components/grid/features/templates%}), [grouping](#grouping) and [reordering]({%slug components/grid/columns/reorder%}). To [edit](#editing) data or invoke custom logic, you define a [CommandColumn]({%slug components/grid/columns/command%}). - ->tip The Telerik Blazor Grid is data source agnostic - you can use any database and service according to your project, you only need to get the collection of data models to the grid in the view-model of the component hosting it. - -The following list of resources provides examples for data binding a grid in various scenarios: - -* Basic **example**, tutorial **video** and **notes** - [Grid Data Binding Overview]({%slug components/grid/columns/bound%}). Also lists the features (parameters) of a bound column. - -* **Optimizing the data source queries** - see the [Notes]({%slug components/grid/columns/bound%}#notes) section in the article above. In a server-side app, an `IQueriable` that ties to an appropriate context (such as EntityFramework) that can optimize the LINQ queries the grid generates is a quick option. For full control, use the [OnRead event]({%slug components/grid/manual-operations%}). - -* **SQL** (or any other) **database** - you can find examples in our [online demos](https://demos.telerik.com/blazor-ui/grid/overview). You can see an offline version of the demos project in the `demos` folder of your installation ([automated]({%slug installation/msi%}) or [archive]({%slug installation/zip%})). They showcase an EntityFramework context using an SQL database that provides data to a grid through a service, which is a common architecture for decouping the front-end from the actual data source that you can apply to any database. - - * The **CRUD sample project** our extensions for [Visual Studio]({%slug getting-started-vs-integration-new-project%}) and [Visual Studio Code]({%slug getting-started-vs-code-integration-overview%}) can generate for you showcases a similar architecture that you can use as a starting point. - - * The [Blazing Coffee sample application](https://github.com/telerik/blazor-ui/tree/master/sample-applications/blazing-coffee) shows how to provide data from a SQL (uses SQLite) database to the Grid using Entity Framework Core services. - -* **WebAPI** data source - you can see how to send an appropriate request for data and return an optimized query in the following sample projects: [Grid DataSourceRequest on the server](https://github.com/telerik/blazor-ui/tree/master/grid/datasourcerequest-on-server). This is a flexible approach that you can use for any type of service you have - serializing and deserializing the data according to the application logic and needs, and optimizing the database queries on the backend. - -* **OData** data source - an extension method we provide lets you make OData v4 queries as shown in the following example: [Grid and OData](https://github.com/telerik/blazor-ui/tree/master/grid/odata). - -* **DataTable**, **ExpandoObject** collection - If you don't have actual strongly typed models (yet) and you use `ExpandoObject`, or your backend comes from an older technology and still returns `DataTable`s, the grid can accommodate such dynamic data types. You can get started from our examples on how to bind the grid to a [ExpandoObject collection](https://github.com/telerik/blazor-ui/tree/master/grid/binding-to-expando-object) and to a [DataTable](https://demos.telerik.com/blazor-ui/grid/data-table) which also support [editing](#editing). - -* **gRPC** - the gRPC tooling supports .NET Core, and as of mid-June 2020, there is a package that brings it to WebAssembly. You can find a basic example and more resources to get you started with gRPC in Blazor in the [Grid Data from gRPC Sample Project](https://github.com/telerik/blazor-ui/tree/master/common/grpc-example). - -* **Foreign Keys** - using foreign tables and keys is usually done through the grid templates. You can read more and find examples in the [Grid - Foreign Key]({%slug grids-foreign-key%}) KnowledgeBase article. - - ->note The `Data` collection of the grid must contain instances of only one model type. +To show data in a Grid, you need to define [GridColumn]({%slug components/grid/columns/bound%}) instances or allow the Grid to [generate columns automatically]({%slug grid-columns-automatically-generated%}). Declared columns take a model `Field` and expose settings for [templates]({%slug components/grid/features/templates%}), [grouping](#grouping) and [reordering]({%slug components/grid/columns/reorder%}). To [edit](#editing) data or invoke custom logic, you define a [CommandColumn]({%slug components/grid/columns/command%}). +The [Grid Data Binding article]({%slug grid-data-binding%}) provides detailed information and examples about binding the Grid in different scenarios and to various data sources. ### Loading Animation diff --git a/components/treelist/data-binding/interface.md b/components/treelist/data-binding/interface.md new file mode 100644 index 0000000000..3770e1672d --- /dev/null +++ b/components/treelist/data-binding/interface.md @@ -0,0 +1,127 @@ +--- +title: Data Binding to Interface +page_title: Data Binding to Interface | TreeList for Blazor +description: Data binding the Blazor TreeList to multiple model types with the same interface. +slug: treelist-data-binding-interface +tags: telerik,blazor,treelist,data,bind,databind,databinding,interface +published: true +position: 4 +--- + +# TreeList Data Binding to Interface + +Since version 2.27, the TreeList supports binding to a collection of multiple model types that implement the same interface. + +Note the usage of [`OnModelInit`]({%slug treelist-events%}#onmodelinit) in the example below. The event handler sets the model type to be used for new items in the TreeList. One-type model creation is supported out-of-the-box. If you need to support adding instances of different types: + +* Use custom **Add** buttons in the [TreeList Toolbar]({%slug treelist-toolbar%}), one for each model type. +* In each button click handler, define an `InsertedItem` of the correct type in the [TreeList State]({%slug treelist-state%}). +* [Put the TreeList in Insert mode]({%slug treelist-state%}#initiate-editing-or-inserting-of-an-item) with the [SetState method]({%slug treelist-state%}#methods). + +>caption Data Binding the TreeList to an Interface + +````CSHTML + + + Add + + + + + Edit + Save + Cancel + + + + +@code { + public interface IModel + { + public int Id { get; set; } + public int ParentId { get; set; } + public int IntProperty { get; set; } + } + + public class Model1 : IModel + { + public int Id { get; set; } + public int ParentId { get; set; } + public int IntProperty { get; set; } + } + + public class Model2 : IModel + { + public int Id { get; set; } + public int ParentId { get; set; } + public int IntProperty { get; set; } + } + + List TreeListData { get; set; } + + protected override void OnInitialized() + { + var data = new List(); + + data.Add(new Model1() + { + Id = 1, + ParentId = null, + IntProperty = 1 + }); + data.Add(new Model2() + { + Id = 2, + ParentId = 1, + IntProperty = 2 + }); + + TreeListData = data; + } + + public void UpdateHandler(TreeListCommandEventArgs args) + { + var model = (IModel)args.Item; + + var matchingItem = TreeListData.FirstOrDefault(c => c.Id == model.Id); + + if (matchingItem != null) + { + matchingItem.IntProperty = model.IntProperty; + } + } + + public void DeleteHandler(TreeListCommandEventArgs args) + { + var model = (IModel)args.Item; + + TreeListData.Remove(model); + } + + public void CreateHandler(TreeListCommandEventArgs args) + { + var model = (IModel)args.Item; + + model.Id = TreeListData.Max(d => d.Id) + 1; + + TreeListData.Insert(0, model); + } +} +```` + +>note Up to version 2.26, the `Data` collection of the TreeList must contain instances of only one model type. + + +## See Also + + * [Binding to Flat Data]({%slug treelist-data-binding-flat-data%}) + * [Binding to Hierarchical Data]({%slug treelist-data-binding-hierarchical-data%}) + * [Load on Demand]({%slug treelist-data-binding-load-on-demand%}) + * [Live Demo: TreeList Flat Data](https://demos.telerik.com/blazor-ui/treelist/flat-data) + * [Live Demo: TreeList Hierarchical Data](https://demos.telerik.com/blazor-ui/treelist/hierarchical-data) + * [Live Demo: TreeList Load on Demand](https://demos.telerik.com/blazor-ui/treelist/lazy-loading) diff --git a/components/treelist/data-binding/overview.md b/components/treelist/data-binding/overview.md index d28bd0cf10..264eb51620 100644 --- a/components/treelist/data-binding/overview.md +++ b/components/treelist/data-binding/overview.md @@ -44,7 +44,6 @@ The properties of a treelist item match directly to a field of the model the tre * HasChildrenField => HasChildren * ItemsField => Items - ## Examples For samples of using each data binding approach listed above, see its corresponding article: From 9894a9ba30198fe3c523b81ac9fc833788f0df8a Mon Sep 17 00:00:00 2001 From: Dimo Dimov Date: Mon, 13 Sep 2021 18:22:03 +0300 Subject: [PATCH 2/5] Add link to general data binding article --- components/grid/columns/bound.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/grid/columns/bound.md b/components/grid/columns/bound.md index e583825eae..c0ff9c12f8 100644 --- a/components/grid/columns/bound.md +++ b/components/grid/columns/bound.md @@ -1,6 +1,6 @@ --- title: Data Binding -page_title: Grid - DataBound Column +page_title: Data Bound Columns | Grid for Blazor description: Data binding and bound column properties in Grid for Blazor. slug: components/grid/columns/bound tags: telerik,blazor,grid,bound,column @@ -8,10 +8,12 @@ published: True position: 0 --- -# Grid Data Binding Overview +# Grid Data Bound Columns This article explains the basics of showing data in a grid and the features of its bound columns. +Important related information are the [Grid data binding fundamentals]({%slug grid-data-binding%}). + @[template](/_contentTemplates/common/general-info.md#valuebind-vs-databind-link) Sections in this article: From 1f93c35fe6d5b821cb8f6c00ee071e6fb873a5cb Mon Sep 17 00:00:00 2001 From: Dimo Dimov Date: Tue, 14 Sep 2021 11:46:47 +0300 Subject: [PATCH 3/5] Fix page title and nullable int --- components/grid/columns/bound.md | 2 +- components/treelist/data-binding/interface.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/grid/columns/bound.md b/components/grid/columns/bound.md index c0ff9c12f8..ee04c2d5d5 100644 --- a/components/grid/columns/bound.md +++ b/components/grid/columns/bound.md @@ -1,6 +1,6 @@ --- title: Data Binding -page_title: Data Bound Columns | Grid for Blazor +page_title: Blazor Grid - Data Bound Columns | Telerik UI for Blazor description: Data binding and bound column properties in Grid for Blazor. slug: components/grid/columns/bound tags: telerik,blazor,grid,bound,column diff --git a/components/treelist/data-binding/interface.md b/components/treelist/data-binding/interface.md index 3770e1672d..3271644447 100644 --- a/components/treelist/data-binding/interface.md +++ b/components/treelist/data-binding/interface.md @@ -44,21 +44,21 @@ Note the usage of [`OnModelInit`]({%slug treelist-events%}#onmodelinit) in the e public interface IModel { public int Id { get; set; } - public int ParentId { get; set; } + public int? ParentId { get; set; } public int IntProperty { get; set; } } public class Model1 : IModel { public int Id { get; set; } - public int ParentId { get; set; } + public int? ParentId { get; set; } public int IntProperty { get; set; } } public class Model2 : IModel { public int Id { get; set; } - public int ParentId { get; set; } + public int? ParentId { get; set; } public int IntProperty { get; set; } } From a152989fe17208ba45c72ac395bb89641dae4374 Mon Sep 17 00:00:00 2001 From: Dimo Dimov Date: Tue, 14 Sep 2021 11:48:33 +0300 Subject: [PATCH 4/5] Fix page title --- components/treelist/data-binding/interface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/treelist/data-binding/interface.md b/components/treelist/data-binding/interface.md index 3271644447..eb7b6a2fe4 100644 --- a/components/treelist/data-binding/interface.md +++ b/components/treelist/data-binding/interface.md @@ -1,6 +1,6 @@ --- title: Data Binding to Interface -page_title: Data Binding to Interface | TreeList for Blazor +page_title: Blazor TreeList - Data Binding to Interface | Telerik UI for Blazor description: Data binding the Blazor TreeList to multiple model types with the same interface. slug: treelist-data-binding-interface tags: telerik,blazor,treelist,data,bind,databind,databinding,interface From 0fe5254882cd6c35915048fe766dfbd38473b6db Mon Sep 17 00:00:00 2001 From: Dimo Dimov Date: Tue, 14 Sep 2021 12:32:10 +0300 Subject: [PATCH 5/5] Fix TreeList id-parent relationship --- components/treelist/data-binding/interface.md | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/components/treelist/data-binding/interface.md b/components/treelist/data-binding/interface.md index eb7b6a2fe4..421a689f64 100644 --- a/components/treelist/data-binding/interface.md +++ b/components/treelist/data-binding/interface.md @@ -22,16 +22,18 @@ Note the usage of [`OnModelInit`]({%slug treelist-events%}#onmodelinit) in the e ````CSHTML + IdField="Id" + ParentIdField="ParentId" + EditMode="TreeListEditMode.Inline" + OnUpdate="@UpdateHandler" + OnDelete="@DeleteHandler" + OnCreate="@CreateHandler" + OnModelInit="@(() => new Model1())"> Add - + Edit Save @@ -43,21 +45,21 @@ Note the usage of [`OnModelInit`]({%slug treelist-events%}#onmodelinit) in the e @code { public interface IModel { - public int Id { get; set; } + public int? Id { get; set; } public int? ParentId { get; set; } public int IntProperty { get; set; } } public class Model1 : IModel { - public int Id { get; set; } + public int? Id { get; set; } public int? ParentId { get; set; } public int IntProperty { get; set; } } public class Model2 : IModel { - public int Id { get; set; } + public int? Id { get; set; } public int? ParentId { get; set; } public int IntProperty { get; set; } }