Scheduler drag and drop with mobile support (#1395)

* Appointment drag and drop functionality for Scheduler component.

* Added drag support for mobile devices.

* Remove DragDropTouch.js.

* Remove touch events. Set ondragstart as an attribute (required for mobile support).

* Remove some views.

---------

Co-authored-by: Atanas Korchev <akorchev@gmail.com>
This commit is contained in:
V45370
2024-03-21 13:03:20 +02:00
committed by GitHub
parent 311a53e4ce
commit b88156a672
19 changed files with 245 additions and 65 deletions

View File

@@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.Extensions.DependencyInjection;
using Radzen.Blazor;
using Radzen.Blazor.Rendering;
using System;
using System.Collections;
using System.Collections.Generic;
@@ -582,6 +583,22 @@ namespace Radzen
public GoogleMapPosition Position { get; set; }
}
/// <summary>
/// Supplies information about a <see cref="DropableViewBase.AppointmentMove" /> event that is being raised.
/// </summary>
public class SchedulerAppointmentMoveEventArgs
{
/// <summary>
/// Gets or sets the appointment data.
/// </summary>
public AppointmentData Appointment { get; set; }
/// <summary>
/// Gets or sets the time span.
/// </summary>
public TimeSpan TimeSpan { get; set; }
}
/// <summary>
/// Supplies information about a <see cref="RadzenMenu.Click" /> event that is being raised.
/// </summary>

View File

@@ -11,6 +11,11 @@ namespace Radzen.Blazor
/// </summary>
public interface IScheduler
{
/// <summary>
/// Gets or sets the appointment move event callback.
/// </summary>
/// <value>The appointment move event callback.</value>
EventCallback<SchedulerAppointmentMoveEventArgs> AppointmentMove { get; set; }
/// <summary>
/// Gets the appointments in the specified range.
/// </summary>
@@ -97,15 +102,18 @@ namespace Radzen.Blazor
/// </summary>
/// <param name="reference"></param>
/// <param name="data"></param>
/// <returns></returns>
Task MouseEnterAppointment(ElementReference reference, AppointmentData data);
/// <summary>
/// Returns true if the scheduler has a mouse enter appointment listener.
/// </summary>
/// <returns></returns>
bool HasMouseEnterAppointmentDelegate();
/// <summary>
/// Returns true if the scheduler has an AppointmentMove listener.
/// </summary>
bool HasAppointmentMoveDelegate();
/// <summary>
/// Notifies the scheduler that the user has moved the mouse out of the specified appointment.
/// </summary>

View File

@@ -1,4 +1,5 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
namespace Radzen.Blazor
@@ -49,5 +50,11 @@ namespace Radzen.Blazor
/// Gets the end date.
/// </summary>
DateTime EndDate { get; }
/// <summary>
/// Handles appointent move event.
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
Task OnAppointmentMove(SchedulerAppointmentMoveEventArgs data);
}
}

View File

@@ -8,10 +8,11 @@
{
var appointments = Scheduler.GetAppointmentsInRange(StartDate, EndDate).ToList();
return
return
@<CascadingValue Value=@Scheduler>
<DayView StartDate=@StartDate EndDate=@EndDate StartTime=@StartTime EndTime=@EndTime Appointments=@appointments
TimeFormat=@TimeFormat MinutesPerSlot=@MinutesPerSlot />
TimeFormat=@TimeFormat MinutesPerSlot=@MinutesPerSlot
AppointmentMove=OnAppointmentMove />
</CascadingValue>
;
}

View File

@@ -3,7 +3,7 @@
@inherits SchedulerViewBase
@code {
@code {
public override RenderFragment Render()
{
var appointments = Scheduler.GetAppointmentsInRange(StartDate, EndDate);
@@ -21,7 +21,7 @@
}
return @<CascadingValue Value=@Scheduler>
<MonthView StartDate=@StartDate EndDate=@EndDate MaxAppointmentsInSlot=@maxAppointmentsInSlot MoreText=@MoreText Appointments=@appointments />
<MonthView StartDate=@StartDate EndDate=@EndDate MaxAppointmentsInSlot=@maxAppointmentsInSlot MoreText=@MoreText Appointments=@appointments AppointmentMove=OnAppointmentMove />
</CascadingValue>;
}
}

