Updated on October 2, 2020 to use the latext Blazor syntax (.NET 5)
This blog post shows how to implement drag and drop in server-side Blazor applications. We will use the HTML 5 Drag and Drop API which is built-in in every modern browser.
Hey, we have announced Blazor support in Radzen! Check how you can create a complete Blazor CRUD application in minutes.
Sample project
Start from the default Blazor project template. Pick BlazorDragAndDrop
as the project name.
DragAndDropService
This is a service which the draggable components will use to communicate with the drop targets.
Add a new file called DragAndDropService.cs
in the Data
directory:
using System;
namespace BlazorDragAndDrop.Data
{
public class DragAndDropService
{
public object Data { get; set; }
public string Zone { get; set; }
public void StartDrag(object data, string zone)
{
this.Data = data;
this.Zone = zone;
}
public bool Accepts(string zone)
{
return this.Zone == zone;
}
}
}
Then register the DragAndDropService
in Startup.cs
:
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddSingleton<WeatherForecastService>();
services.AddSingleton<DragAndDropService>();
}
Draggable component
The next step is to create the component which the users will drag.
Add a new file Draggable.razor
in the Shared
directory:
@typeparam T
@using BlazorDragAndDrop.Data
@inject DragAndDropService DragAndDropService
<div draggable="true" @ondragstart="@OnDragStart">
@ChildContent
</div>
@code {
[Parameter]
public RenderFragment ChildContent { get; set; }
[Parameter]
public string Zone { get; set; }
[Parameter]
public T Data { get; set;}
void OnDragStart()
{
// Notify the DragAndDropService what the current Data and Zone are.
DragAndDropService.StartDrag(Data, Zone);
}
}
The Draggable
component has three properties.
ChildContent
is the user defined draggable content. We simply render it via@ChildContent
.Zone
is restricts (optinally) where this draggable can be dropped. A draggable can be dropped in a drop target only if their zones have the same value.Data
is the user specified data associated with the draggable. Can be anything.
DropTarget component
The DropTarget
accepts Draggable
components and triggers an event when the user drops one.
Add a new file DropTarget.cshtml
in the Shared
directory:
@using BlazorDragAndDrop.Data
@inject DragAndDropService DragAndDropService
@typeparam T
<div ondragover="event.preventDefault()" @ondrop="@OnDrop">
@ChildContent
</div>
@code {
[Parameter]
public RenderFragment ChildContent { get; set; }
[Parameter]
public string Zone { get; set; }
[Parameter]
public Action<T> Drop { get; set; }
void OnDrop()
{
if (Drop != null && DragAndDropService.Accepts(Zone))
{
Drop((T)DragAndDropService.Data);
}
}
}
The component has three properties.
ChildContent
is the user defined drop target content.Zone
is specifies (optinally) what draggable components are accepted. A draggable can be dropped in a drop target only if their zones have the same value.Drop
is the event handler that the DropTarget will trigger when the user drops an accepted draggable. TheData
assocated with the dropped component is provided as argument.
Usage
Here is how to use the Draggable
and DropTarget
components in the Index.razor
page:
@page "/"
<style>
.draggable {
border: 1px solid #ccc;
border-radius: 5px;
margin: 1rem;
padding: 1rem;
display: inline-block;
cursor: move;
}
.drop-target {
border: 1px dashed #ebebeb;
margin: 1rem;
padding: 1rem;
display: inline-block;
}
</style>
<Draggable Data="@draggableDataA">
<div class="draggable">
Draggable A
</div>
</Draggable>
<Draggable Data="@draggableDataB">
<div class="draggable">
Draggable B
</div>
</Draggable>
<DropTarget T="String" Drop="@OnDrop">
<div class="drop-target">
Accepts Draggable A or B
</div>
</DropTarget>
@if (dropMessage != null) {
@dropMessage
}
<DropTarget T="String" Zone="DropZone">
<div class="drop-target">
Can't drop here
</div>
</DropTarget>
@code {
string draggableDataA = "Draggable Data A";
string draggableDataB = "Draggable Data B";
string dropMessage = null;
void OnDrop(string data)
{
dropMessage = $"Dropped: {data}";
// Important: Invoke StateHasChanged() to update the page
StateHasChanged();
}
}
The complete sample project is available in the Radzen Github repository.
Cheers!