View File

@@ -235,6 +235,32 @@ namespace Radzen.Blazor
[Parameter]
public EventCallback<SchedulerLoadDataEventArgs> LoadData { get; set; }
/// <summary>
/// A callback that will be invoked when an appointment is being dragged and then dropped on a different slot.
/// Commonly used to change it to a different timeslot.
/// </summary>
/// <example>
/// <code>
/// &lt;RadzenScheduler Data=@appointments AppointmentMove=@OnAppointmentMove&gt;
/// &lt;/RadzenScheduler&gt;
/// @code {
/// async Task OnAppointmentMove(SchedulerAppointmentMoveEventArgs moved)
/// {
/// var draggedAppointment = appointments.SingleOrDefault(x => x == (Appointment)moved.Appointment.Data);
/// if (draggedAppointment != null)
/// {
/// draggedAppointment.Start = draggedAppointment.Start + moved.TimeSpan;
/// draggedAppointment.End = draggedAppointment.End + moved.TimeSpan;
/// await scheduler.Reload();
/// }
/// }
/// }
/// </code>
/// </example>
/// <value></value>
[Parameter]
public EventCallback<SchedulerAppointmentMoveEventArgs> AppointmentMove { get; set; }
IList<ISchedulerView> Views { get; set; } = new List<ISchedulerView>();
/// <summary>
@@ -610,5 +636,10 @@ namespace Radzen.Blazor
{
return AppointmentMouseEnter.HasDelegate;
}
bool IScheduler.HasAppointmentMoveDelegate()
{
return AppointmentMove.HasDelegate;
}
}
}

View File

@@ -9,7 +9,7 @@
var appointments = Scheduler.GetAppointmentsInRange(StartDate, EndDate).ToList();
return @<CascadingValue Value=@Scheduler>
<WeekView HeaderFormat=@HeaderFormat MinutesPerSlot=@MinutesPerSlot StartDate=@StartDate EndDate=@EndDate StartTime=@StartTime EndTime=@EndTime Appointments=@appointments TimeFormat="@TimeFormat" />
<WeekView HeaderFormat=@HeaderFormat MinutesPerSlot=@MinutesPerSlot StartDate=@StartDate EndDate=@EndDate StartTime=@StartTime EndTime=@EndTime Appointments=@appointments TimeFormat="@TimeFormat" AppointmentMove=OnAppointmentMove />
</CascadingValue>;
}
}

View File

@@ -3,7 +3,7 @@
@inherits SchedulerViewBase
@code {
@code {
public override RenderFragment Render()
{
var appointments = Scheduler.GetAppointmentsInRange(StartDate, EndDate);
@@ -21,12 +21,13 @@
}
return @<CascadingValue Value=@Scheduler>
<YearPlannerView StartDate=@StartDate
EndDate=@EndDate
<YearPlannerView StartDate=@StartDate
EndDate=@EndDate
StartMonth=@StartMonth
MaxAppointmentsInSlot=@maxAppointmentsInSlot
MoreText=@MoreText
Appointments=@appointments />
MaxAppointmentsInSlot=@maxAppointmentsInSlot
MoreText=@MoreText
Appointments=@appointments
AppointmentMove=OnAppointmentMove />
</CascadingValue>;
}
}

View File

@@ -26,7 +26,8 @@
StartMonth=@StartMonth
MaxAppointmentsInSlot=@maxAppointmentsInSlot
MoreText=@MoreText
Appointments=@appointments />
Appointments=@appointments
AppointmentMove=OnAppointmentMove />
</CascadingValue>;
}
}

View File

@@ -1,19 +1,23 @@
@using Radzen.Blazor
@using Radzen.Blazor.Rendering
<div @ref=@element class="@($"{"rz-event"} {CssClass}".Trim())" style=@Style @onclick=@OnClick @onmouseenter=@OnMouseEnter @onmouseleave=@OnMouseLeave>
<div class="rz-event-content" title=@Title @attributes=@Attributes>
@if (ShowAppointmentContent)
{
@Scheduler.RenderAppointment(Data)
}
<div @ref=@element class="@($"{"rz-event"} {CssClass}".Trim())" draggable=@DraggableAttribute style=@Style @onclick=@OnClick @onmouseenter=@OnMouseEnter @onmouseleave=@OnMouseLeave @ondrag=@OnDragStart ondragstart=@OnDragStartAttribute>
<div class="rz-event-content" title=@Title @attributes=@Attributes>
@if (ShowAppointmentContent)
{
@Scheduler.RenderAppointment(Data)
}
</div>
</div>
</div>
@code {
private ElementReference element;
private string Title => Scheduler.HasMouseEnterAppointmentDelegate() ? null : Data?.Text;
private string DraggableAttribute => Scheduler?.HasAppointmentMoveDelegate() == true ? "true" : null;
private string OnDragStartAttribute => Scheduler?.HasAppointmentMoveDelegate() == true ? "event.dataTransfer.setData('', event.target.id)" : null;
[Parameter]
public string CssClass { get; set; }
@@ -32,6 +36,9 @@
[Parameter]
public EventCallback<AppointmentData> Click { get; set; }
[Parameter]
public EventCallback<AppointmentData> DragStart { get; set; }
IDictionary<string, object> Attributes { get; set; }
[Parameter]
@@ -88,4 +95,9 @@
{
await Scheduler.MouseLeaveAppointment(element, Data);
}
public async Task OnDragStart(DragEventArgs args)
{
await DragStart.InvokeAsync(Data);
}
}

View File

@@ -33,12 +33,14 @@
@if (item.Start >= start && item.Start <= end)
{
<Appointment Data=@item Top=@top Left=@left Width=@width Height=@height Click=@OnAppointmentSelect
CssClass="@(CurrentDate.Date == date.Date && object.Equals(Appointments.Where(i => i.Start.Date == CurrentDate.Date).OrderBy(i => i.Start).ThenByDescending(i => i.End).ElementAtOrDefault(CurrentAppointment),item) ? "rz-state-focused" : "")" />
CssClass="@(CurrentDate.Date == date.Date && object.Equals(Appointments.Where(i => i.Start.Date == CurrentDate.Date).OrderBy(i => i.Start).ThenByDescending(i => i.End).ElementAtOrDefault(CurrentAppointment),item) ? "rz-state-focused" : "")"
DragStart=@OnAppointmentDragStart />
}
else if (date == StartDate)
{
<Appointment Data=@item Top=@top Left=@left Width=@width Height=@height Click=@OnAppointmentSelect
CssClass="@(CurrentDate == date && CurrentAppointment != - 1 && object.Equals(appointments.ElementAtOrDefault(CurrentAppointment),item) ? "rz-state-focused" : "")" />
CssClass="@(CurrentDate == date && CurrentAppointment != - 1 && object.Equals(appointments.ElementAtOrDefault(CurrentAppointment),item) ? "rz-state-focused" : "")"
DragStart=@OnAppointmentDragStart />
}
}
}
@@ -63,6 +65,9 @@
[Parameter]
public int MinutesPerSlot { get; set; }
[Parameter]
public EventCallback<AppointmentData> AppointmentDragStart { get; set; }
[Parameter]
public IList<AppointmentData> Appointments { get; set; }
@@ -136,4 +141,9 @@
return groups;
}
public async Task OnAppointmentDragStart(AppointmentData Data)
{
await AppointmentDragStart.InvokeAsync(Data);
}
}

View File

@@ -1,4 +1,5 @@
@using Radzen.Blazor
@inherits DropableViewBase
<div class="rz-view rz-day-view">
<div class="rz-view-header">
@@ -11,11 +12,11 @@
@onfocus=@(args => {if(CurrentDate == default(DateTime)) { CurrentDate = StartDate; }})>
<Hours Start=@StartTime End=@EndTime TimeFormat=@TimeFormat MinutesPerSlot=@MinutesPerSlot />
<div class="rz-slots">
<DaySlotEvents MinutesPerSlot=@MinutesPerSlot StartDate=@StartDate EndDate=@EndDate Appointments=@Appointments CurrentDate="@CurrentDate" CurrentAppointment="@currentAppointment"/>
<DaySlotEvents MinutesPerSlot=@MinutesPerSlot StartDate=@StartDate EndDate=@EndDate Appointments=@Appointments CurrentDate="@CurrentDate" CurrentAppointment="@currentAppointment" AppointmentDragStart=@OnAppointmentDragStart />
@for (var date = StartDate; date < EndDate; date = date.AddMinutes(MinutesPerSlot))
{
var slotDate = date;
<div @onclick=@(args => OnSlotClick(slotDate)) @attributes=@Attributes(date)></div>
<div @onclick=@(args => OnSlotClick(slotDate)) @attributes=@Attributes(date) ondragover="event.preventDefault();" @ondrop=@(args => @OnDrop(slotDate))></div>
}
</div>
</div>
@@ -67,6 +68,7 @@
{
var attributes = Scheduler.GetSlotAttributes(date, date.AddMinutes(MinutesPerSlot));
attributes["class"] = ClassList.Create("rz-slot").Add("rz-slot-minor", (date.Minute / MinutesPerSlot) % 2 == 1).Add(attributes).ToString();
attributes["dropzone"] = "move";
return attributes;
}
@@ -119,4 +121,4 @@
preventKeyPress = false;
}
}
}
}

View File

@@ -0,0 +1,54 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
namespace Radzen.Blazor.Rendering
{
/// <summary>
/// A base class for <see cref="MonthView" /> <see cref="DayView" /> <see cref="WeekView" /> <see cref="YearPlannerView" /> <see cref="YearTimelineView" /> views.
/// </summary>
public abstract class DropableViewBase : ComponentBase
{
private bool dragStarted = false;
private AppointmentData draggedAppointment;
/// <summary>
/// Gets or sets the appointment move event callback.
/// </summary>
/// <value>The appointment move event callback.</value>
[Parameter]
public EventCallback<SchedulerAppointmentMoveEventArgs> AppointmentMove { get; set; }
/// <summary>
/// Handles on slot drop.
/// </summary>
/// <param name="slotDate"></param>
/// <returns>Task</returns>
public async Task OnDrop(DateTime slotDate)
{
if (draggedAppointment != null)
{
TimeSpan timespan = slotDate - draggedAppointment.Start;
await AppointmentMove.InvokeAsync(new SchedulerAppointmentMoveEventArgs { Appointment = draggedAppointment, TimeSpan = timespan });
draggedAppointment = null;
}
dragStarted = false;
}
/// <summary>
/// Handles Appointment drag started.
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public void OnAppointmentDragStart(AppointmentData data)
{
if (!dragStarted)
{
dragStarted = true;
draggedAppointment = data;
}
}
}
}

View File

@@ -2,17 +2,19 @@
@using Radzen.Blazor
@using Radzen.Blazor.Rendering
@inject DialogService DialogService
@inherits DropableViewBase
<div class="rz-view rz-month-view">
<div class="rz-view-header">
@for(var date = StartDate; date <= StartDate.EndOfWeek(); date = date.AddDays(1))
{
<div class="rz-slot-header">
@date.ToString("ddd", Scheduler.Culture)
</div>
}
</div>
@{
<div class="rz-view rz-month-view">
<div class="rz-view-header">
@for (var date = StartDate; date <= StartDate.EndOfWeek(); date = date.AddDays(1))
{
<div class="rz-slot-header">
@date.ToString("ddd", Scheduler.Culture)
</div>
}
</div>
@{
var days = 0;
var points = new Dictionary<AppointmentData, double>();
}
@@ -49,7 +51,8 @@
@if (item.Start >= start && item.Start <= end)
{
<Appointment Data=@item Top=@top Left=@left Width=@width Height=@height Click=@OnAppointmentClick
CssClass="@(CurrentDate >= start && CurrentDate <= end && object.Equals(currentAppointments?.ElementAtOrDefault(currentAppointment),item) ? "rz-state-focused" : "")" />
CssClass="@(CurrentDate >= start && CurrentDate <= end && object.Equals(currentAppointments?.ElementAtOrDefault(currentAppointment),item) ? "rz-state-focused" : "")"
DragStart=@OnAppointmentDragStart />
}
else if (start == date)
{
@@ -58,7 +61,8 @@
width = length * slotWidth;
<Appointment Data=@item Top=@top Left=@left Width=@width Height=@height Click=@OnAppointmentClick
CssClass="@(CurrentDate == date && object.Equals(currentAppointments?.ElementAtOrDefault(currentAppointment),item) ? "rz-state-focused" : "")"/>
CssClass="@(CurrentDate == date && object.Equals(currentAppointments?.ElementAtOrDefault(currentAppointment),item) ? "rz-state-focused" : "")"
DragStart=@OnAppointmentDragStart />
}
}
@@ -77,7 +81,7 @@
@for (var day = 0; day < 7; day ++)
{
var dayOfWeek = StartDate.AddDays(days++);
<div @onclick="@(args => OnSlotClick(dayOfWeek))" @attributes=@Attributes(dayOfWeek)>
<div @onclick="@(args => OnSlotClick(dayOfWeek))" @attributes=@Attributes(dayOfWeek) ondragover="event.preventDefault();" @ondrop=@(args => @OnDrop(dayOfWeek))>
<div class="rz-slot-title @(dayOfWeek == CurrentDate ? " rz-state-focused" : "")">
@dayOfWeek.Day
</div>
@@ -112,6 +116,7 @@
{
var attributes = Scheduler.GetSlotAttributes(start, start.AddDays(1));
attributes["class"] = ClassList.Create("rz-slot").Add(attributes).ToString();
attributes["dropzone"] = "move";
return attributes;
}
@@ -173,16 +178,16 @@
if (!preventDefault)
{
await DialogService.OpenAsync(date.ToShortDateString(), ds =>
@<div class="rz-event-list">
<CascadingValue Value=@Scheduler>
@foreach(var item in appointments)
{
<Appointment Data=@item Click="OnListEventClick" />
}
</CascadingValue>
</div>
);
await DialogService.OpenAsync(date.ToShortDateString(), ds =>
@<div class="rz-event-list">
<CascadingValue Value=@Scheduler>
@foreach(var item in appointments)
{
<Appointment Data=@item Click="OnListEventClick" />
}
</CascadingValue>
</div>
);
}
}

View File

@@ -1,5 +1,6 @@
@using Radzen.Blazor
@using Microsoft.JSInterop
@inherits DropableViewBase
@inject IJSRuntime JSRuntime
<div class="rz-view rz-week-view">
@@ -20,12 +21,12 @@
{
var start = day.Add(StartTime);
var end = day.Add(EndTime);
<div class="rz-slots @(day == CurrentDate ? " rz-state-focused" : "")">
<DaySlotEvents MinutesPerSlot=@MinutesPerSlot StartDate=@start EndDate=@end Appointments=@Appointments CurrentDate="@CurrentDate" CurrentAppointment="@currentAppointment"/>
<div class="rz-slots @(day == CurrentDate ? " rz-state-focused" : "")">
<DaySlotEvents MinutesPerSlot=@MinutesPerSlot StartDate=@start EndDate=@end Appointments=@Appointments CurrentDate="@CurrentDate" CurrentAppointment="@currentAppointment"AppointmentDragStart=@OnAppointmentDragStart/>
@for (var date = start; date < end; date = date.AddMinutes(MinutesPerSlot))
{
var slotDate = date;
<div @onclick=@(args => OnSlotClick(slotDate)) @attributes=@Attributes(date)></div>
<div @onclick=@(args => OnSlotClick(slotDate)) @attributes=@Attributes(date) ondragover="event.preventDefault();" @ondrop=@(args => @OnDrop(slotDate))></div>
}
</div>
}
@@ -81,6 +82,7 @@
{
var attributes = Scheduler.GetSlotAttributes(date, date.AddMinutes(MinutesPerSlot));
attributes["class"] = ClassList.Create("rz-slot").Add("rz-slot-minor", (date.Minute / MinutesPerSlot) % 2 == 1).Add(attributes).ToString();
attributes["dropzone"] = "move";
return attributes;
}

View File

@@ -1,6 +1,7 @@
@using Radzen
@using Radzen.Blazor
@using Radzen.Blazor.Rendering
@inherits DropableViewBase
@inject DialogService DialogService
@{
@@ -66,7 +67,7 @@
@if (item.Start >= realstart && item.Start <= end)
{
<Appointment Data=@item Top=@top Left=@left Width=@width Height=@height Click=@OnAppointmentClick ShowAppointmentContent=false />
<Appointment Data=@item Top=@top Left=@left Width=@width Height=@height Click=@OnAppointmentClick ShowAppointmentContent=false DragStart=@OnAppointmentDragStart />
}
else if (realstart == start)
{
@@ -74,7 +75,7 @@
length = Math.Max(1, Math.Min(daysinmonth, Math.Ceiling(item.End.Subtract(date).TotalDays - (startSlotIndex - 1))));
width = length * slotWidth;
<Appointment Data=@item Top=@top Left=@left Width=@width Height=@height Click=@OnAppointmentClick ShowAppointmentContent=false />
<Appointment Data=@item Top=@top Left=@left Width=@width Height=@height Click=@OnAppointmentClick ShowAppointmentContent=false DragStart=@OnAppointmentDragStart />
}
}
@@ -109,7 +110,7 @@
@if (slotInMonth)
{
<div @onclick="@(args => OnSlotClick(dayOfWeek))" @attributes=@Attributes(dayOfWeek, ($"rz-slot {dayType} {(CurrentDate.Date == dayOfWeek.Date ? "rz-state-focused" : "")}"), slotInMonth)>
<div @onclick="@(args => OnSlotClick(dayOfWeek))" @attributes=@Attributes(dayOfWeek, ($"rz-slot {dayType} {(CurrentDate.Date == dayOfWeek.Date ? "rz-state-focused" : "")}"), slotInMonth) ondragover="event.preventDefault();" @ondrop=@(args => @OnDrop(dayOfWeek))>
<div class="rz-slot-title">
@dayOfWeek.Day
</div>
@@ -117,7 +118,7 @@
}
else
{
<div @attributes=@Attributes(dayOfWeek, ($"rz-slot {dayType}"), slotInMonth)>
<div @attributes=@Attributes(dayOfWeek, ($"rz-slot {dayType}"), slotInMonth) ondragover="event.preventDefault();" @ondrop=@(args => @OnDrop(dayOfWeek))>
<div class="rz-slot-title">
</div>
</div>
@@ -162,6 +163,7 @@
{
var attributes = Scheduler.GetSlotAttributes(start, start.AddDays(1));
attributes["class"] = ClassList.Create(className).Add(attributes).ToString();
attributes["dropzone"] = "move";
if (!slotInMonth)
{
attributes.Remove("style");
@@ -264,7 +266,7 @@
if(newDate < firstDate)
{
CurrentDate = firstDate;
}
}
else if(newDate > lastDate)
{
CurrentDate = lastDate;

View File

@@ -3,6 +3,7 @@
@using Radzen.Blazor.Rendering
@using Microsoft.JSInterop
@inject DialogService DialogService
@inherits DropableViewBase
@inject IJSRuntime JSRuntime
@{
var points = new Dictionary<AppointmentData, double>();
@@ -67,7 +68,7 @@
@if (item.Start >= realstart && item.Start <= end)
{
<Appointment Data=@item Top=@top Left=@left Width=@width Height=@height Click=@OnAppointmentClick />
<Appointment Data=@item Top=@top Left=@left Width=@width Height=@height Click=@OnAppointmentClick DragStart=@OnAppointmentDragStart />
}
else if (realstart == start)
{
@@ -75,7 +76,7 @@
length = Math.Max(1, Math.Min(daysinmonth, Math.Ceiling(item.End.Subtract(date).TotalDays - (startSlotIndex - 1))));
width = length * slotWidth;
<Appointment Data=@item Top=@top Left=@left Width=@width Height=@height Click=@OnAppointmentClick />
<Appointment Data=@item Top=@top Left=@left Width=@width Height=@height Click=@OnAppointmentClick DragStart=@OnAppointmentDragStart />
}
}
@@ -109,7 +110,7 @@
@if (slotInMonth)
{
<div @onclick="@(args => OnSlotClick(dayOfWeek))" @attributes=@Attributes(dayOfWeek, ($"rz-slot {dayType} {(CurrentDate.Date == dayOfWeek.Date ? "rz-state-focused" : "")}"), slotInMonth)>
<div @onclick="@(args => OnSlotClick(dayOfWeek))" @attributes=@Attributes(dayOfWeek, ($"rz-slot {dayType} {(CurrentDate.Date == dayOfWeek.Date ? "rz-state-focused" : "")}"), slotInMonth) ondragover="event.preventDefault();" @ondrop=@(args => @OnDrop(dayOfWeek))>
<div class="rz-slot-title">
@dayOfWeek.Day
</div>
@@ -117,7 +118,7 @@
}
else
{
<div @attributes=@Attributes(dayOfWeek, ($"rz-slot {dayType}"), slotInMonth)>
<div @attributes=@Attributes(dayOfWeek, ($"rz-slot {dayType}"), slotInMonth) ondragover="event.preventDefault();" @ondrop=@(args => @OnDrop(dayOfWeek))>
<div class="rz-slot-title">
</div>
</div>
@@ -154,6 +155,7 @@
{
var attributes = Scheduler.GetSlotAttributes(start, start.AddDays(1));
attributes["class"] = ClassList.Create(className).Add(attributes).ToString();
attributes["dropzone"] = "move";
if (!slotInMonth)
{
attributes.Remove("style");
@@ -244,7 +246,7 @@
{
CurrentDate = StartDate.AddDays(1);
}
var key = args.Code != null ? args.Code : args.Key;
if (key == "ArrowLeft" || key == "ArrowRight")
@@ -257,7 +259,7 @@
if(newDate < firstDate)
{
CurrentDate = firstDate;
}
}
else if(newDate > lastDate)
{
CurrentDate = lastDate;

View File

@@ -34,6 +34,7 @@ namespace Radzen.Blazor
[CascadingParameter]
public IScheduler Scheduler { get; set; }
/// <summary>
/// Disposes this instance.
/// </summary>
@@ -88,5 +89,15 @@ namespace Radzen.Blazor
/// </summary>
/// <value>The end date.</value>
public abstract DateTime EndDate { get; }
/// <summary>
/// Handles appointent move event.
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public async Task OnAppointmentMove(SchedulerAppointmentMoveEventArgs data)
{
await Scheduler.AppointmentMove.InvokeAsync(data);
}
}
}

View File

@@ -2,11 +2,11 @@
<RadzenScheduler @ref=@scheduler SlotRender=@OnSlotRender style="height: 768px;" TItem="Appointment" Data=@appointments StartProperty="Start" EndProperty="End"
TextProperty="Text" SelectedIndex="2"
SlotSelect=@OnSlotSelect AppointmentSelect=@OnAppointmentSelect AppointmentRender=@OnAppointmentRender>
SlotSelect=@OnSlotSelect AppointmentSelect=@OnAppointmentSelect AppointmentRender=@OnAppointmentRender
AppointmentMove=@OnAppointmentMove >
<RadzenDayView />
<RadzenWeekView />
<RadzenMonthView />
<RadzenYearView />
</RadzenScheduler>
<EventConsole @ref=@console />
@@ -93,4 +93,18 @@
args.Attributes["style"] = "background: red";
}
}
async Task OnAppointmentMove(SchedulerAppointmentMoveEventArgs args)
{
var draggedAppointment = appointments.FirstOrDefault(x => x == args.Appointment.Data);
if (draggedAppointment != null)
{
draggedAppointment.Start = draggedAppointment.Start + args.TimeSpan;
draggedAppointment.End = draggedAppointment.End + args.TimeSpan;
await scheduler.Reload();
}
}
}